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