• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 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 android.os.Parcel;
20 import android.os.Parcelable;
21 import android.util.DisplayMetrics;
22 
23 import java.io.OutputStream;
24 import java.nio.Buffer;
25 import java.nio.ByteBuffer;
26 import java.nio.IntBuffer;
27 import java.nio.ShortBuffer;
28 
29 public final class Bitmap implements Parcelable {
30     /**
31      * Indicates that the bitmap was created for an unknown pixel density.
32      *
33      * @see Bitmap#getDensity()
34      * @see Bitmap#setDensity(int)
35      */
36     public static final int DENSITY_NONE = 0;
37 
38     /**
39      * Note:  mNativeBitmap is used by FaceDetector_jni.cpp
40      * Don't change/rename without updating FaceDetector_jni.cpp
41      *
42      * @hide
43      */
44     public final int mNativeBitmap;
45 
46     /**
47      * Backing buffer for the Bitmap.
48      * Made public for quick access from drawing methods -- do NOT modify
49      * from outside this class.
50      *
51      * @hide
52      */
53     public byte[] mBuffer;
54 
55     @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) // Keep to finalize native resources
56     private final BitmapFinalizer mFinalizer;
57 
58     private final boolean mIsMutable;
59     private byte[] mNinePatchChunk;   // may be null
60     private int[] mLayoutBounds;   // may be null
61     private int mWidth = -1;
62     private int mHeight = -1;
63     private boolean mRecycled;
64 
65     // Package-scoped for fast access.
66     int mDensity = getDefaultDensity();
67 
68     private static volatile Matrix sScaleMatrix;
69 
70     private static volatile int sDefaultDensity = -1;
71 
72     /**
73      * For backwards compatibility, allows the app layer to change the default
74      * density when running old apps.
75      * @hide
76      */
setDefaultDensity(int density)77     public static void setDefaultDensity(int density) {
78         sDefaultDensity = density;
79     }
80 
getDefaultDensity()81     static int getDefaultDensity() {
82         if (sDefaultDensity >= 0) {
83             return sDefaultDensity;
84         }
85         sDefaultDensity = DisplayMetrics.DENSITY_DEVICE;
86         return sDefaultDensity;
87     }
88 
89     /**
90      * @noinspection UnusedDeclaration
91      */
92     /*  Private constructor that must received an already allocated native
93         bitmap int (pointer).
94 
95         This can be called from JNI code.
96     */
Bitmap(int nativeBitmap, byte[] buffer, boolean isMutable, byte[] ninePatchChunk, int density)97     Bitmap(int nativeBitmap, byte[] buffer, boolean isMutable, byte[] ninePatchChunk,
98             int density) {
99         this(nativeBitmap, buffer, isMutable, ninePatchChunk, null, density);
100     }
101 
102     /**
103      * @noinspection UnusedDeclaration
104      */
105     /*  Private constructor that must received an already allocated native
106         bitmap int (pointer).
107 
108         This can be called from JNI code.
109     */
Bitmap(int nativeBitmap, byte[] buffer, boolean isMutable, byte[] ninePatchChunk, int[] layoutBounds, int density)110     Bitmap(int nativeBitmap, byte[] buffer, boolean isMutable, byte[] ninePatchChunk,
111             int[] layoutBounds, int density) {
112         if (nativeBitmap == 0) {
113             throw new RuntimeException("internal error: native bitmap is 0");
114         }
115 
116         mBuffer = buffer;
117         // we delete this in our finalizer
118         mNativeBitmap = nativeBitmap;
119         mFinalizer = new BitmapFinalizer(nativeBitmap);
120 
121         mIsMutable = isMutable;
122         mNinePatchChunk = ninePatchChunk;
123         mLayoutBounds = layoutBounds;
124         if (density >= 0) {
125             mDensity = density;
126         }
127     }
128 
129     /**
130      * <p>Returns the density for this bitmap.</p>
131      *
132      * <p>The default density is the same density as the current display,
133      * unless the current application does not support different screen
134      * densities in which case it is
135      * {@link android.util.DisplayMetrics#DENSITY_DEFAULT}.  Note that
136      * compatibility mode is determined by the application that was initially
137      * loaded into a process -- applications that share the same process should
138      * all have the same compatibility, or ensure they explicitly set the
139      * density of their bitmaps appropriately.</p>
140      *
141      * @return A scaling factor of the default density or {@link #DENSITY_NONE}
142      *         if the scaling factor is unknown.
143      *
144      * @see #setDensity(int)
145      * @see android.util.DisplayMetrics#DENSITY_DEFAULT
146      * @see android.util.DisplayMetrics#densityDpi
147      * @see #DENSITY_NONE
148      */
getDensity()149     public int getDensity() {
150         return mDensity;
151     }
152 
153     /**
154      * <p>Specifies the density for this bitmap.  When the bitmap is
155      * drawn to a Canvas that also has a density, it will be scaled
156      * appropriately.</p>
157      *
158      * @param density The density scaling factor to use with this bitmap or
159      *        {@link #DENSITY_NONE} if the density is unknown.
160      *
161      * @see #getDensity()
162      * @see android.util.DisplayMetrics#DENSITY_DEFAULT
163      * @see android.util.DisplayMetrics#densityDpi
164      * @see #DENSITY_NONE
165      */
setDensity(int density)166     public void setDensity(int density) {
167         mDensity = density;
168     }
169 
170     /**
171      * Sets the nine patch chunk.
172      *
173      * @param chunk The definition of the nine patch
174      *
175      * @hide
176      */
setNinePatchChunk(byte[] chunk)177     public void setNinePatchChunk(byte[] chunk) {
178         mNinePatchChunk = chunk;
179     }
180 
181     /**
182      * Sets the layout bounds as an array of left, top, right, bottom integers
183      * @param bounds the array containing the padding values
184      *
185      * @hide
186      */
setLayoutBounds(int[] bounds)187     public void setLayoutBounds(int[] bounds) {
188         mLayoutBounds = bounds;
189     }
190 
191     /**
192      * Free the native object associated with this bitmap, and clear the
193      * reference to the pixel data. This will not free the pixel data synchronously;
194      * it simply allows it to be garbage collected if there are no other references.
195      * The bitmap is marked as "dead", meaning it will throw an exception if
196      * getPixels() or setPixels() is called, and will draw nothing. This operation
197      * cannot be reversed, so it should only be called if you are sure there are no
198      * further uses for the bitmap. This is an advanced call, and normally need
199      * not be called, since the normal GC process will free up this memory when
200      * there are no more references to this bitmap.
201      */
recycle()202     public void recycle() {
203         if (!mRecycled) {
204             if (nativeRecycle(mNativeBitmap)) {
205                 // return value indicates whether native pixel object was actually recycled.
206                 // false indicates that it is still in use at the native level and these
207                 // objects should not be collected now. They will be collected later when the
208                 // Bitmap itself is collected.
209                 mBuffer = null;
210                 mNinePatchChunk = null;
211             }
212             mRecycled = true;
213         }
214     }
215 
216     /**
217      * Returns true if this bitmap has been recycled. If so, then it is an error
218      * to try to access its pixels, and the bitmap will not draw.
219      *
220      * @return true if the bitmap has been recycled
221      */
isRecycled()222     public final boolean isRecycled() {
223         return mRecycled;
224     }
225 
226     /**
227      * Returns the generation ID of this bitmap. The generation ID changes
228      * whenever the bitmap is modified. This can be used as an efficient way to
229      * check if a bitmap has changed.
230      *
231      * @return The current generation ID for this bitmap.
232      */
getGenerationId()233     public int getGenerationId() {
234         return nativeGenerationId(mNativeBitmap);
235     }
236 
237     /**
238      * This is called by methods that want to throw an exception if the bitmap
239      * has already been recycled.
240      */
checkRecycled(String errorMessage)241     private void checkRecycled(String errorMessage) {
242         if (mRecycled) {
243             throw new IllegalStateException(errorMessage);
244         }
245     }
246 
247     /**
248      * Common code for checking that x and y are >= 0
249      *
250      * @param x x coordinate to ensure is >= 0
251      * @param y y coordinate to ensure is >= 0
252      */
checkXYSign(int x, int y)253     private static void checkXYSign(int x, int y) {
254         if (x < 0) {
255             throw new IllegalArgumentException("x must be >= 0");
256         }
257         if (y < 0) {
258             throw new IllegalArgumentException("y must be >= 0");
259         }
260     }
261 
262     /**
263      * Common code for checking that width and height are > 0
264      *
265      * @param width  width to ensure is > 0
266      * @param height height to ensure is > 0
267      */
checkWidthHeight(int width, int height)268     private static void checkWidthHeight(int width, int height) {
269         if (width <= 0) {
270             throw new IllegalArgumentException("width must be > 0");
271         }
272         if (height <= 0) {
273             throw new IllegalArgumentException("height must be > 0");
274         }
275     }
276 
277     /**
278      * Possible bitmap configurations. A bitmap configuration describes
279      * how pixels are stored. This affects the quality (color depth) as
280      * well as the ability to display transparent/translucent colors.
281      */
282     public enum Config {
283         // these native values must match up with the enum in SkBitmap.h
284 
285         /**
286          * Each pixel is stored as a single translucency (alpha) channel.
287          * This is very useful to efficiently store masks for instance.
288          * No color information is stored.
289          * With this configuration, each pixel requires 1 byte of memory.
290          */
291         ALPHA_8     (2),
292 
293         /**
294          * Each pixel is stored on 2 bytes and only the RGB channels are
295          * encoded: red is stored with 5 bits of precision (32 possible
296          * values), green is stored with 6 bits of precision (64 possible
297          * values) and blue is stored with 5 bits of precision.
298          *
299          * This configuration can produce slight visual artifacts depending
300          * on the configuration of the source. For instance, without
301          * dithering, the result might show a greenish tint. To get better
302          * results dithering should be applied.
303          *
304          * This configuration may be useful when using opaque bitmaps
305          * that do not require high color fidelity.
306          */
307         RGB_565     (4),
308 
309         /**
310          * Each pixel is stored on 2 bytes. The three RGB color channels
311          * and the alpha channel (translucency) are stored with a 4 bits
312          * precision (16 possible values.)
313          *
314          * This configuration is mostly useful if the application needs
315          * to store translucency information but also needs to save
316          * memory.
317          *
318          * It is recommended to use {@link #ARGB_8888} instead of this
319          * configuration.
320          *
321          * @deprecated Because of the poor quality of this configuration,
322          *             it is advised to use {@link #ARGB_8888} instead.
323          */
324         @Deprecated
325         ARGB_4444   (5),
326 
327         /**
328          * Each pixel is stored on 4 bytes. Each channel (RGB and alpha
329          * for translucency) is stored with 8 bits of precision (256
330          * possible values.)
331          *
332          * This configuration is very flexible and offers the best
333          * quality. It should be used whenever possible.
334          */
335         ARGB_8888   (6);
336 
337         final int nativeInt;
338 
339         @SuppressWarnings({"deprecation"})
340         private static Config sConfigs[] = {
341             null, null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888
342         };
343 
Config(int ni)344         Config(int ni) {
345             this.nativeInt = ni;
346         }
347 
nativeToConfig(int ni)348         static Config nativeToConfig(int ni) {
349             return sConfigs[ni];
350         }
351     }
352 
353     /**
354      * <p>Copy the bitmap's pixels into the specified buffer (allocated by the
355      * caller). An exception is thrown if the buffer is not large enough to
356      * hold all of the pixels (taking into account the number of bytes per
357      * pixel) or if the Buffer subclass is not one of the support types
358      * (ByteBuffer, ShortBuffer, IntBuffer).</p>
359      * <p>The content of the bitmap is copied into the buffer as-is. This means
360      * that if this bitmap stores its pixels pre-multiplied
361      * (see {@link #isPremultiplied()}, the values in the buffer will also be
362      * pre-multiplied.</p>
363      */
copyPixelsToBuffer(Buffer dst)364     public void copyPixelsToBuffer(Buffer dst) {
365         int elements = dst.remaining();
366         int shift;
367         if (dst instanceof ByteBuffer) {
368             shift = 0;
369         } else if (dst instanceof ShortBuffer) {
370             shift = 1;
371         } else if (dst instanceof IntBuffer) {
372             shift = 2;
373         } else {
374             throw new RuntimeException("unsupported Buffer subclass");
375         }
376 
377         long bufferSize = (long)elements << shift;
378         long pixelSize = getByteCount();
379 
380         if (bufferSize < pixelSize) {
381             throw new RuntimeException("Buffer not large enough for pixels");
382         }
383 
384         nativeCopyPixelsToBuffer(mNativeBitmap, dst);
385 
386         // now update the buffer's position
387         int position = dst.position();
388         position += pixelSize >> shift;
389         dst.position(position);
390     }
391 
392     /**
393      * <p>Copy the pixels from the buffer, beginning at the current position,
394      * overwriting the bitmap's pixels. The data in the buffer is not changed
395      * in any way (unlike setPixels(), which converts from unpremultipled 32bit
396      * to whatever the bitmap's native format is.</p>
397      */
copyPixelsFromBuffer(Buffer src)398     public void copyPixelsFromBuffer(Buffer src) {
399         checkRecycled("copyPixelsFromBuffer called on recycled bitmap");
400 
401         int elements = src.remaining();
402         int shift;
403         if (src instanceof ByteBuffer) {
404             shift = 0;
405         } else if (src instanceof ShortBuffer) {
406             shift = 1;
407         } else if (src instanceof IntBuffer) {
408             shift = 2;
409         } else {
410             throw new RuntimeException("unsupported Buffer subclass");
411         }
412 
413         long bufferBytes = (long) elements << shift;
414         long bitmapBytes = getByteCount();
415 
416         if (bufferBytes < bitmapBytes) {
417             throw new RuntimeException("Buffer not large enough for pixels");
418         }
419 
420         nativeCopyPixelsFromBuffer(mNativeBitmap, src);
421 
422         // now update the buffer's position
423         int position = src.position();
424         position += bitmapBytes >> shift;
425         src.position(position);
426     }
427 
428     /**
429      * Tries to make a new bitmap based on the dimensions of this bitmap,
430      * setting the new bitmap's config to the one specified, and then copying
431      * this bitmap's pixels into the new bitmap. If the conversion is not
432      * supported, or the allocator fails, then this returns NULL.  The returned
433      * bitmap initially has the same density as the original.
434      *
435      * @param config    The desired config for the resulting bitmap
436      * @param isMutable True if the resulting bitmap should be mutable (i.e.
437      *                  its pixels can be modified)
438      * @return the new bitmap, or null if the copy could not be made.
439      */
copy(Config config, boolean isMutable)440     public Bitmap copy(Config config, boolean isMutable) {
441         checkRecycled("Can't copy a recycled bitmap");
442         Bitmap b = nativeCopy(mNativeBitmap, config.nativeInt, isMutable);
443         if (b != null) {
444             b.mDensity = mDensity;
445         }
446         return b;
447     }
448 
449     /**
450      * Creates a new bitmap, scaled from an existing bitmap, when possible. If the
451      * specified width and height are the same as the current width and height of
452      * the source btimap, the source bitmap is returned and now new bitmap is
453      * created.
454      *
455      * @param src       The source bitmap.
456      * @param dstWidth  The new bitmap's desired width.
457      * @param dstHeight The new bitmap's desired height.
458      * @param filter    true if the source should be filtered.
459      * @return The new scaled bitmap or the source bitmap if no scaling is required.
460      */
createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)461     public static Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight,
462             boolean filter) {
463         Matrix m;
464         synchronized (Bitmap.class) {
465             // small pool of just 1 matrix
466             m = sScaleMatrix;
467             sScaleMatrix = null;
468         }
469 
470         if (m == null) {
471             m = new Matrix();
472         }
473 
474         final int width = src.getWidth();
475         final int height = src.getHeight();
476         final float sx = dstWidth  / (float)width;
477         final float sy = dstHeight / (float)height;
478         m.setScale(sx, sy);
479         Bitmap b = Bitmap.createBitmap(src, 0, 0, width, height, m, filter);
480 
481         synchronized (Bitmap.class) {
482             // do we need to check for null? why not just assign everytime?
483             if (sScaleMatrix == null) {
484                 sScaleMatrix = m;
485             }
486         }
487 
488         return b;
489     }
490 
491     /**
492      * Returns an immutable bitmap from the source bitmap. The new bitmap may
493      * be the same object as source, or a copy may have been made.  It is
494      * initialized with the same density as the original bitmap.
495      */
createBitmap(Bitmap src)496     public static Bitmap createBitmap(Bitmap src) {
497         return createBitmap(src, 0, 0, src.getWidth(), src.getHeight());
498     }
499 
500     /**
501      * Returns an immutable bitmap from the specified subset of the source
502      * bitmap. The new bitmap may be the same object as source, or a copy may
503      * have been made. It is initialized with the same density as the original
504      * bitmap.
505      *
506      * @param source   The bitmap we are subsetting
507      * @param x        The x coordinate of the first pixel in source
508      * @param y        The y coordinate of the first pixel in source
509      * @param width    The number of pixels in each row
510      * @param height   The number of rows
511      * @return A copy of a subset of the source bitmap or the source bitmap itself.
512      */
createBitmap(Bitmap source, int x, int y, int width, int height)513     public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height) {
514         return createBitmap(source, x, y, width, height, null, false);
515     }
516 
517     /**
518      * Returns an immutable bitmap from subset of the source bitmap,
519      * transformed by the optional matrix. The new bitmap may be the
520      * same object as source, or a copy may have been made. It is
521      * initialized with the same density as the original bitmap.
522      *
523      * If the source bitmap is immutable and the requested subset is the
524      * same as the source bitmap itself, then the source bitmap is
525      * returned and no new bitmap is created.
526      *
527      * @param source   The bitmap we are subsetting
528      * @param x        The x coordinate of the first pixel in source
529      * @param y        The y coordinate of the first pixel in source
530      * @param width    The number of pixels in each row
531      * @param height   The number of rows
532      * @param m        Optional matrix to be applied to the pixels
533      * @param filter   true if the source should be filtered.
534      *                   Only applies if the matrix contains more than just
535      *                   translation.
536      * @return A bitmap that represents the specified subset of source
537      * @throws IllegalArgumentException if the x, y, width, height values are
538      *         outside of the dimensions of the source bitmap.
539      */
createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)540     public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height,
541             Matrix m, boolean filter) {
542 
543         checkXYSign(x, y);
544         checkWidthHeight(width, height);
545         if (x + width > source.getWidth()) {
546             throw new IllegalArgumentException("x + width must be <= bitmap.width()");
547         }
548         if (y + height > source.getHeight()) {
549             throw new IllegalArgumentException("y + height must be <= bitmap.height()");
550         }
551 
552         // check if we can just return our argument unchanged
553         if (!source.isMutable() && x == 0 && y == 0 && width == source.getWidth() &&
554                 height == source.getHeight() && (m == null || m.isIdentity())) {
555             return source;
556         }
557 
558         int neww = width;
559         int newh = height;
560         Canvas canvas = new Canvas();
561         Bitmap bitmap;
562         Paint paint;
563 
564         Rect srcR = new Rect(x, y, x + width, y + height);
565         RectF dstR = new RectF(0, 0, width, height);
566 
567         Config newConfig = Config.ARGB_8888;
568         final Config config = source.getConfig();
569         // GIF files generate null configs, assume ARGB_8888
570         if (config != null) {
571             switch (config) {
572                 case RGB_565:
573                     newConfig = Config.RGB_565;
574                     break;
575                 case ALPHA_8:
576                     newConfig = Config.ALPHA_8;
577                     break;
578                 //noinspection deprecation
579                 case ARGB_4444:
580                 case ARGB_8888:
581                 default:
582                     newConfig = Config.ARGB_8888;
583                     break;
584             }
585         }
586 
587         if (m == null || m.isIdentity()) {
588             bitmap = createBitmap(neww, newh, newConfig, source.hasAlpha());
589             paint = null;   // not needed
590         } else {
591             final boolean transformed = !m.rectStaysRect();
592 
593             RectF deviceR = new RectF();
594             m.mapRect(deviceR, dstR);
595 
596             neww = Math.round(deviceR.width());
597             newh = Math.round(deviceR.height());
598 
599             bitmap = createBitmap(neww, newh, transformed ? Config.ARGB_8888 : newConfig,
600                     transformed || source.hasAlpha());
601 
602             canvas.translate(-deviceR.left, -deviceR.top);
603             canvas.concat(m);
604 
605             paint = new Paint();
606             paint.setFilterBitmap(filter);
607             if (transformed) {
608                 paint.setAntiAlias(true);
609             }
610         }
611 
612         // The new bitmap was created from a known bitmap source so assume that
613         // they use the same density
614         bitmap.mDensity = source.mDensity;
615 
616         canvas.setBitmap(bitmap);
617         canvas.drawBitmap(source, srcR, dstR, paint);
618         canvas.setBitmap(null);
619 
620         return bitmap;
621     }
622 
623     /**
624      * Returns a mutable bitmap with the specified width and height.  Its
625      * initial density is as per {@link #getDensity}.
626      *
627      * @param width    The width of the bitmap
628      * @param height   The height of the bitmap
629      * @param config   The bitmap config to create.
630      * @throws IllegalArgumentException if the width or height are <= 0
631      */
createBitmap(int width, int height, Config config)632     public static Bitmap createBitmap(int width, int height, Config config) {
633         return createBitmap(width, height, config, true);
634     }
635 
636     /**
637      * Returns a mutable bitmap with the specified width and height.  Its
638      * initial density is determined from the given {@link DisplayMetrics}.
639      *
640      * @param display  Display metrics for the display this bitmap will be
641      *                 drawn on.
642      * @param width    The width of the bitmap
643      * @param height   The height of the bitmap
644      * @param config   The bitmap config to create.
645      * @throws IllegalArgumentException if the width or height are <= 0
646      */
createBitmap(DisplayMetrics display, int width, int height, Config config)647     public static Bitmap createBitmap(DisplayMetrics display, int width,
648             int height, Config config) {
649         return createBitmap(display, width, height, config, true);
650     }
651 
652     /**
653      * Returns a mutable bitmap with the specified width and height.  Its
654      * initial density is as per {@link #getDensity}.
655      *
656      * @param width    The width of the bitmap
657      * @param height   The height of the bitmap
658      * @param config   The bitmap config to create.
659      * @param hasAlpha If the bitmap is ARGB_8888 this flag can be used to mark the
660      *                 bitmap as opaque. Doing so will clear the bitmap in black
661      *                 instead of transparent.
662      *
663      * @throws IllegalArgumentException if the width or height are <= 0
664      */
createBitmap(int width, int height, Config config, boolean hasAlpha)665     private static Bitmap createBitmap(int width, int height, Config config, boolean hasAlpha) {
666         return createBitmap(null, width, height, config, hasAlpha);
667     }
668 
669     /**
670      * Returns a mutable bitmap with the specified width and height.  Its
671      * initial density is determined from the given {@link DisplayMetrics}.
672      *
673      * @param display  Display metrics for the display this bitmap will be
674      *                 drawn on.
675      * @param width    The width of the bitmap
676      * @param height   The height of the bitmap
677      * @param config   The bitmap config to create.
678      * @param hasAlpha If the bitmap is ARGB_8888 this flag can be used to mark the
679      *                 bitmap as opaque. Doing so will clear the bitmap in black
680      *                 instead of transparent.
681      *
682      * @throws IllegalArgumentException if the width or height are <= 0
683      */
createBitmap(DisplayMetrics display, int width, int height, Config config, boolean hasAlpha)684     private static Bitmap createBitmap(DisplayMetrics display, int width, int height,
685             Config config, boolean hasAlpha) {
686         if (width <= 0 || height <= 0) {
687             throw new IllegalArgumentException("width and height must be > 0");
688         }
689         Bitmap bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true);
690         if (display != null) {
691             bm.mDensity = display.densityDpi;
692         }
693         if (config == Config.ARGB_8888 && !hasAlpha) {
694             nativeErase(bm.mNativeBitmap, 0xff000000);
695             nativeSetHasAlpha(bm.mNativeBitmap, hasAlpha);
696         } else {
697             // No need to initialize it to zeroes; it is backed by a VM byte array
698             // which is by definition preinitialized to all zeroes.
699             //
700             //nativeErase(bm.mNativeBitmap, 0);
701         }
702         return bm;
703     }
704 
705     /**
706      * Returns a immutable bitmap with the specified width and height, with each
707      * pixel value set to the corresponding value in the colors array.  Its
708      * initial density is as per {@link #getDensity}.
709      *
710      * @param colors   Array of {@link Color} used to initialize the pixels.
711      * @param offset   Number of values to skip before the first color in the
712      *                 array of colors.
713      * @param stride   Number of colors in the array between rows (must be >=
714      *                 width or <= -width).
715      * @param width    The width of the bitmap
716      * @param height   The height of the bitmap
717      * @param config   The bitmap config to create. If the config does not
718      *                 support per-pixel alpha (e.g. RGB_565), then the alpha
719      *                 bytes in the colors[] will be ignored (assumed to be FF)
720      * @throws IllegalArgumentException if the width or height are <= 0, or if
721      *         the color array's length is less than the number of pixels.
722      */
createBitmap(int colors[], int offset, int stride, int width, int height, Config config)723     public static Bitmap createBitmap(int colors[], int offset, int stride,
724             int width, int height, Config config) {
725         return createBitmap(null, colors, offset, stride, width, height, config);
726     }
727 
728     /**
729      * Returns a immutable bitmap with the specified width and height, with each
730      * pixel value set to the corresponding value in the colors array.  Its
731      * initial density is determined from the given {@link DisplayMetrics}.
732      *
733      * @param display  Display metrics for the display this bitmap will be
734      *                 drawn on.
735      * @param colors   Array of {@link Color} used to initialize the pixels.
736      * @param offset   Number of values to skip before the first color in the
737      *                 array of colors.
738      * @param stride   Number of colors in the array between rows (must be >=
739      *                 width or <= -width).
740      * @param width    The width of the bitmap
741      * @param height   The height of the bitmap
742      * @param config   The bitmap config to create. If the config does not
743      *                 support per-pixel alpha (e.g. RGB_565), then the alpha
744      *                 bytes in the colors[] will be ignored (assumed to be FF)
745      * @throws IllegalArgumentException if the width or height are <= 0, or if
746      *         the color array's length is less than the number of pixels.
747      */
createBitmap(DisplayMetrics display, int colors[], int offset, int stride, int width, int height, Config config)748     public static Bitmap createBitmap(DisplayMetrics display, int colors[],
749             int offset, int stride, int width, int height, Config config) {
750 
751         checkWidthHeight(width, height);
752         if (Math.abs(stride) < width) {
753             throw new IllegalArgumentException("abs(stride) must be >= width");
754         }
755         int lastScanline = offset + (height - 1) * stride;
756         int length = colors.length;
757         if (offset < 0 || (offset + width > length) || lastScanline < 0 ||
758                 (lastScanline + width > length)) {
759             throw new ArrayIndexOutOfBoundsException();
760         }
761         if (width <= 0 || height <= 0) {
762             throw new IllegalArgumentException("width and height must be > 0");
763         }
764         Bitmap bm = nativeCreate(colors, offset, stride, width, height,
765                             config.nativeInt, false);
766         if (display != null) {
767             bm.mDensity = display.densityDpi;
768         }
769         return bm;
770     }
771 
772     /**
773      * Returns a immutable bitmap with the specified width and height, with each
774      * pixel value set to the corresponding value in the colors array.  Its
775      * initial density is as per {@link #getDensity}.
776      *
777      * @param colors   Array of {@link Color} used to initialize the pixels.
778      *                 This array must be at least as large as width * height.
779      * @param width    The width of the bitmap
780      * @param height   The height of the bitmap
781      * @param config   The bitmap config to create. If the config does not
782      *                 support per-pixel alpha (e.g. RGB_565), then the alpha
783      *                 bytes in the colors[] will be ignored (assumed to be FF)
784      * @throws IllegalArgumentException if the width or height are <= 0, or if
785      *         the color array's length is less than the number of pixels.
786      */
createBitmap(int colors[], int width, int height, Config config)787     public static Bitmap createBitmap(int colors[], int width, int height, Config config) {
788         return createBitmap(null, colors, 0, width, width, height, config);
789     }
790 
791     /**
792      * Returns a immutable bitmap with the specified width and height, with each
793      * pixel value set to the corresponding value in the colors array.  Its
794      * initial density is determined from the given {@link DisplayMetrics}.
795      *
796      * @param display  Display metrics for the display this bitmap will be
797      *                 drawn on.
798      * @param colors   Array of {@link Color} used to initialize the pixels.
799      *                 This array must be at least as large as width * height.
800      * @param width    The width of the bitmap
801      * @param height   The height of the bitmap
802      * @param config   The bitmap config to create. If the config does not
803      *                 support per-pixel alpha (e.g. RGB_565), then the alpha
804      *                 bytes in the colors[] will be ignored (assumed to be FF)
805      * @throws IllegalArgumentException if the width or height are <= 0, or if
806      *         the color array's length is less than the number of pixels.
807      */
createBitmap(DisplayMetrics display, int colors[], int width, int height, Config config)808     public static Bitmap createBitmap(DisplayMetrics display, int colors[],
809             int width, int height, Config config) {
810         return createBitmap(display, colors, 0, width, width, height, config);
811     }
812 
813     /**
814      * Returns an optional array of private data, used by the UI system for
815      * some bitmaps. Not intended to be called by applications.
816      */
getNinePatchChunk()817     public byte[] getNinePatchChunk() {
818         return mNinePatchChunk;
819     }
820 
821     /**
822      * @hide
823      * @return the layout padding [left, right, top, bottom]
824      */
getLayoutBounds()825     public int[] getLayoutBounds() {
826         return mLayoutBounds;
827     }
828 
829     /**
830      * Specifies the known formats a bitmap can be compressed into
831      */
832     public enum CompressFormat {
833         JPEG    (0),
834         PNG     (1),
835         WEBP    (2);
836 
CompressFormat(int nativeInt)837         CompressFormat(int nativeInt) {
838             this.nativeInt = nativeInt;
839         }
840         final int nativeInt;
841     }
842 
843     /**
844      * Number of bytes of temp storage we use for communicating between the
845      * native compressor and the java OutputStream.
846      */
847     private final static int WORKING_COMPRESS_STORAGE = 4096;
848 
849     /**
850      * Write a compressed version of the bitmap to the specified outputstream.
851      * If this returns true, the bitmap can be reconstructed by passing a
852      * corresponding inputstream to BitmapFactory.decodeStream(). Note: not
853      * all Formats support all bitmap configs directly, so it is possible that
854      * the returned bitmap from BitmapFactory could be in a different bitdepth,
855      * and/or may have lost per-pixel alpha (e.g. JPEG only supports opaque
856      * pixels).
857      *
858      * @param format   The format of the compressed image
859      * @param quality  Hint to the compressor, 0-100. 0 meaning compress for
860      *                 small size, 100 meaning compress for max quality. Some
861      *                 formats, like PNG which is lossless, will ignore the
862      *                 quality setting
863      * @param stream   The outputstream to write the compressed data.
864      * @return true if successfully compressed to the specified stream.
865      */
compress(CompressFormat format, int quality, OutputStream stream)866     public boolean compress(CompressFormat format, int quality, OutputStream stream) {
867         checkRecycled("Can't compress a recycled bitmap");
868         // do explicit check before calling the native method
869         if (stream == null) {
870             throw new NullPointerException();
871         }
872         if (quality < 0 || quality > 100) {
873             throw new IllegalArgumentException("quality must be 0..100");
874         }
875         return nativeCompress(mNativeBitmap, format.nativeInt, quality,
876                               stream, new byte[WORKING_COMPRESS_STORAGE]);
877     }
878 
879     /**
880      * Returns true if the bitmap is marked as mutable (i.e. can be drawn into)
881      */
isMutable()882     public final boolean isMutable() {
883         return mIsMutable;
884     }
885 
886     /**
887      * <p>Indicates whether pixels stored in this bitmaps are stored pre-multiplied.
888      * When a pixel is pre-multiplied, the RGB components have been multiplied by
889      * the alpha component. For instance, if the original color is a 50%
890      * translucent red <code>(128, 255, 0, 0)</code>, the pre-multiplied form is
891      * <code>(128, 128, 0, 0)</code>.</p>
892      *
893      * <p>This method always returns false if {@link #getConfig()} is
894      * {@link Bitmap.Config#RGB_565}.</p>
895      *
896      * <p>This method only returns true if {@link #hasAlpha()} returns true.
897      * A bitmap with no alpha channel can be used both as a pre-multiplied and
898      * as a non pre-multiplied bitmap.</p>
899      *
900      * @return true if the underlying pixels have been pre-multiplied, false
901      *         otherwise
902      */
isPremultiplied()903     public final boolean isPremultiplied() {
904         return getConfig() != Config.RGB_565 && hasAlpha();
905     }
906 
907     /** Returns the bitmap's width */
getWidth()908     public final int getWidth() {
909         return mWidth == -1 ? mWidth = nativeWidth(mNativeBitmap) : mWidth;
910     }
911 
912     /** Returns the bitmap's height */
getHeight()913     public final int getHeight() {
914         return mHeight == -1 ? mHeight = nativeHeight(mNativeBitmap) : mHeight;
915     }
916 
917     /**
918      * Convenience for calling {@link #getScaledWidth(int)} with the target
919      * density of the given {@link Canvas}.
920      */
getScaledWidth(Canvas canvas)921     public int getScaledWidth(Canvas canvas) {
922         return scaleFromDensity(getWidth(), mDensity, canvas.mDensity);
923     }
924 
925     /**
926      * Convenience for calling {@link #getScaledHeight(int)} with the target
927      * density of the given {@link Canvas}.
928      */
getScaledHeight(Canvas canvas)929     public int getScaledHeight(Canvas canvas) {
930         return scaleFromDensity(getHeight(), mDensity, canvas.mDensity);
931     }
932 
933     /**
934      * Convenience for calling {@link #getScaledWidth(int)} with the target
935      * density of the given {@link DisplayMetrics}.
936      */
getScaledWidth(DisplayMetrics metrics)937     public int getScaledWidth(DisplayMetrics metrics) {
938         return scaleFromDensity(getWidth(), mDensity, metrics.densityDpi);
939     }
940 
941     /**
942      * Convenience for calling {@link #getScaledHeight(int)} with the target
943      * density of the given {@link DisplayMetrics}.
944      */
getScaledHeight(DisplayMetrics metrics)945     public int getScaledHeight(DisplayMetrics metrics) {
946         return scaleFromDensity(getHeight(), mDensity, metrics.densityDpi);
947     }
948 
949     /**
950      * Convenience method that returns the width of this bitmap divided
951      * by the density scale factor.
952      *
953      * @param targetDensity The density of the target canvas of the bitmap.
954      * @return The scaled width of this bitmap, according to the density scale factor.
955      */
getScaledWidth(int targetDensity)956     public int getScaledWidth(int targetDensity) {
957         return scaleFromDensity(getWidth(), mDensity, targetDensity);
958     }
959 
960     /**
961      * Convenience method that returns the height of this bitmap divided
962      * by the density scale factor.
963      *
964      * @param targetDensity The density of the target canvas of the bitmap.
965      * @return The scaled height of this bitmap, according to the density scale factor.
966      */
getScaledHeight(int targetDensity)967     public int getScaledHeight(int targetDensity) {
968         return scaleFromDensity(getHeight(), mDensity, targetDensity);
969     }
970 
971     /**
972      * @hide
973      */
scaleFromDensity(int size, int sdensity, int tdensity)974     static public int scaleFromDensity(int size, int sdensity, int tdensity) {
975         if (sdensity == DENSITY_NONE || tdensity == DENSITY_NONE || sdensity == tdensity) {
976             return size;
977         }
978 
979         // Scale by tdensity / sdensity, rounding up.
980         return ((size * tdensity) + (sdensity >> 1)) / sdensity;
981     }
982 
983     /**
984      * Return the number of bytes between rows in the bitmap's pixels. Note that
985      * this refers to the pixels as stored natively by the bitmap. If you call
986      * getPixels() or setPixels(), then the pixels are uniformly treated as
987      * 32bit values, packed according to the Color class.
988      *
989      * @return number of bytes between rows of the native bitmap pixels.
990      */
getRowBytes()991     public final int getRowBytes() {
992         return nativeRowBytes(mNativeBitmap);
993     }
994 
995     /**
996      * Returns the number of bytes used to store this bitmap's pixels.
997      */
getByteCount()998     public final int getByteCount() {
999         // int result permits bitmaps up to 46,340 x 46,340
1000         return getRowBytes() * getHeight();
1001     }
1002 
1003     /**
1004      * If the bitmap's internal config is in one of the public formats, return
1005      * that config, otherwise return null.
1006      */
getConfig()1007     public final Config getConfig() {
1008         return Config.nativeToConfig(nativeConfig(mNativeBitmap));
1009     }
1010 
1011     /** Returns true if the bitmap's config supports per-pixel alpha, and
1012      * if the pixels may contain non-opaque alpha values. For some configs,
1013      * this is always false (e.g. RGB_565), since they do not support per-pixel
1014      * alpha. However, for configs that do, the bitmap may be flagged to be
1015      * known that all of its pixels are opaque. In this case hasAlpha() will
1016      * also return false. If a config such as ARGB_8888 is not so flagged,
1017      * it will return true by default.
1018      */
hasAlpha()1019     public final boolean hasAlpha() {
1020         return nativeHasAlpha(mNativeBitmap);
1021     }
1022 
1023     /**
1024      * Tell the bitmap if all of the pixels are known to be opaque (false)
1025      * or if some of the pixels may contain non-opaque alpha values (true).
1026      * Note, for some configs (e.g. RGB_565) this call is ignored, since it
1027      * does not support per-pixel alpha values.
1028      *
1029      * This is meant as a drawing hint, as in some cases a bitmap that is known
1030      * to be opaque can take a faster drawing case than one that may have
1031      * non-opaque per-pixel alpha values.
1032      */
setHasAlpha(boolean hasAlpha)1033     public void setHasAlpha(boolean hasAlpha) {
1034         nativeSetHasAlpha(mNativeBitmap, hasAlpha);
1035     }
1036 
1037     /**
1038      * Indicates whether the renderer responsible for drawing this
1039      * bitmap should attempt to use mipmaps when this bitmap is drawn
1040      * scaled down.
1041      *
1042      * If you know that you are going to draw this bitmap at less than
1043      * 50% of its original size, you may be able to obtain a higher
1044      * quality
1045      *
1046      * This property is only a suggestion that can be ignored by the
1047      * renderer. It is not guaranteed to have any effect.
1048      *
1049      * @return true if the renderer should attempt to use mipmaps,
1050      *         false otherwise
1051      *
1052      * @see #setHasMipMap(boolean)
1053      */
hasMipMap()1054     public final boolean hasMipMap() {
1055         return nativeHasMipMap(mNativeBitmap);
1056     }
1057 
1058     /**
1059      * Set a hint for the renderer responsible for drawing this bitmap
1060      * indicating that it should attempt to use mipmaps when this bitmap
1061      * is drawn scaled down.
1062      *
1063      * If you know that you are going to draw this bitmap at less than
1064      * 50% of its original size, you may be able to obtain a higher
1065      * quality by turning this property on.
1066      *
1067      * Note that if the renderer respects this hint it might have to
1068      * allocate extra memory to hold the mipmap levels for this bitmap.
1069      *
1070      * This property is only a suggestion that can be ignored by the
1071      * renderer. It is not guaranteed to have any effect.
1072      *
1073      * @param hasMipMap indicates whether the renderer should attempt
1074      *                  to use mipmaps
1075      *
1076      * @see #hasMipMap()
1077      */
setHasMipMap(boolean hasMipMap)1078     public final void setHasMipMap(boolean hasMipMap) {
1079         nativeSetHasMipMap(mNativeBitmap, hasMipMap);
1080     }
1081 
1082     /**
1083      * Fills the bitmap's pixels with the specified {@link Color}.
1084      *
1085      * @throws IllegalStateException if the bitmap is not mutable.
1086      */
eraseColor(int c)1087     public void eraseColor(int c) {
1088         checkRecycled("Can't erase a recycled bitmap");
1089         if (!isMutable()) {
1090             throw new IllegalStateException("cannot erase immutable bitmaps");
1091         }
1092         nativeErase(mNativeBitmap, c);
1093     }
1094 
1095     /**
1096      * Returns the {@link Color} at the specified location. Throws an exception
1097      * if x or y are out of bounds (negative or >= to the width or height
1098      * respectively). The returned color is a non-premultiplied ARGB value.
1099      *
1100      * @param x    The x coordinate (0...width-1) of the pixel to return
1101      * @param y    The y coordinate (0...height-1) of the pixel to return
1102      * @return     The argb {@link Color} at the specified coordinate
1103      * @throws IllegalArgumentException if x, y exceed the bitmap's bounds
1104      */
getPixel(int x, int y)1105     public int getPixel(int x, int y) {
1106         checkRecycled("Can't call getPixel() on a recycled bitmap");
1107         checkPixelAccess(x, y);
1108         return nativeGetPixel(mNativeBitmap, x, y);
1109     }
1110 
1111     /**
1112      * Returns in pixels[] a copy of the data in the bitmap. Each value is
1113      * a packed int representing a {@link Color}. The stride parameter allows
1114      * the caller to allow for gaps in the returned pixels array between
1115      * rows. For normal packed results, just pass width for the stride value.
1116      * The returned colors are non-premultiplied ARGB values.
1117      *
1118      * @param pixels   The array to receive the bitmap's colors
1119      * @param offset   The first index to write into pixels[]
1120      * @param stride   The number of entries in pixels[] to skip between
1121      *                 rows (must be >= bitmap's width). Can be negative.
1122      * @param x        The x coordinate of the first pixel to read from
1123      *                 the bitmap
1124      * @param y        The y coordinate of the first pixel to read from
1125      *                 the bitmap
1126      * @param width    The number of pixels to read from each row
1127      * @param height   The number of rows to read
1128      *
1129      * @throws IllegalArgumentException if x, y, width, height exceed the
1130      *         bounds of the bitmap, or if abs(stride) < width.
1131      * @throws ArrayIndexOutOfBoundsException if the pixels array is too small
1132      *         to receive the specified number of pixels.
1133      */
getPixels(int[] pixels, int offset, int stride, int x, int y, int width, int height)1134     public void getPixels(int[] pixels, int offset, int stride,
1135                           int x, int y, int width, int height) {
1136         checkRecycled("Can't call getPixels() on a recycled bitmap");
1137         if (width == 0 || height == 0) {
1138             return; // nothing to do
1139         }
1140         checkPixelsAccess(x, y, width, height, offset, stride, pixels);
1141         nativeGetPixels(mNativeBitmap, pixels, offset, stride,
1142                         x, y, width, height);
1143     }
1144 
1145     /**
1146      * Shared code to check for illegal arguments passed to getPixel()
1147      * or setPixel()
1148      *
1149      * @param x x coordinate of the pixel
1150      * @param y y coordinate of the pixel
1151      */
checkPixelAccess(int x, int y)1152     private void checkPixelAccess(int x, int y) {
1153         checkXYSign(x, y);
1154         if (x >= getWidth()) {
1155             throw new IllegalArgumentException("x must be < bitmap.width()");
1156         }
1157         if (y >= getHeight()) {
1158             throw new IllegalArgumentException("y must be < bitmap.height()");
1159         }
1160     }
1161 
1162     /**
1163      * Shared code to check for illegal arguments passed to getPixels()
1164      * or setPixels()
1165      *
1166      * @param x left edge of the area of pixels to access
1167      * @param y top edge of the area of pixels to access
1168      * @param width width of the area of pixels to access
1169      * @param height height of the area of pixels to access
1170      * @param offset offset into pixels[] array
1171      * @param stride number of elements in pixels[] between each logical row
1172      * @param pixels array to hold the area of pixels being accessed
1173     */
checkPixelsAccess(int x, int y, int width, int height, int offset, int stride, int pixels[])1174     private void checkPixelsAccess(int x, int y, int width, int height,
1175                                    int offset, int stride, int pixels[]) {
1176         checkXYSign(x, y);
1177         if (width < 0) {
1178             throw new IllegalArgumentException("width must be >= 0");
1179         }
1180         if (height < 0) {
1181             throw new IllegalArgumentException("height must be >= 0");
1182         }
1183         if (x + width > getWidth()) {
1184             throw new IllegalArgumentException(
1185                     "x + width must be <= bitmap.width()");
1186         }
1187         if (y + height > getHeight()) {
1188             throw new IllegalArgumentException(
1189                     "y + height must be <= bitmap.height()");
1190         }
1191         if (Math.abs(stride) < width) {
1192             throw new IllegalArgumentException("abs(stride) must be >= width");
1193         }
1194         int lastScanline = offset + (height - 1) * stride;
1195         int length = pixels.length;
1196         if (offset < 0 || (offset + width > length)
1197                 || lastScanline < 0
1198                 || (lastScanline + width > length)) {
1199             throw new ArrayIndexOutOfBoundsException();
1200         }
1201     }
1202 
1203     /**
1204      * <p>Write the specified {@link Color} into the bitmap (assuming it is
1205      * mutable) at the x,y coordinate. The color must be a
1206      * non-premultiplied ARGB value.</p>
1207      *
1208      * @param x     The x coordinate of the pixel to replace (0...width-1)
1209      * @param y     The y coordinate of the pixel to replace (0...height-1)
1210      * @param color The ARGB color to write into the bitmap
1211      *
1212      * @throws IllegalStateException if the bitmap is not mutable
1213      * @throws IllegalArgumentException if x, y are outside of the bitmap's
1214      *         bounds.
1215      */
setPixel(int x, int y, int color)1216     public void setPixel(int x, int y, int color) {
1217         checkRecycled("Can't call setPixel() on a recycled bitmap");
1218         if (!isMutable()) {
1219             throw new IllegalStateException();
1220         }
1221         checkPixelAccess(x, y);
1222         nativeSetPixel(mNativeBitmap, x, y, color);
1223     }
1224 
1225     /**
1226      * <p>Replace pixels in the bitmap with the colors in the array. Each element
1227      * in the array is a packed int prepresenting a non-premultiplied ARGB
1228      * {@link Color}.</p>
1229      *
1230      * @param pixels   The colors to write to the bitmap
1231      * @param offset   The index of the first color to read from pixels[]
1232      * @param stride   The number of colors in pixels[] to skip between rows.
1233      *                 Normally this value will be the same as the width of
1234      *                 the bitmap, but it can be larger (or negative).
1235      * @param x        The x coordinate of the first pixel to write to in
1236      *                 the bitmap.
1237      * @param y        The y coordinate of the first pixel to write to in
1238      *                 the bitmap.
1239      * @param width    The number of colors to copy from pixels[] per row
1240      * @param height   The number of rows to write to the bitmap
1241      *
1242      * @throws IllegalStateException if the bitmap is not mutable
1243      * @throws IllegalArgumentException if x, y, width, height are outside of
1244      *         the bitmap's bounds.
1245      * @throws ArrayIndexOutOfBoundsException if the pixels array is too small
1246      *         to receive the specified number of pixels.
1247      */
setPixels(int[] pixels, int offset, int stride, int x, int y, int width, int height)1248     public void setPixels(int[] pixels, int offset, int stride,
1249             int x, int y, int width, int height) {
1250         checkRecycled("Can't call setPixels() on a recycled bitmap");
1251         if (!isMutable()) {
1252             throw new IllegalStateException();
1253         }
1254         if (width == 0 || height == 0) {
1255             return; // nothing to do
1256         }
1257         checkPixelsAccess(x, y, width, height, offset, stride, pixels);
1258         nativeSetPixels(mNativeBitmap, pixels, offset, stride,
1259                         x, y, width, height);
1260     }
1261 
1262     public static final Parcelable.Creator<Bitmap> CREATOR
1263             = new Parcelable.Creator<Bitmap>() {
1264         /**
1265          * Rebuilds a bitmap previously stored with writeToParcel().
1266          *
1267          * @param p    Parcel object to read the bitmap from
1268          * @return a new bitmap created from the data in the parcel
1269          */
1270         public Bitmap createFromParcel(Parcel p) {
1271             Bitmap bm = nativeCreateFromParcel(p);
1272             if (bm == null) {
1273                 throw new RuntimeException("Failed to unparcel Bitmap");
1274             }
1275             return bm;
1276         }
1277         public Bitmap[] newArray(int size) {
1278             return new Bitmap[size];
1279         }
1280     };
1281 
1282     /**
1283      * No special parcel contents.
1284      */
describeContents()1285     public int describeContents() {
1286         return 0;
1287     }
1288 
1289     /**
1290      * Write the bitmap and its pixels to the parcel. The bitmap can be
1291      * rebuilt from the parcel by calling CREATOR.createFromParcel().
1292      * @param p    Parcel object to write the bitmap data into
1293      */
writeToParcel(Parcel p, int flags)1294     public void writeToParcel(Parcel p, int flags) {
1295         checkRecycled("Can't parcel a recycled bitmap");
1296         if (!nativeWriteToParcel(mNativeBitmap, mIsMutable, mDensity, p)) {
1297             throw new RuntimeException("native writeToParcel failed");
1298         }
1299     }
1300 
1301     /**
1302      * Returns a new bitmap that captures the alpha values of the original.
1303      * This may be drawn with Canvas.drawBitmap(), where the color(s) will be
1304      * taken from the paint that is passed to the draw call.
1305      *
1306      * @return new bitmap containing the alpha channel of the original bitmap.
1307      */
extractAlpha()1308     public Bitmap extractAlpha() {
1309         return extractAlpha(null, null);
1310     }
1311 
1312     /**
1313      * Returns a new bitmap that captures the alpha values of the original.
1314      * These values may be affected by the optional Paint parameter, which
1315      * can contain its own alpha, and may also contain a MaskFilter which
1316      * could change the actual dimensions of the resulting bitmap (e.g.
1317      * a blur maskfilter might enlarge the resulting bitmap). If offsetXY
1318      * is not null, it returns the amount to offset the returned bitmap so
1319      * that it will logically align with the original. For example, if the
1320      * paint contains a blur of radius 2, then offsetXY[] would contains
1321      * -2, -2, so that drawing the alpha bitmap offset by (-2, -2) and then
1322      * drawing the original would result in the blur visually aligning with
1323      * the original.
1324      *
1325      * <p>The initial density of the returned bitmap is the same as the original's.
1326      *
1327      * @param paint Optional paint used to modify the alpha values in the
1328      *              resulting bitmap. Pass null for default behavior.
1329      * @param offsetXY Optional array that returns the X (index 0) and Y
1330      *                 (index 1) offset needed to position the returned bitmap
1331      *                 so that it visually lines up with the original.
1332      * @return new bitmap containing the (optionally modified by paint) alpha
1333      *         channel of the original bitmap. This may be drawn with
1334      *         Canvas.drawBitmap(), where the color(s) will be taken from the
1335      *         paint that is passed to the draw call.
1336      */
extractAlpha(Paint paint, int[] offsetXY)1337     public Bitmap extractAlpha(Paint paint, int[] offsetXY) {
1338         checkRecycled("Can't extractAlpha on a recycled bitmap");
1339         int nativePaint = paint != null ? paint.mNativePaint : 0;
1340         Bitmap bm = nativeExtractAlpha(mNativeBitmap, nativePaint, offsetXY);
1341         if (bm == null) {
1342             throw new RuntimeException("Failed to extractAlpha on Bitmap");
1343         }
1344         bm.mDensity = mDensity;
1345         return bm;
1346     }
1347 
1348     /**
1349      *  Given another bitmap, return true if it has the same dimensions, config,
1350      *  and pixel data as this bitmap. If any of those differ, return false.
1351      *  If other is null, return false.
1352      */
sameAs(Bitmap other)1353     public boolean sameAs(Bitmap other) {
1354         return this == other || (other != null && nativeSameAs(mNativeBitmap, other.mNativeBitmap));
1355     }
1356 
1357     /**
1358      * Rebuilds any caches associated with the bitmap that are used for
1359      * drawing it. In the case of purgeable bitmaps, this call will attempt to
1360      * ensure that the pixels have been decoded.
1361      * If this is called on more than one bitmap in sequence, the priority is
1362      * given in LRU order (i.e. the last bitmap called will be given highest
1363      * priority).
1364      *
1365      * For bitmaps with no associated caches, this call is effectively a no-op,
1366      * and therefore is harmless.
1367      */
prepareToDraw()1368     public void prepareToDraw() {
1369         nativePrepareToDraw(mNativeBitmap);
1370     }
1371 
1372     private static class BitmapFinalizer {
1373         private final int mNativeBitmap;
1374 
BitmapFinalizer(int nativeBitmap)1375         BitmapFinalizer(int nativeBitmap) {
1376             mNativeBitmap = nativeBitmap;
1377         }
1378 
1379         @Override
finalize()1380         public void finalize() {
1381             try {
1382                 super.finalize();
1383             } catch (Throwable t) {
1384                 // Ignore
1385             } finally {
1386                 nativeDestructor(mNativeBitmap);
1387             }
1388         }
1389     }
1390 
1391     //////////// native methods
1392 
nativeCreate(int[] colors, int offset, int stride, int width, int height, int nativeConfig, boolean mutable)1393     private static native Bitmap nativeCreate(int[] colors, int offset,
1394                                               int stride, int width, int height,
1395                                             int nativeConfig, boolean mutable);
nativeCopy(int srcBitmap, int nativeConfig, boolean isMutable)1396     private static native Bitmap nativeCopy(int srcBitmap, int nativeConfig,
1397                                             boolean isMutable);
nativeDestructor(int nativeBitmap)1398     private static native void nativeDestructor(int nativeBitmap);
nativeRecycle(int nativeBitmap)1399     private static native boolean nativeRecycle(int nativeBitmap);
1400 
nativeCompress(int nativeBitmap, int format, int quality, OutputStream stream, byte[] tempStorage)1401     private static native boolean nativeCompress(int nativeBitmap, int format,
1402                                             int quality, OutputStream stream,
1403                                             byte[] tempStorage);
nativeErase(int nativeBitmap, int color)1404     private static native void nativeErase(int nativeBitmap, int color);
nativeWidth(int nativeBitmap)1405     private static native int nativeWidth(int nativeBitmap);
nativeHeight(int nativeBitmap)1406     private static native int nativeHeight(int nativeBitmap);
nativeRowBytes(int nativeBitmap)1407     private static native int nativeRowBytes(int nativeBitmap);
nativeConfig(int nativeBitmap)1408     private static native int nativeConfig(int nativeBitmap);
1409 
nativeGetPixel(int nativeBitmap, int x, int y)1410     private static native int nativeGetPixel(int nativeBitmap, int x, int y);
nativeGetPixels(int nativeBitmap, int[] pixels, int offset, int stride, int x, int y, int width, int height)1411     private static native void nativeGetPixels(int nativeBitmap, int[] pixels,
1412                                                int offset, int stride, int x,
1413                                                int y, int width, int height);
1414 
nativeSetPixel(int nativeBitmap, int x, int y, int color)1415     private static native void nativeSetPixel(int nativeBitmap, int x, int y,
1416                                               int color);
nativeSetPixels(int nativeBitmap, int[] colors, int offset, int stride, int x, int y, int width, int height)1417     private static native void nativeSetPixels(int nativeBitmap, int[] colors,
1418                                                int offset, int stride, int x,
1419                                                int y, int width, int height);
nativeCopyPixelsToBuffer(int nativeBitmap, Buffer dst)1420     private static native void nativeCopyPixelsToBuffer(int nativeBitmap,
1421                                                         Buffer dst);
nativeCopyPixelsFromBuffer(int nb, Buffer src)1422     private static native void nativeCopyPixelsFromBuffer(int nb, Buffer src);
nativeGenerationId(int nativeBitmap)1423     private static native int nativeGenerationId(int nativeBitmap);
1424 
nativeCreateFromParcel(Parcel p)1425     private static native Bitmap nativeCreateFromParcel(Parcel p);
1426     // returns true on success
nativeWriteToParcel(int nativeBitmap, boolean isMutable, int density, Parcel p)1427     private static native boolean nativeWriteToParcel(int nativeBitmap,
1428                                                       boolean isMutable,
1429                                                       int density,
1430                                                       Parcel p);
1431     // returns a new bitmap built from the native bitmap's alpha, and the paint
nativeExtractAlpha(int nativeBitmap, int nativePaint, int[] offsetXY)1432     private static native Bitmap nativeExtractAlpha(int nativeBitmap,
1433                                                     int nativePaint,
1434                                                     int[] offsetXY);
1435 
nativePrepareToDraw(int nativeBitmap)1436     private static native void nativePrepareToDraw(int nativeBitmap);
nativeHasAlpha(int nativeBitmap)1437     private static native boolean nativeHasAlpha(int nativeBitmap);
nativeSetHasAlpha(int nBitmap, boolean hasAlpha)1438     private static native void nativeSetHasAlpha(int nBitmap, boolean hasAlpha);
nativeHasMipMap(int nativeBitmap)1439     private static native boolean nativeHasMipMap(int nativeBitmap);
nativeSetHasMipMap(int nBitmap, boolean hasMipMap)1440     private static native void nativeSetHasMipMap(int nBitmap, boolean hasMipMap);
nativeSameAs(int nb0, int nb1)1441     private static native boolean nativeSameAs(int nb0, int nb1);
1442 
ni()1443     /* package */ final int ni() {
1444         return mNativeBitmap;
1445     }
1446 }
1447