• 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     /**
32      * Indicates that the bitmap was created for an unknown pixel density.
33      *
34      * @see Bitmap#getDensity()
35      * @see Bitmap#setDensity(int)
36      */
37     public static final int DENSITY_NONE = 0;
38 
39     /**
40      * Note:  mNativeBitmap is used by FaceDetector_jni.cpp
41      * Don't change/rename without updating FaceDetector_jni.cpp
42      *
43      * @hide
44      */
45     public final int mNativeBitmap;
46 
47     /**
48      * Backing buffer for the Bitmap.
49      * Made public for quick access from drawing methods -- do NOT modify
50      * from outside this class.
51      *
52      * @hide
53      */
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     private byte[] mNinePatchChunk;   // may be null
61     private int[] mLayoutBounds;   // may be null
62     private int mWidth = -1;
63     private int mHeight = -1;
64     private boolean mRecycled;
65 
66     // Package-scoped for fast access.
67     /*package*/ int mDensity = sDefaultDensity = getDefaultDensity();
68 
69     private static volatile Matrix sScaleMatrix;
70 
71     private static volatile int sDefaultDensity = -1;
72 
73     /**
74      * For backwards compatibility, allows the app layer to change the default
75      * density when running old apps.
76      * @hide
77      */
setDefaultDensity(int density)78     public static void setDefaultDensity(int density) {
79         sDefaultDensity = density;
80     }
81 
getDefaultDensity()82     /*package*/ static int getDefaultDensity() {
83         if (sDefaultDensity >= 0) {
84             return sDefaultDensity;
85         }
86         sDefaultDensity = DisplayMetrics.DENSITY_DEVICE;
87         return sDefaultDensity;
88     }
89 
90     /**
91      * @noinspection UnusedDeclaration
92      */
93     /*  Private constructor that must received an already allocated native
94         bitmap int (pointer).
95 
96         This can be called from JNI code.
97     */
Bitmap(int nativeBitmap, byte[] buffer, boolean isMutable, byte[] ninePatchChunk, int density)98     /*package*/ Bitmap(int nativeBitmap, byte[] buffer, boolean isMutable, byte[] ninePatchChunk,
99             int density) {
100         this(nativeBitmap, buffer, isMutable, ninePatchChunk, null, density);
101     }
102 
103     /**
104      * @noinspection UnusedDeclaration
105      */
106     /*  Private constructor that must received an already allocated native
107         bitmap int (pointer).
108 
109         This can be called from JNI code.
110     */
Bitmap(int nativeBitmap, byte[] buffer, boolean isMutable, byte[] ninePatchChunk, int[] layoutBounds, int density)111     /*package*/ Bitmap(int nativeBitmap, byte[] buffer, boolean isMutable, byte[] ninePatchChunk,
112             int[] layoutBounds, int density) {
113         if (nativeBitmap == 0) {
114             throw new RuntimeException("internal error: native bitmap is 0");
115         }
116 
117         mBuffer = buffer;
118         // we delete this in our finalizer
119         mNativeBitmap = nativeBitmap;
120         mFinalizer = new BitmapFinalizer(nativeBitmap);
121 
122         mIsMutable = isMutable;
123         mNinePatchChunk = ninePatchChunk;
124         mLayoutBounds = layoutBounds;
125         if (density >= 0) {
126             mDensity = density;
127         }
128     }
129 
130     /**
131      * <p>Returns the density for this bitmap.</p>
132      *
133      * <p>The default density is the same density as the current display,
134      * unless the current application does not support different screen
135      * densities in which case it is
136      * {@link android.util.DisplayMetrics#DENSITY_DEFAULT}.  Note that
137      * compatibility mode is determined by the application that was initially
138      * loaded into a process -- applications that share the same process should
139      * all have the same compatibility, or ensure they explicitly set the
140      * density of their bitmaps appropriately.</p>
141      *
142      * @return A scaling factor of the default density or {@link #DENSITY_NONE}
143      *         if the scaling factor is unknown.
144      *
145      * @see #setDensity(int)
146      * @see android.util.DisplayMetrics#DENSITY_DEFAULT
147      * @see android.util.DisplayMetrics#densityDpi
148      * @see #DENSITY_NONE
149      */
getDensity()150     public int getDensity() {
151         return mDensity;
152     }
153 
154     /**
155      * <p>Specifies the density for this bitmap.  When the bitmap is
156      * drawn to a Canvas that also has a density, it will be scaled
157      * appropriately.</p>
158      *
159      * @param density The density scaling factor to use with this bitmap or
160      *        {@link #DENSITY_NONE} if the density is unknown.
161      *
162      * @see #getDensity()
163      * @see android.util.DisplayMetrics#DENSITY_DEFAULT
164      * @see android.util.DisplayMetrics#densityDpi
165      * @see #DENSITY_NONE
166      */
setDensity(int density)167     public void setDensity(int density) {
168         mDensity = density;
169     }
170 
171     /**
172      * Sets the nine patch chunk.
173      *
174      * @param chunk The definition of the nine patch
175      *
176      * @hide
177      */
setNinePatchChunk(byte[] chunk)178     public void setNinePatchChunk(byte[] chunk) {
179         mNinePatchChunk = chunk;
180     }
181 
182     /**
183      * Sets the layout bounds as an array of left, top, right, bottom integers
184      * @param bounds the array containing the padding values
185      *
186      * @hide
187      */
setLayoutBounds(int[] bounds)188     public void setLayoutBounds(int[] bounds) {
189         mLayoutBounds = bounds;
190     }
191 
192     /**
193      * Free the native object associated with this bitmap, and clear the
194      * reference to the pixel data. This will not free the pixel data synchronously;
195      * it simply allows it to be garbage collected if there are no other references.
196      * The bitmap is marked as "dead", meaning it will throw an exception if
197      * getPixels() or setPixels() is called, and will draw nothing. This operation
198      * cannot be reversed, so it should only be called if you are sure there are no
199      * further uses for the bitmap. This is an advanced call, and normally need
200      * not be called, since the normal GC process will free up this memory when
201      * there are no more references to this bitmap.
202      */
recycle()203     public void recycle() {
204         if (!mRecycled) {
205             mBuffer = null;
206             nativeRecycle(mNativeBitmap);
207             mNinePatchChunk = null;
208             mRecycled = true;
209         }
210     }
211 
212     /**
213      * Returns true if this bitmap has been recycled. If so, then it is an error
214      * to try to access its pixels, and the bitmap will not draw.
215      *
216      * @return true if the bitmap has been recycled
217      */
isRecycled()218     public final boolean isRecycled() {
219         return mRecycled;
220     }
221 
222     /**
223      * Returns the generation ID of this bitmap. The generation ID changes
224      * whenever the bitmap is modified. This can be used as an efficient way to
225      * check if a bitmap has changed.
226      *
227      * @return The current generation ID for this bitmap.
228      */
getGenerationId()229     public int getGenerationId() {
230         return nativeGenerationId(mNativeBitmap);
231     }
232 
233     /**
234      * This is called by methods that want to throw an exception if the bitmap
235      * has already been recycled.
236      */
checkRecycled(String errorMessage)237     private void checkRecycled(String errorMessage) {
238         if (mRecycled) {
239             throw new IllegalStateException(errorMessage);
240         }
241     }
242 
243     /**
244      * Common code for checking that x and y are >= 0
245      *
246      * @param x x coordinate to ensure is >= 0
247      * @param y y coordinate to ensure is >= 0
248      */
checkXYSign(int x, int y)249     private static void checkXYSign(int x, int y) {
250         if (x < 0) {
251             throw new IllegalArgumentException("x must be >= 0");
252         }
253         if (y < 0) {
254             throw new IllegalArgumentException("y must be >= 0");
255         }
256     }
257 
258     /**
259      * Common code for checking that width and height are > 0
260      *
261      * @param width  width to ensure is > 0
262      * @param height height to ensure is > 0
263      */
checkWidthHeight(int width, int height)264     private static void checkWidthHeight(int width, int height) {
265         if (width <= 0) {
266             throw new IllegalArgumentException("width must be > 0");
267         }
268         if (height <= 0) {
269             throw new IllegalArgumentException("height must be > 0");
270         }
271     }
272 
273     /**
274      * Possible bitmap configurations. A bitmap configuration describes
275      * how pixels are stored. This affects the quality (color depth) as
276      * well as the ability to display transparent/translucent colors.
277      */
278     public enum Config {
279         // these native values must match up with the enum in SkBitmap.h
280 
281         /**
282          * Each pixel is stored as a single translucency (alpha) channel.
283          * This is very useful to efficiently store masks for instance.
284          * No color information is stored.
285          * With this configuration, each pixel requires 1 byte of memory.
286          */
287         ALPHA_8     (2),
288 
289         /**
290          * Each pixel is stored on 2 bytes and only the RGB channels are
291          * encoded: red is stored with 5 bits of precision (32 possible
292          * values), green is stored with 6 bits of precision (64 possible
293          * values) and blue is stored with 5 bits of precision.
294          *
295          * This configuration can produce slight visual artifacts depending
296          * on the configuration of the source. For instance, without
297          * dithering, the result might show a greenish tint. To get better
298          * results dithering should be applied.
299          *
300          * This configuration may be useful when using opaque bitmaps
301          * that do not require high color fidelity.
302          */
303         RGB_565     (4),
304 
305         /**
306          * Each pixel is stored on 2 bytes. The three RGB color channels
307          * and the alpha channel (translucency) are stored with a 4 bits
308          * precision (16 possible values.)
309          *
310          * This configuration is mostly useful if the application needs
311          * to store translucency information but also needs to save
312          * memory.
313          *
314          * It is recommended to use {@link #ARGB_8888} instead of this
315          * configuration.
316          *
317          * @deprecated Because of the poor quality of this configuration,
318          *             it is advised to use {@link #ARGB_8888} instead.
319          */
320         @Deprecated
321         ARGB_4444   (5),
322 
323         /**
324          * Each pixel is stored on 4 bytes. Each channel (RGB and alpha
325          * for translucency) is stored with 8 bits of precision (256
326          * possible values.)
327          *
328          * This configuration is very flexible and offers the best
329          * quality. It should be used whenever possible.
330          */
331         ARGB_8888   (6);
332 
333         final int nativeInt;
334 
335         @SuppressWarnings({"deprecation"})
336         private static Config sConfigs[] = {
337             null, null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888
338         };
339 
Config(int ni)340         Config(int ni) {
341             this.nativeInt = ni;
342         }
343 
nativeToConfig(int ni)344         static Config nativeToConfig(int ni) {
345             return sConfigs[ni];
346         }
347     }
348 
349     /**
350      * Copy the bitmap's pixels into the specified buffer (allocated by the
351      * caller). An exception is thrown if the buffer is not large enough to
352      * hold all of the pixels (taking into account the number of bytes per
353      * pixel) or if the Buffer subclass is not one of the support types
354      * (ByteBuffer, ShortBuffer, IntBuffer).
355      */
copyPixelsToBuffer(Buffer dst)356     public void copyPixelsToBuffer(Buffer dst) {
357         int elements = dst.remaining();
358         int shift;
359         if (dst instanceof ByteBuffer) {
360             shift = 0;
361         } else if (dst instanceof ShortBuffer) {
362             shift = 1;
363         } else if (dst instanceof IntBuffer) {
364             shift = 2;
365         } else {
366             throw new RuntimeException("unsupported Buffer subclass");
367         }
368 
369         long bufferSize = (long)elements << shift;
370         long pixelSize = getByteCount();
371 
372         if (bufferSize < pixelSize) {
373             throw new RuntimeException("Buffer not large enough for pixels");
374         }
375 
376         nativeCopyPixelsToBuffer(mNativeBitmap, dst);
377 
378         // now update the buffer's position
379         int position = dst.position();
380         position += pixelSize >> shift;
381         dst.position(position);
382     }
383 
384     /**
385      * Copy the pixels from the buffer, beginning at the current position,
386      * overwriting the bitmap's pixels. The data in the buffer is not changed
387      * in any way (unlike setPixels(), which converts from unpremultipled 32bit
388      * to whatever the bitmap's native format is.
389      */
copyPixelsFromBuffer(Buffer src)390     public void copyPixelsFromBuffer(Buffer src) {
391         checkRecycled("copyPixelsFromBuffer called on recycled bitmap");
392 
393         int elements = src.remaining();
394         int shift;
395         if (src instanceof ByteBuffer) {
396             shift = 0;
397         } else if (src instanceof ShortBuffer) {
398             shift = 1;
399         } else if (src instanceof IntBuffer) {
400             shift = 2;
401         } else {
402             throw new RuntimeException("unsupported Buffer subclass");
403         }
404 
405         long bufferBytes = (long)elements << shift;
406         long bitmapBytes = getByteCount();
407 
408         if (bufferBytes < bitmapBytes) {
409             throw new RuntimeException("Buffer not large enough for pixels");
410         }
411 
412         nativeCopyPixelsFromBuffer(mNativeBitmap, src);
413     }
414 
415     /**
416      * Tries to make a new bitmap based on the dimensions of this bitmap,
417      * setting the new bitmap's config to the one specified, and then copying
418      * this bitmap's pixels into the new bitmap. If the conversion is not
419      * supported, or the allocator fails, then this returns NULL.  The returned
420      * bitmap initially has the same density as the original.
421      *
422      * @param config    The desired config for the resulting bitmap
423      * @param isMutable True if the resulting bitmap should be mutable (i.e.
424      *                  its pixels can be modified)
425      * @return the new bitmap, or null if the copy could not be made.
426      */
copy(Config config, boolean isMutable)427     public Bitmap copy(Config config, boolean isMutable) {
428         checkRecycled("Can't copy a recycled bitmap");
429         Bitmap b = nativeCopy(mNativeBitmap, config.nativeInt, isMutable);
430         if (b != null) {
431             b.mDensity = mDensity;
432         }
433         return b;
434     }
435 
436     /**
437      * Creates a new bitmap, scaled from an existing bitmap, when possible. If the
438      * specified width and height are the same as the current width and height of
439      * the source btimap, the source bitmap is returned and now new bitmap is
440      * created.
441      *
442      * @param src       The source bitmap.
443      * @param dstWidth  The new bitmap's desired width.
444      * @param dstHeight The new bitmap's desired height.
445      * @param filter    true if the source should be filtered.
446      * @return The new scaled bitmap or the source bitmap if no scaling is required.
447      */
createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)448     public static Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight,
449             boolean filter) {
450         Matrix m;
451         synchronized (Bitmap.class) {
452             // small pool of just 1 matrix
453             m = sScaleMatrix;
454             sScaleMatrix = null;
455         }
456 
457         if (m == null) {
458             m = new Matrix();
459         }
460 
461         final int width = src.getWidth();
462         final int height = src.getHeight();
463         final float sx = dstWidth  / (float)width;
464         final float sy = dstHeight / (float)height;
465         m.setScale(sx, sy);
466         Bitmap b = Bitmap.createBitmap(src, 0, 0, width, height, m, filter);
467 
468         synchronized (Bitmap.class) {
469             // do we need to check for null? why not just assign everytime?
470             if (sScaleMatrix == null) {
471                 sScaleMatrix = m;
472             }
473         }
474 
475         return b;
476     }
477 
478     /**
479      * Returns an immutable bitmap from the source bitmap. The new bitmap may
480      * be the same object as source, or a copy may have been made.  It is
481      * initialized with the same density as the original bitmap.
482      */
createBitmap(Bitmap src)483     public static Bitmap createBitmap(Bitmap src) {
484         return createBitmap(src, 0, 0, src.getWidth(), src.getHeight());
485     }
486 
487     /**
488      * Returns an immutable bitmap from the specified subset of the source
489      * bitmap. The new bitmap may be the same object as source, or a copy may
490      * have been made. It is initialized with the same density as the original
491      * bitmap.
492      *
493      * @param source   The bitmap we are subsetting
494      * @param x        The x coordinate of the first pixel in source
495      * @param y        The y coordinate of the first pixel in source
496      * @param width    The number of pixels in each row
497      * @param height   The number of rows
498      * @return A copy of a subset of the source bitmap or the source bitmap itself.
499      */
createBitmap(Bitmap source, int x, int y, int width, int height)500     public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height) {
501         return createBitmap(source, x, y, width, height, null, false);
502     }
503 
504     /**
505      * Returns an immutable bitmap from subset of the source bitmap,
506      * transformed by the optional matrix. The new bitmap may be the
507      * same object as source, or a copy may have been made. It is
508      * initialized with the same density as the original bitmap.
509      *
510      * If the source bitmap is immutable and the requested subset is the
511      * same as the source bitmap itself, then the source bitmap is
512      * returned and no new bitmap is created.
513      *
514      * @param source   The bitmap we are subsetting
515      * @param x        The x coordinate of the first pixel in source
516      * @param y        The y coordinate of the first pixel in source
517      * @param width    The number of pixels in each row
518      * @param height   The number of rows
519      * @param m        Optional matrix to be applied to the pixels
520      * @param filter   true if the source should be filtered.
521      *                   Only applies if the matrix contains more than just
522      *                   translation.
523      * @return A bitmap that represents the specified subset of source
524      * @throws IllegalArgumentException if the x, y, width, height values are
525      *         outside of the dimensions of the source bitmap.
526      */
createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)527     public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height,
528             Matrix m, boolean filter) {
529 
530         checkXYSign(x, y);
531         checkWidthHeight(width, height);
532         if (x + width > source.getWidth()) {
533             throw new IllegalArgumentException("x + width must be <= bitmap.width()");
534         }
535         if (y + height > source.getHeight()) {
536             throw new IllegalArgumentException("y + height must be <= bitmap.height()");
537         }
538 
539         // check if we can just return our argument unchanged
540         if (!source.isMutable() && x == 0 && y == 0 && width == source.getWidth() &&
541                 height == source.getHeight() && (m == null || m.isIdentity())) {
542             return source;
543         }
544 
545         int neww = width;
546         int newh = height;
547         Canvas canvas = new Canvas();
548         Bitmap bitmap;
549         Paint paint;
550 
551         Rect srcR = new Rect(x, y, x + width, y + height);
552         RectF dstR = new RectF(0, 0, width, height);
553 
554         Config newConfig = Config.ARGB_8888;
555         final Config config = source.getConfig();
556         // GIF files generate null configs, assume ARGB_8888
557         if (config != null) {
558             switch (config) {
559                 case RGB_565:
560                     newConfig = Config.RGB_565;
561                     break;
562                 case ALPHA_8:
563                     newConfig = Config.ALPHA_8;
564                     break;
565                 //noinspection deprecation
566                 case ARGB_4444:
567                 case ARGB_8888:
568                 default:
569                     newConfig = Config.ARGB_8888;
570                     break;
571             }
572         }
573 
574         if (m == null || m.isIdentity()) {
575             bitmap = createBitmap(neww, newh, newConfig, source.hasAlpha());
576             paint = null;   // not needed
577         } else {
578             final boolean transformed = !m.rectStaysRect();
579 
580             RectF deviceR = new RectF();
581             m.mapRect(deviceR, dstR);
582 
583             neww = Math.round(deviceR.width());
584             newh = Math.round(deviceR.height());
585 
586             bitmap = createBitmap(neww, newh, transformed ? Config.ARGB_8888 : newConfig,
587                     transformed || source.hasAlpha());
588 
589             canvas.translate(-deviceR.left, -deviceR.top);
590             canvas.concat(m);
591 
592             paint = new Paint();
593             paint.setFilterBitmap(filter);
594             if (transformed) {
595                 paint.setAntiAlias(true);
596             }
597         }
598 
599         // The new bitmap was created from a known bitmap source so assume that
600         // they use the same density
601         bitmap.mDensity = source.mDensity;
602 
603         canvas.setBitmap(bitmap);
604         canvas.drawBitmap(source, srcR, dstR, paint);
605         canvas.setBitmap(null);
606 
607         return bitmap;
608     }
609 
610     /**
611      * Returns a mutable bitmap with the specified width and height.  Its
612      * initial density is as per {@link #getDensity}.
613      *
614      * @param width    The width of the bitmap
615      * @param height   The height of the bitmap
616      * @param config   The bitmap config to create.
617      * @throws IllegalArgumentException if the width or height are <= 0
618      */
createBitmap(int width, int height, Config config)619     public static Bitmap createBitmap(int width, int height, Config config) {
620         return createBitmap(width, height, config, true);
621     }
622 
623     /**
624      * Returns a mutable bitmap with the specified width and height.  Its
625      * initial density is as per {@link #getDensity}.
626      *
627      * @param width    The width of the bitmap
628      * @param height   The height of the bitmap
629      * @param config   The bitmap config to create.
630      * @param hasAlpha If the bitmap is ARGB_8888 this flag can be used to mark the
631      *                 bitmap as opaque. Doing so will clear the bitmap in black
632      *                 instead of transparent.
633      *
634      * @throws IllegalArgumentException if the width or height are <= 0
635      */
createBitmap(int width, int height, Config config, boolean hasAlpha)636     private static Bitmap createBitmap(int width, int height, Config config, boolean hasAlpha) {
637         if (width <= 0 || height <= 0) {
638             throw new IllegalArgumentException("width and height must be > 0");
639         }
640         Bitmap bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true);
641         if (config == Config.ARGB_8888 && !hasAlpha) {
642             nativeErase(bm.mNativeBitmap, 0xff000000);
643             nativeSetHasAlpha(bm.mNativeBitmap, hasAlpha);
644         } else {
645             // No need to initialize it to zeroes; it is backed by a VM byte array
646             // which is by definition preinitialized to all zeroes.
647             //
648             //nativeErase(bm.mNativeBitmap, 0);
649         }
650         return bm;
651     }
652 
653     /**
654      * Returns a immutable bitmap with the specified width and height, with each
655      * pixel value set to the corresponding value in the colors array.  Its
656      * initial density is as per {@link #getDensity}.
657      *
658      * @param colors   Array of {@link Color} used to initialize the pixels.
659      * @param offset   Number of values to skip before the first color in the
660      *                 array of colors.
661      * @param stride   Number of colors in the array between rows (must be >=
662      *                 width or <= -width).
663      * @param width    The width of the bitmap
664      * @param height   The height of the bitmap
665      * @param config   The bitmap config to create. If the config does not
666      *                 support per-pixel alpha (e.g. RGB_565), then the alpha
667      *                 bytes in the colors[] will be ignored (assumed to be FF)
668      * @throws IllegalArgumentException if the width or height are <= 0, or if
669      *         the color array's length is less than the number of pixels.
670      */
createBitmap(int colors[], int offset, int stride, int width, int height, Config config)671     public static Bitmap createBitmap(int colors[], int offset, int stride,
672             int width, int height, Config config) {
673 
674         checkWidthHeight(width, height);
675         if (Math.abs(stride) < width) {
676             throw new IllegalArgumentException("abs(stride) must be >= width");
677         }
678         int lastScanline = offset + (height - 1) * stride;
679         int length = colors.length;
680         if (offset < 0 || (offset + width > length) || lastScanline < 0 ||
681                 (lastScanline + width > length)) {
682             throw new ArrayIndexOutOfBoundsException();
683         }
684         if (width <= 0 || height <= 0) {
685             throw new IllegalArgumentException("width and height must be > 0");
686         }
687         return nativeCreate(colors, offset, stride, width, height,
688                             config.nativeInt, false);
689     }
690 
691     /**
692      * Returns a immutable bitmap with the specified width and height, with each
693      * pixel value set to the corresponding value in the colors array.  Its
694      * initial density is as per {@link #getDensity}.
695      *
696      * @param colors   Array of {@link Color} used to initialize the pixels.
697      *                 This array must be at least as large as width * height.
698      * @param width    The width of the bitmap
699      * @param height   The height of the bitmap
700      * @param config   The bitmap config to create. If the config does not
701      *                 support per-pixel alpha (e.g. RGB_565), then the alpha
702      *                 bytes in the colors[] will be ignored (assumed to be FF)
703      * @throws IllegalArgumentException if the width or height are <= 0, or if
704      *         the color array's length is less than the number of pixels.
705      */
createBitmap(int colors[], int width, int height, Config config)706     public static Bitmap createBitmap(int colors[], int width, int height, Config config) {
707         return createBitmap(colors, 0, width, width, height, config);
708     }
709 
710     /**
711      * Returns an optional array of private data, used by the UI system for
712      * some bitmaps. Not intended to be called by applications.
713      */
getNinePatchChunk()714     public byte[] getNinePatchChunk() {
715         return mNinePatchChunk;
716     }
717 
718     /**
719      * @hide
720      * @return the layout padding [left, right, top, bottom]
721      */
getLayoutBounds()722     public int[] getLayoutBounds() {
723         return mLayoutBounds;
724     }
725 
726     /**
727      * Specifies the known formats a bitmap can be compressed into
728      */
729     public enum CompressFormat {
730         JPEG    (0),
731         PNG     (1),
732         WEBP    (2);
733 
CompressFormat(int nativeInt)734         CompressFormat(int nativeInt) {
735             this.nativeInt = nativeInt;
736         }
737         final int nativeInt;
738     }
739 
740     /**
741      * Number of bytes of temp storage we use for communicating between the
742      * native compressor and the java OutputStream.
743      */
744     private final static int WORKING_COMPRESS_STORAGE = 4096;
745 
746     /**
747      * Write a compressed version of the bitmap to the specified outputstream.
748      * If this returns true, the bitmap can be reconstructed by passing a
749      * corresponding inputstream to BitmapFactory.decodeStream(). Note: not
750      * all Formats support all bitmap configs directly, so it is possible that
751      * the returned bitmap from BitmapFactory could be in a different bitdepth,
752      * and/or may have lost per-pixel alpha (e.g. JPEG only supports opaque
753      * pixels).
754      *
755      * @param format   The format of the compressed image
756      * @param quality  Hint to the compressor, 0-100. 0 meaning compress for
757      *                 small size, 100 meaning compress for max quality. Some
758      *                 formats, like PNG which is lossless, will ignore the
759      *                 quality setting
760      * @param stream   The outputstream to write the compressed data.
761      * @return true if successfully compressed to the specified stream.
762      */
compress(CompressFormat format, int quality, OutputStream stream)763     public boolean compress(CompressFormat format, int quality, OutputStream stream) {
764         checkRecycled("Can't compress a recycled bitmap");
765         // do explicit check before calling the native method
766         if (stream == null) {
767             throw new NullPointerException();
768         }
769         if (quality < 0 || quality > 100) {
770             throw new IllegalArgumentException("quality must be 0..100");
771         }
772         return nativeCompress(mNativeBitmap, format.nativeInt, quality,
773                               stream, new byte[WORKING_COMPRESS_STORAGE]);
774     }
775 
776     /**
777      * Returns true if the bitmap is marked as mutable (i.e. can be drawn into)
778      */
isMutable()779     public final boolean isMutable() {
780         return mIsMutable;
781     }
782 
783     /** Returns the bitmap's width */
getWidth()784     public final int getWidth() {
785         return mWidth == -1 ? mWidth = nativeWidth(mNativeBitmap) : mWidth;
786     }
787 
788     /** Returns the bitmap's height */
getHeight()789     public final int getHeight() {
790         return mHeight == -1 ? mHeight = nativeHeight(mNativeBitmap) : mHeight;
791     }
792 
793     /**
794      * Convenience for calling {@link #getScaledWidth(int)} with the target
795      * density of the given {@link Canvas}.
796      */
getScaledWidth(Canvas canvas)797     public int getScaledWidth(Canvas canvas) {
798         return scaleFromDensity(getWidth(), mDensity, canvas.mDensity);
799     }
800 
801     /**
802      * Convenience for calling {@link #getScaledHeight(int)} with the target
803      * density of the given {@link Canvas}.
804      */
getScaledHeight(Canvas canvas)805     public int getScaledHeight(Canvas canvas) {
806         return scaleFromDensity(getHeight(), mDensity, canvas.mDensity);
807     }
808 
809     /**
810      * Convenience for calling {@link #getScaledWidth(int)} with the target
811      * density of the given {@link DisplayMetrics}.
812      */
getScaledWidth(DisplayMetrics metrics)813     public int getScaledWidth(DisplayMetrics metrics) {
814         return scaleFromDensity(getWidth(), mDensity, metrics.densityDpi);
815     }
816 
817     /**
818      * Convenience for calling {@link #getScaledHeight(int)} with the target
819      * density of the given {@link DisplayMetrics}.
820      */
getScaledHeight(DisplayMetrics metrics)821     public int getScaledHeight(DisplayMetrics metrics) {
822         return scaleFromDensity(getHeight(), mDensity, metrics.densityDpi);
823     }
824 
825     /**
826      * Convenience method that returns the width of this bitmap divided
827      * by the density scale factor.
828      *
829      * @param targetDensity The density of the target canvas of the bitmap.
830      * @return The scaled width of this bitmap, according to the density scale factor.
831      */
getScaledWidth(int targetDensity)832     public int getScaledWidth(int targetDensity) {
833         return scaleFromDensity(getWidth(), mDensity, targetDensity);
834     }
835 
836     /**
837      * Convenience method that returns the height of this bitmap divided
838      * by the density scale factor.
839      *
840      * @param targetDensity The density of the target canvas of the bitmap.
841      * @return The scaled height of this bitmap, according to the density scale factor.
842      */
getScaledHeight(int targetDensity)843     public int getScaledHeight(int targetDensity) {
844         return scaleFromDensity(getHeight(), mDensity, targetDensity);
845     }
846 
847     /**
848      * @hide
849      */
scaleFromDensity(int size, int sdensity, int tdensity)850     static public int scaleFromDensity(int size, int sdensity, int tdensity) {
851         if (sdensity == DENSITY_NONE || sdensity == tdensity) {
852             return size;
853         }
854 
855         // Scale by tdensity / sdensity, rounding up.
856         return ((size * tdensity) + (sdensity >> 1)) / sdensity;
857     }
858 
859     /**
860      * Return the number of bytes between rows in the bitmap's pixels. Note that
861      * this refers to the pixels as stored natively by the bitmap. If you call
862      * getPixels() or setPixels(), then the pixels are uniformly treated as
863      * 32bit values, packed according to the Color class.
864      *
865      * @return number of bytes between rows of the native bitmap pixels.
866      */
getRowBytes()867     public final int getRowBytes() {
868         return nativeRowBytes(mNativeBitmap);
869     }
870 
871     /**
872      * Returns the number of bytes used to store this bitmap's pixels.
873      */
getByteCount()874     public final int getByteCount() {
875         // int result permits bitmaps up to 46,340 x 46,340
876         return getRowBytes() * getHeight();
877     }
878 
879     /**
880      * If the bitmap's internal config is in one of the public formats, return
881      * that config, otherwise return null.
882      */
getConfig()883     public final Config getConfig() {
884         return Config.nativeToConfig(nativeConfig(mNativeBitmap));
885     }
886 
887     /** Returns true if the bitmap's config supports per-pixel alpha, and
888      * if the pixels may contain non-opaque alpha values. For some configs,
889      * this is always false (e.g. RGB_565), since they do not support per-pixel
890      * alpha. However, for configs that do, the bitmap may be flagged to be
891      * known that all of its pixels are opaque. In this case hasAlpha() will
892      * also return false. If a config such as ARGB_8888 is not so flagged,
893      * it will return true by default.
894      */
hasAlpha()895     public final boolean hasAlpha() {
896         return nativeHasAlpha(mNativeBitmap);
897     }
898 
899     /**
900      * Tell the bitmap if all of the pixels are known to be opaque (false)
901      * or if some of the pixels may contain non-opaque alpha values (true).
902      * Note, for some configs (e.g. RGB_565) this call is ignored, since it
903      * does not support per-pixel alpha values.
904      *
905      * This is meant as a drawing hint, as in some cases a bitmap that is known
906      * to be opaque can take a faster drawing case than one that may have
907      * non-opaque per-pixel alpha values.
908      */
setHasAlpha(boolean hasAlpha)909     public void setHasAlpha(boolean hasAlpha) {
910         nativeSetHasAlpha(mNativeBitmap, hasAlpha);
911     }
912 
913     /**
914      * Fills the bitmap's pixels with the specified {@link Color}.
915      *
916      * @throws IllegalStateException if the bitmap is not mutable.
917      */
eraseColor(int c)918     public void eraseColor(int c) {
919         checkRecycled("Can't erase a recycled bitmap");
920         if (!isMutable()) {
921             throw new IllegalStateException("cannot erase immutable bitmaps");
922         }
923         nativeErase(mNativeBitmap, c);
924     }
925 
926     /**
927      * Returns the {@link Color} at the specified location. Throws an exception
928      * if x or y are out of bounds (negative or >= to the width or height
929      * respectively).
930      *
931      * @param x    The x coordinate (0...width-1) of the pixel to return
932      * @param y    The y coordinate (0...height-1) of the pixel to return
933      * @return     The argb {@link Color} at the specified coordinate
934      * @throws IllegalArgumentException if x, y exceed the bitmap's bounds
935      */
getPixel(int x, int y)936     public int getPixel(int x, int y) {
937         checkRecycled("Can't call getPixel() on a recycled bitmap");
938         checkPixelAccess(x, y);
939         return nativeGetPixel(mNativeBitmap, x, y);
940     }
941 
942     /**
943      * Returns in pixels[] a copy of the data in the bitmap. Each value is
944      * a packed int representing a {@link Color}. The stride parameter allows
945      * the caller to allow for gaps in the returned pixels array between
946      * rows. For normal packed results, just pass width for the stride value.
947      *
948      * @param pixels   The array to receive the bitmap's colors
949      * @param offset   The first index to write into pixels[]
950      * @param stride   The number of entries in pixels[] to skip between
951      *                 rows (must be >= bitmap's width). Can be negative.
952      * @param x        The x coordinate of the first pixel to read from
953      *                 the bitmap
954      * @param y        The y coordinate of the first pixel to read from
955      *                 the bitmap
956      * @param width    The number of pixels to read from each row
957      * @param height   The number of rows to read
958      * @throws IllegalArgumentException if x, y, width, height exceed the
959      *         bounds of the bitmap, or if abs(stride) < width.
960      * @throws ArrayIndexOutOfBoundsException if the pixels array is too small
961      *         to receive the specified number of pixels.
962      */
getPixels(int[] pixels, int offset, int stride, int x, int y, int width, int height)963     public void getPixels(int[] pixels, int offset, int stride,
964                           int x, int y, int width, int height) {
965         checkRecycled("Can't call getPixels() on a recycled bitmap");
966         if (width == 0 || height == 0) {
967             return; // nothing to do
968         }
969         checkPixelsAccess(x, y, width, height, offset, stride, pixels);
970         nativeGetPixels(mNativeBitmap, pixels, offset, stride,
971                         x, y, width, height);
972     }
973 
974     /**
975      * Shared code to check for illegal arguments passed to getPixel()
976      * or setPixel()
977      * @param x x coordinate of the pixel
978      * @param y y coordinate of the pixel
979      */
checkPixelAccess(int x, int y)980     private void checkPixelAccess(int x, int y) {
981         checkXYSign(x, y);
982         if (x >= getWidth()) {
983             throw new IllegalArgumentException("x must be < bitmap.width()");
984         }
985         if (y >= getHeight()) {
986             throw new IllegalArgumentException("y must be < bitmap.height()");
987         }
988     }
989 
990     /**
991      * Shared code to check for illegal arguments passed to getPixels()
992      * or setPixels()
993      *
994      * @param x left edge of the area of pixels to access
995      * @param y top edge of the area of pixels to access
996      * @param width width of the area of pixels to access
997      * @param height height of the area of pixels to access
998      * @param offset offset into pixels[] array
999      * @param stride number of elements in pixels[] between each logical row
1000      * @param pixels array to hold the area of pixels being accessed
1001     */
checkPixelsAccess(int x, int y, int width, int height, int offset, int stride, int pixels[])1002     private void checkPixelsAccess(int x, int y, int width, int height,
1003                                    int offset, int stride, int pixels[]) {
1004         checkXYSign(x, y);
1005         if (width < 0) {
1006             throw new IllegalArgumentException("width must be >= 0");
1007         }
1008         if (height < 0) {
1009             throw new IllegalArgumentException("height must be >= 0");
1010         }
1011         if (x + width > getWidth()) {
1012             throw new IllegalArgumentException(
1013                     "x + width must be <= bitmap.width()");
1014         }
1015         if (y + height > getHeight()) {
1016             throw new IllegalArgumentException(
1017                     "y + height must be <= bitmap.height()");
1018         }
1019         if (Math.abs(stride) < width) {
1020             throw new IllegalArgumentException("abs(stride) must be >= width");
1021         }
1022         int lastScanline = offset + (height - 1) * stride;
1023         int length = pixels.length;
1024         if (offset < 0 || (offset + width > length)
1025                 || lastScanline < 0
1026                 || (lastScanline + width > length)) {
1027             throw new ArrayIndexOutOfBoundsException();
1028         }
1029     }
1030 
1031     /**
1032      * Write the specified {@link Color} into the bitmap (assuming it is
1033      * mutable) at the x,y coordinate.
1034      *
1035      * @param x     The x coordinate of the pixel to replace (0...width-1)
1036      * @param y     The y coordinate of the pixel to replace (0...height-1)
1037      * @param color The {@link Color} to write into the bitmap
1038      * @throws IllegalStateException if the bitmap is not mutable
1039      * @throws IllegalArgumentException if x, y are outside of the bitmap's
1040      *         bounds.
1041      */
setPixel(int x, int y, int color)1042     public void setPixel(int x, int y, int color) {
1043         checkRecycled("Can't call setPixel() on a recycled bitmap");
1044         if (!isMutable()) {
1045             throw new IllegalStateException();
1046         }
1047         checkPixelAccess(x, y);
1048         nativeSetPixel(mNativeBitmap, x, y, color);
1049     }
1050 
1051     /**
1052      * Replace pixels in the bitmap with the colors in the array. Each element
1053      * in the array is a packed int prepresenting a {@link Color}
1054      *
1055      * @param pixels   The colors to write to the bitmap
1056      * @param offset   The index of the first color to read from pixels[]
1057      * @param stride   The number of colors in pixels[] to skip between rows.
1058      *                 Normally this value will be the same as the width of
1059      *                 the bitmap, but it can be larger (or negative).
1060      * @param x        The x coordinate of the first pixel to write to in
1061      *                 the bitmap.
1062      * @param y        The y coordinate of the first pixel to write to in
1063      *                 the bitmap.
1064      * @param width    The number of colors to copy from pixels[] per row
1065      * @param height   The number of rows to write to the bitmap
1066      * @throws IllegalStateException if the bitmap is not mutable
1067      * @throws IllegalArgumentException if x, y, width, height are outside of
1068      *         the bitmap's bounds.
1069      * @throws ArrayIndexOutOfBoundsException if the pixels array is too small
1070      *         to receive the specified number of pixels.
1071      */
setPixels(int[] pixels, int offset, int stride, int x, int y, int width, int height)1072     public void setPixels(int[] pixels, int offset, int stride,
1073                           int x, int y, int width, int height) {
1074         checkRecycled("Can't call setPixels() on a recycled bitmap");
1075         if (!isMutable()) {
1076             throw new IllegalStateException();
1077         }
1078         if (width == 0 || height == 0) {
1079             return; // nothing to do
1080         }
1081         checkPixelsAccess(x, y, width, height, offset, stride, pixels);
1082         nativeSetPixels(mNativeBitmap, pixels, offset, stride,
1083                         x, y, width, height);
1084     }
1085 
1086     public static final Parcelable.Creator<Bitmap> CREATOR
1087             = new Parcelable.Creator<Bitmap>() {
1088         /**
1089          * Rebuilds a bitmap previously stored with writeToParcel().
1090          *
1091          * @param p    Parcel object to read the bitmap from
1092          * @return a new bitmap created from the data in the parcel
1093          */
1094         public Bitmap createFromParcel(Parcel p) {
1095             Bitmap bm = nativeCreateFromParcel(p);
1096             if (bm == null) {
1097                 throw new RuntimeException("Failed to unparcel Bitmap");
1098             }
1099             return bm;
1100         }
1101         public Bitmap[] newArray(int size) {
1102             return new Bitmap[size];
1103         }
1104     };
1105 
1106     /**
1107      * No special parcel contents.
1108      */
describeContents()1109     public int describeContents() {
1110         return 0;
1111     }
1112 
1113     /**
1114      * Write the bitmap and its pixels to the parcel. The bitmap can be
1115      * rebuilt from the parcel by calling CREATOR.createFromParcel().
1116      * @param p    Parcel object to write the bitmap data into
1117      */
writeToParcel(Parcel p, int flags)1118     public void writeToParcel(Parcel p, int flags) {
1119         checkRecycled("Can't parcel a recycled bitmap");
1120         if (!nativeWriteToParcel(mNativeBitmap, mIsMutable, mDensity, p)) {
1121             throw new RuntimeException("native writeToParcel failed");
1122         }
1123     }
1124 
1125     /**
1126      * Returns a new bitmap that captures the alpha values of the original.
1127      * This may be drawn with Canvas.drawBitmap(), where the color(s) will be
1128      * taken from the paint that is passed to the draw call.
1129      *
1130      * @return new bitmap containing the alpha channel of the original bitmap.
1131      */
extractAlpha()1132     public Bitmap extractAlpha() {
1133         return extractAlpha(null, null);
1134     }
1135 
1136     /**
1137      * Returns a new bitmap that captures the alpha values of the original.
1138      * These values may be affected by the optional Paint parameter, which
1139      * can contain its own alpha, and may also contain a MaskFilter which
1140      * could change the actual dimensions of the resulting bitmap (e.g.
1141      * a blur maskfilter might enlarge the resulting bitmap). If offsetXY
1142      * is not null, it returns the amount to offset the returned bitmap so
1143      * that it will logically align with the original. For example, if the
1144      * paint contains a blur of radius 2, then offsetXY[] would contains
1145      * -2, -2, so that drawing the alpha bitmap offset by (-2, -2) and then
1146      * drawing the original would result in the blur visually aligning with
1147      * the original.
1148      *
1149      * <p>The initial density of the returned bitmap is the same as the original's.
1150      *
1151      * @param paint Optional paint used to modify the alpha values in the
1152      *              resulting bitmap. Pass null for default behavior.
1153      * @param offsetXY Optional array that returns the X (index 0) and Y
1154      *                 (index 1) offset needed to position the returned bitmap
1155      *                 so that it visually lines up with the original.
1156      * @return new bitmap containing the (optionally modified by paint) alpha
1157      *         channel of the original bitmap. This may be drawn with
1158      *         Canvas.drawBitmap(), where the color(s) will be taken from the
1159      *         paint that is passed to the draw call.
1160      */
extractAlpha(Paint paint, int[] offsetXY)1161     public Bitmap extractAlpha(Paint paint, int[] offsetXY) {
1162         checkRecycled("Can't extractAlpha on a recycled bitmap");
1163         int nativePaint = paint != null ? paint.mNativePaint : 0;
1164         Bitmap bm = nativeExtractAlpha(mNativeBitmap, nativePaint, offsetXY);
1165         if (bm == null) {
1166             throw new RuntimeException("Failed to extractAlpha on Bitmap");
1167         }
1168         bm.mDensity = mDensity;
1169         return bm;
1170     }
1171 
1172     /**
1173      *  Given another bitmap, return true if it has the same dimensions, config,
1174      *  and pixel data as this bitmap. If any of those differ, return false.
1175      *  If other is null, return false.
1176      */
sameAs(Bitmap other)1177     public boolean sameAs(Bitmap other) {
1178         return this == other || (other != null && nativeSameAs(mNativeBitmap, other.mNativeBitmap));
1179     }
1180 
1181     /**
1182      * Rebuilds any caches associated with the bitmap that are used for
1183      * drawing it. In the case of purgeable bitmaps, this call will attempt to
1184      * ensure that the pixels have been decoded.
1185      * If this is called on more than one bitmap in sequence, the priority is
1186      * given in LRU order (i.e. the last bitmap called will be given highest
1187      * priority).
1188      *
1189      * For bitmaps with no associated caches, this call is effectively a no-op,
1190      * and therefore is harmless.
1191      */
prepareToDraw()1192     public void prepareToDraw() {
1193         nativePrepareToDraw(mNativeBitmap);
1194     }
1195 
1196     private static class BitmapFinalizer {
1197         private final int mNativeBitmap;
1198 
BitmapFinalizer(int nativeBitmap)1199         BitmapFinalizer(int nativeBitmap) {
1200             mNativeBitmap = nativeBitmap;
1201         }
1202 
1203         @Override
finalize()1204         public void finalize() {
1205             try {
1206                 super.finalize();
1207             } catch (Throwable t) {
1208                 // Ignore
1209             } finally {
1210                 nativeDestructor(mNativeBitmap);
1211             }
1212         }
1213     }
1214 
1215     //////////// native methods
1216 
nativeCreate(int[] colors, int offset, int stride, int width, int height, int nativeConfig, boolean mutable)1217     private static native Bitmap nativeCreate(int[] colors, int offset,
1218                                               int stride, int width, int height,
1219                                             int nativeConfig, boolean mutable);
nativeCopy(int srcBitmap, int nativeConfig, boolean isMutable)1220     private static native Bitmap nativeCopy(int srcBitmap, int nativeConfig,
1221                                             boolean isMutable);
nativeDestructor(int nativeBitmap)1222     private static native void nativeDestructor(int nativeBitmap);
nativeRecycle(int nativeBitmap)1223     private static native void nativeRecycle(int nativeBitmap);
1224 
nativeCompress(int nativeBitmap, int format, int quality, OutputStream stream, byte[] tempStorage)1225     private static native boolean nativeCompress(int nativeBitmap, int format,
1226                                             int quality, OutputStream stream,
1227                                             byte[] tempStorage);
nativeErase(int nativeBitmap, int color)1228     private static native void nativeErase(int nativeBitmap, int color);
nativeWidth(int nativeBitmap)1229     private static native int nativeWidth(int nativeBitmap);
nativeHeight(int nativeBitmap)1230     private static native int nativeHeight(int nativeBitmap);
nativeRowBytes(int nativeBitmap)1231     private static native int nativeRowBytes(int nativeBitmap);
nativeConfig(int nativeBitmap)1232     private static native int nativeConfig(int nativeBitmap);
nativeHasAlpha(int nativeBitmap)1233     private static native boolean nativeHasAlpha(int nativeBitmap);
1234 
nativeGetPixel(int nativeBitmap, int x, int y)1235     private static native int nativeGetPixel(int nativeBitmap, int x, int y);
nativeGetPixels(int nativeBitmap, int[] pixels, int offset, int stride, int x, int y, int width, int height)1236     private static native void nativeGetPixels(int nativeBitmap, int[] pixels,
1237                                                int offset, int stride, int x,
1238                                                int y, int width, int height);
1239 
nativeSetPixel(int nativeBitmap, int x, int y, int color)1240     private static native void nativeSetPixel(int nativeBitmap, int x, int y,
1241                                               int color);
nativeSetPixels(int nativeBitmap, int[] colors, int offset, int stride, int x, int y, int width, int height)1242     private static native void nativeSetPixels(int nativeBitmap, int[] colors,
1243                                                int offset, int stride, int x,
1244                                                int y, int width, int height);
nativeCopyPixelsToBuffer(int nativeBitmap, Buffer dst)1245     private static native void nativeCopyPixelsToBuffer(int nativeBitmap,
1246                                                         Buffer dst);
nativeCopyPixelsFromBuffer(int nb, Buffer src)1247     private static native void nativeCopyPixelsFromBuffer(int nb, Buffer src);
nativeGenerationId(int nativeBitmap)1248     private static native int nativeGenerationId(int nativeBitmap);
1249 
nativeCreateFromParcel(Parcel p)1250     private static native Bitmap nativeCreateFromParcel(Parcel p);
1251     // returns true on success
nativeWriteToParcel(int nativeBitmap, boolean isMutable, int density, Parcel p)1252     private static native boolean nativeWriteToParcel(int nativeBitmap,
1253                                                       boolean isMutable,
1254                                                       int density,
1255                                                       Parcel p);
1256     // returns a new bitmap built from the native bitmap's alpha, and the paint
nativeExtractAlpha(int nativeBitmap, int nativePaint, int[] offsetXY)1257     private static native Bitmap nativeExtractAlpha(int nativeBitmap,
1258                                                     int nativePaint,
1259                                                     int[] offsetXY);
1260 
nativePrepareToDraw(int nativeBitmap)1261     private static native void nativePrepareToDraw(int nativeBitmap);
nativeSetHasAlpha(int nBitmap, boolean hasAlpha)1262     private static native void nativeSetHasAlpha(int nBitmap, boolean hasAlpha);
nativeSameAs(int nb0, int nb1)1263     private static native boolean nativeSameAs(int nb0, int nb1);
1264 
ni()1265     /* package */ final int ni() {
1266         return mNativeBitmap;
1267     }
1268 }
1269