• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.graphics;
18 
19 import java.io.InputStream;
20 import java.io.OutputStream;
21 
22 /**
23  * A picture records drawing calls (via the canvas returned by beginRecording)
24  * and can then play them back (via picture.draw(canvas) or canvas.drawPicture).
25  * The picture's contents can also be written to a stream, and then later
26  * restored to a new picture (via writeToStream / createFromStream). For most
27  * content (esp. text, lines, rectangles), drawing a sequence from a picture can
28  * be faster than the equivalent API calls, since the picture performs its
29  * playback without incurring any java-call overhead.
30  */
31 public class Picture {
32     private Canvas mRecordingCanvas;
33     private final int mNativePicture;
34 
35     private static final int WORKING_STREAM_STORAGE = 16 * 1024;
36 
Picture()37     public Picture() {
38         this(nativeConstructor(0));
39     }
40 
41     /**
42      * Create a picture by making a copy of what has already been recorded in
43      * src. The contents of src are unchanged, and if src changes later, those
44      * changes will not be reflected in this picture.
45      */
Picture(Picture src)46     public Picture(Picture src) {
47         this(nativeConstructor(src != null ? src.mNativePicture : 0));
48     }
49 
50     /**
51      * To record a picture, call beginRecording() and then draw into the Canvas
52      * that is returned. Nothing we appear on screen, but all of the draw
53      * commands (e.g. drawRect(...)) will be recorded. To stop recording, call
54      * endRecording(). At this point the Canvas that was returned must no longer
55      * be referenced, and nothing should be drawn into it.
56      */
beginRecording(int width, int height)57     public Canvas beginRecording(int width, int height) {
58         int ni = nativeBeginRecording(mNativePicture, width, height);
59         mRecordingCanvas = new RecordingCanvas(this, ni);
60         return mRecordingCanvas;
61     }
62 
63     /**
64      * Call endRecording when the picture is built. After this call, the picture
65      * may be drawn, but the canvas that was returned by beginRecording must not
66      * be referenced anymore. This is automatically called if Picture.draw() or
67      * Canvas.drawPicture() is called.
68      */
endRecording()69     public void endRecording() {
70         if (mRecordingCanvas != null) {
71             mRecordingCanvas = null;
72             nativeEndRecording(mNativePicture);
73         }
74     }
75 
76     /**
77      * Get the width of the picture as passed to beginRecording. This
78      * does not reflect (per se) the content of the picture.
79      */
getWidth()80     public native int getWidth();
81 
82     /**
83      * Get the height of the picture as passed to beginRecording. This
84      * does not reflect (per se) the content of the picture.
85      */
getHeight()86     public native int getHeight();
87 
88     /**
89      * Draw this picture on the canvas. The picture may have the side effect
90      * of changing the matrix and clip of the canvas.
91      *
92      * @param canvas  The picture is drawn to this canvas
93      */
draw(Canvas canvas)94     public void draw(Canvas canvas) {
95         if (mRecordingCanvas != null) {
96             endRecording();
97         }
98         nativeDraw(canvas.mNativeCanvas, mNativePicture);
99     }
100 
101     /**
102      * Create a new picture (already recorded) from the data in the stream. This
103      * data was generated by a previous call to writeToStream().
104      */
createFromStream(InputStream stream)105     public static Picture createFromStream(InputStream stream) {
106         return new Picture(
107             nativeCreateFromStream(stream, new byte[WORKING_STREAM_STORAGE]));
108     }
109 
110     /**
111      * Write the picture contents to a stream. The data can be used to recreate
112      * the picture in this or another process by calling createFromStream.
113      */
writeToStream(OutputStream stream)114     public void writeToStream(OutputStream stream) {
115         // do explicit check before calling the native method
116         if (stream == null) {
117             throw new NullPointerException();
118         }
119         if (!nativeWriteToStream(mNativePicture, stream,
120                              new byte[WORKING_STREAM_STORAGE])) {
121             throw new RuntimeException();
122         }
123     }
124 
finalize()125     protected void finalize() throws Throwable {
126         nativeDestructor(mNativePicture);
127     }
128 
ni()129     /*package*/ final int ni() {
130         return mNativePicture;
131     }
132 
Picture(int nativePicture)133     private Picture(int nativePicture) {
134         if (nativePicture == 0) {
135             throw new RuntimeException();
136         }
137         mNativePicture = nativePicture;
138     }
139 
140     // return empty picture if src is 0, or a copy of the native src
nativeConstructor(int nativeSrcOr0)141     private static native int nativeConstructor(int nativeSrcOr0);
nativeCreateFromStream(InputStream stream, byte[] storage)142     private static native int nativeCreateFromStream(InputStream stream,
143                                                 byte[] storage);
nativeBeginRecording(int nativeCanvas, int w, int h)144     private static native int nativeBeginRecording(int nativeCanvas,
145                                                     int w, int h);
nativeEndRecording(int nativeCanvas)146     private static native void nativeEndRecording(int nativeCanvas);
nativeDraw(int nativeCanvas, int nativePicture)147     private static native void nativeDraw(int nativeCanvas, int nativePicture);
nativeWriteToStream(int nativePicture, OutputStream stream, byte[] storage)148     private static native boolean nativeWriteToStream(int nativePicture,
149                                            OutputStream stream, byte[] storage);
nativeDestructor(int nativePicture)150     private static native void nativeDestructor(int nativePicture);
151 
152     private static class RecordingCanvas extends Canvas {
153         private final Picture mPicture;
154 
RecordingCanvas(Picture pict, int nativeCanvas)155         public RecordingCanvas(Picture pict, int nativeCanvas) {
156             super(nativeCanvas);
157             mPicture = pict;
158         }
159 
160         @Override
setBitmap(Bitmap bitmap)161         public void setBitmap(Bitmap bitmap) {
162             throw new RuntimeException(
163                                 "Cannot call setBitmap on a picture canvas");
164         }
165 
166         @Override
drawPicture(Picture picture)167         public void drawPicture(Picture picture) {
168             if (mPicture == picture) {
169                 throw new RuntimeException(
170                             "Cannot draw a picture into its recording canvas");
171             }
172             super.drawPicture(picture);
173         }
174     }
175 }
176 
177