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