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