All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.android.graphics.Picture Maven / Gradle / Ivy

Go to download

A library jar that provides APIs for Applications written for the Google Android Platform.

There is a newer version: 15-robolectric-12650502
Show newest version
/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.graphics;

import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;

import java.io.InputStream;
import java.io.OutputStream;

/**
 * A Picture records drawing calls (via the canvas returned by beginRecording)
 * and can then play them back into Canvas (via {@link Picture#draw(Canvas)} or
 * {@link Canvas#drawPicture(Picture)}).For most content (e.g. text, lines, rectangles),
 * drawing a sequence from a picture can be faster than the equivalent API
 * calls, since the picture performs its playback without incurring any
 * method-call overhead.
 *
 * 

Note: Prior to API level 23 a picture cannot * be replayed on a hardware accelerated canvas.

*/ public class Picture { private PictureCanvas mRecordingCanvas; // TODO: Figure out if this was a false-positive @UnsupportedAppUsage(maxTargetSdk = 28) private long mNativePicture; private boolean mRequiresHwAcceleration; private static final int WORKING_STREAM_STORAGE = 16 * 1024; /** * Creates an empty picture that is ready to record. */ public Picture() { this(nativeConstructor(0)); } /** * Create a picture by making a copy of what has already been recorded in * src. The contents of src are unchanged, and if src changes later, those * changes will not be reflected in this picture. */ public Picture(Picture src) { this(nativeConstructor(src != null ? src.mNativePicture : 0)); } /** @hide */ public Picture(long nativePicture) { if (nativePicture == 0) { throw new IllegalArgumentException(); } mNativePicture = nativePicture; } /** * Immediately releases the backing data of the Picture. This object will no longer * be usable after calling this, and any further calls on the Picture will throw an * IllegalStateException. * // TODO: Support? * @hide */ public void close() { if (mNativePicture != 0) { nativeDestructor(mNativePicture); mNativePicture = 0; } } @Override protected void finalize() throws Throwable { try { close(); } finally { super.finalize(); } } private void verifyValid() { if (mNativePicture == 0) { throw new IllegalStateException("Picture is destroyed"); } } /** * To record a picture, call beginRecording() and then draw into the Canvas * that is returned. Nothing we appear on screen, but all of the draw * commands (e.g. {@link Canvas#drawRect(Rect, Paint)}) will be recorded. * To stop recording, call endRecording(). After endRecording() the Canvas * that was returned must no longer be used, and nothing should be drawn * into it. */ @NonNull public Canvas beginRecording(int width, int height) { verifyValid(); if (mRecordingCanvas != null) { throw new IllegalStateException("Picture already recording, must call #endRecording()"); } long ni = nativeBeginRecording(mNativePicture, width, height); mRecordingCanvas = new PictureCanvas(this, ni); mRequiresHwAcceleration = false; return mRecordingCanvas; } /** * Call endRecording when the picture is built. After this call, the picture * may be drawn, but the canvas that was returned by beginRecording must not * be used anymore. This is automatically called if {@link Picture#draw} * or {@link Canvas#drawPicture(Picture)} is called. */ public void endRecording() { verifyValid(); if (mRecordingCanvas != null) { mRequiresHwAcceleration = mRecordingCanvas.mHoldsHwBitmap; mRecordingCanvas = null; nativeEndRecording(mNativePicture); } } /** * Get the width of the picture as passed to beginRecording. This * does not reflect (per se) the content of the picture. */ public int getWidth() { verifyValid(); return nativeGetWidth(mNativePicture); } /** * Get the height of the picture as passed to beginRecording. This * does not reflect (per se) the content of the picture. */ public int getHeight() { verifyValid(); return nativeGetHeight(mNativePicture); } /** * Indicates whether or not this Picture contains recorded commands that only work when * drawn to a hardware-accelerated canvas. If this returns true then this Picture can only * be drawn to another Picture or to a Canvas where canvas.isHardwareAccelerated() is true. * * Note this value is only updated after recording has finished by a call to * {@link #endRecording()}. Prior to that it will be the default value of false. * * @return true if the Picture can only be drawn to a hardware-accelerated canvas, * false otherwise. */ public boolean requiresHardwareAcceleration() { verifyValid(); return mRequiresHwAcceleration; } /** * Draw this picture on the canvas. *

* Prior to {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this call could * have the side effect of changing the matrix and clip of the canvas * if this picture had imbalanced saves/restores. * *

* Note: This forces the picture to internally call * {@link Picture#endRecording()} in order to prepare for playback. * * @param canvas The picture is drawn to this canvas */ public void draw(@NonNull Canvas canvas) { verifyValid(); if (mRecordingCanvas != null) { endRecording(); } if (mRequiresHwAcceleration && !canvas.isHardwareAccelerated()) { canvas.onHwBitmapInSwMode(); } nativeDraw(canvas.getNativeCanvasWrapper(), mNativePicture); } /** * Create a new picture (already recorded) from the data in the stream. This * data was generated by a previous call to writeToStream(). Pictures that * have been persisted across device restarts are not guaranteed to decode * properly and are highly discouraged. * * @see #writeToStream(java.io.OutputStream) * @removed * @deprecated The recommended alternative is to not use writeToStream and * instead draw the picture into a Bitmap from which you can persist it as * raw or compressed pixels. */ @Deprecated public static Picture createFromStream(@NonNull InputStream stream) { return new Picture(nativeCreateFromStream(stream, new byte[WORKING_STREAM_STORAGE])); } /** * Write the picture contents to a stream. The data can be used to recreate * the picture in this or another process by calling createFromStream(...) * The resulting stream is NOT to be persisted across device restarts as * there is no guarantee that the Picture can be successfully reconstructed. * * @see #createFromStream(java.io.InputStream) * @removed * @deprecated The recommended alternative is to draw the picture into a * Bitmap from which you can persist it as raw or compressed pixels. */ @Deprecated public void writeToStream(@NonNull OutputStream stream) { verifyValid(); // do explicit check before calling the native method if (stream == null) { throw new IllegalArgumentException("stream cannot be null"); } if (!nativeWriteToStream(mNativePicture, stream, new byte[WORKING_STREAM_STORAGE])) { throw new RuntimeException(); } } // return empty picture if src is 0, or a copy of the native src private static native long nativeConstructor(long nativeSrcOr0); private static native long nativeCreateFromStream(InputStream stream, byte[] storage); private static native int nativeGetWidth(long nativePicture); private static native int nativeGetHeight(long nativePicture); private static native long nativeBeginRecording(long nativeCanvas, int w, int h); private static native void nativeEndRecording(long nativeCanvas); private static native void nativeDraw(long nativeCanvas, long nativePicture); private static native boolean nativeWriteToStream(long nativePicture, OutputStream stream, byte[] storage); private static native void nativeDestructor(long nativePicture); private static class PictureCanvas extends Canvas { private final Picture mPicture; boolean mHoldsHwBitmap; public PictureCanvas(Picture pict, long nativeCanvas) { super(nativeCanvas); mPicture = pict; // Disable bitmap density scaling. This matches RecordingCanvas. mDensity = 0; } @Override public void setBitmap(Bitmap bitmap) { throw new RuntimeException("Cannot call setBitmap on a picture canvas"); } @Override public void drawPicture(Picture picture) { if (mPicture == picture) { throw new RuntimeException("Cannot draw a picture into its recording canvas"); } super.drawPicture(picture); } @Override protected void onHwBitmapInSwMode() { mHoldsHwBitmap = true; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy