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