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