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