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