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