Bitmap.java revision 3e776dee3e8af646cdcfb7a60e0e301c99f05293
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 bitmap, scaled from an existing bitmap, when possible. If the
562     * specified width and height are the same as the current width and height of
563     * the source bitmap, the source bitmap is returned and no new bitmap is
564     * created.
565     *
566     * @param src       The source bitmap.
567     * @param dstWidth  The new bitmap's desired width.
568     * @param dstHeight The new bitmap's desired height.
569     * @param filter    true if the source should be filtered.
570     * @return The new scaled bitmap or the source bitmap if no scaling is required.
571     * @throws IllegalArgumentException if width is <= 0, or height is <= 0
572     */
573    public static Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight,
574            boolean filter) {
575        Matrix m;
576        synchronized (Bitmap.class) {
577            // small pool of just 1 matrix
578            m = sScaleMatrix;
579            sScaleMatrix = null;
580        }
581
582        if (m == null) {
583            m = new Matrix();
584        }
585
586        final int width = src.getWidth();
587        final int height = src.getHeight();
588        final float sx = dstWidth  / (float)width;
589        final float sy = dstHeight / (float)height;
590        m.setScale(sx, sy);
591        Bitmap b = Bitmap.createBitmap(src, 0, 0, width, height, m, filter);
592
593        synchronized (Bitmap.class) {
594            // do we need to check for null? why not just assign everytime?
595            if (sScaleMatrix == null) {
596                sScaleMatrix = m;
597            }
598        }
599
600        return b;
601    }
602
603    /**
604     * Returns an immutable bitmap from the source bitmap. The new bitmap may
605     * be the same object as source, or a copy may have been made.  It is
606     * initialized with the same density as the original bitmap.
607     */
608    public static Bitmap createBitmap(Bitmap src) {
609        return createBitmap(src, 0, 0, src.getWidth(), src.getHeight());
610    }
611
612    /**
613     * Returns an immutable bitmap from the specified subset of the source
614     * bitmap. The new bitmap may be the same object as source, or a copy may
615     * have been made. It is initialized with the same density as the original
616     * bitmap.
617     *
618     * @param source   The bitmap we are subsetting
619     * @param x        The x coordinate of the first pixel in source
620     * @param y        The y coordinate of the first pixel in source
621     * @param width    The number of pixels in each row
622     * @param height   The number of rows
623     * @return A copy of a subset of the source bitmap or the source bitmap itself.
624     * @throws IllegalArgumentException if the x, y, width, height values are
625     *         outside of the dimensions of the source bitmap, or width is <= 0,
626     *         or height is <= 0
627     */
628    public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height) {
629        return createBitmap(source, x, y, width, height, null, false);
630    }
631
632    /**
633     * Returns an immutable bitmap from subset of the source bitmap,
634     * transformed by the optional matrix. The new bitmap may be the
635     * same object as source, or a copy may have been made. It is
636     * initialized with the same density as the original bitmap.
637     *
638     * If the source bitmap is immutable and the requested subset is the
639     * same as the source bitmap itself, then the source bitmap is
640     * returned and no new bitmap is created.
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     * @param m        Optional matrix to be applied to the pixels
648     * @param filter   true if the source should be filtered.
649     *                   Only applies if the matrix contains more than just
650     *                   translation.
651     * @return A bitmap that represents the specified subset of source
652     * @throws IllegalArgumentException if the x, y, width, height values are
653     *         outside of the dimensions of the source bitmap, or width is <= 0,
654     *         or height is <= 0
655     */
656    public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height,
657            Matrix m, boolean filter) {
658
659        checkXYSign(x, y);
660        checkWidthHeight(width, height);
661        if (x + width > source.getWidth()) {
662            throw new IllegalArgumentException("x + width must be <= bitmap.width()");
663        }
664        if (y + height > source.getHeight()) {
665            throw new IllegalArgumentException("y + height must be <= bitmap.height()");
666        }
667
668        // check if we can just return our argument unchanged
669        if (!source.isMutable() && x == 0 && y == 0 && width == source.getWidth() &&
670                height == source.getHeight() && (m == null || m.isIdentity())) {
671            return source;
672        }
673
674        int neww = width;
675        int newh = height;
676        Canvas canvas = new Canvas();
677        Bitmap bitmap;
678        Paint paint;
679
680        Rect srcR = new Rect(x, y, x + width, y + height);
681        RectF dstR = new RectF(0, 0, width, height);
682
683        Config newConfig = Config.ARGB_8888;
684        final Config config = source.getConfig();
685        // GIF files generate null configs, assume ARGB_8888
686        if (config != null) {
687            switch (config) {
688                case RGB_565:
689                    newConfig = Config.RGB_565;
690                    break;
691                case ALPHA_8:
692                    newConfig = Config.ALPHA_8;
693                    break;
694                //noinspection deprecation
695                case ARGB_4444:
696                case ARGB_8888:
697                default:
698                    newConfig = Config.ARGB_8888;
699                    break;
700            }
701        }
702
703        if (m == null || m.isIdentity()) {
704            bitmap = createBitmap(neww, newh, newConfig, source.hasAlpha());
705            paint = null;   // not needed
706        } else {
707            final boolean transformed = !m.rectStaysRect();
708
709            RectF deviceR = new RectF();
710            m.mapRect(deviceR, dstR);
711
712            neww = Math.round(deviceR.width());
713            newh = Math.round(deviceR.height());
714
715            bitmap = createBitmap(neww, newh, transformed ? Config.ARGB_8888 : newConfig,
716                    transformed || source.hasAlpha());
717
718            canvas.translate(-deviceR.left, -deviceR.top);
719            canvas.concat(m);
720
721            paint = new Paint();
722            paint.setFilterBitmap(filter);
723            if (transformed) {
724                paint.setAntiAlias(true);
725            }
726        }
727
728        // The new bitmap was created from a known bitmap source so assume that
729        // they use the same density
730        bitmap.mDensity = source.mDensity;
731        bitmap.setHasAlpha(source.hasAlpha());
732        bitmap.setPremultiplied(source.mRequestPremultiplied);
733
734        canvas.setBitmap(bitmap);
735        canvas.drawBitmap(source, srcR, dstR, paint);
736        canvas.setBitmap(null);
737
738        return bitmap;
739    }
740
741    /**
742     * Returns a mutable bitmap with the specified width and height.  Its
743     * initial density is as per {@link #getDensity}.
744     *
745     * @param width    The width of the bitmap
746     * @param height   The height of the bitmap
747     * @param config   The bitmap config to create.
748     * @throws IllegalArgumentException if the width or height are <= 0
749     */
750    public static Bitmap createBitmap(int width, int height, Config config) {
751        return createBitmap(width, height, config, true);
752    }
753
754    /**
755     * Returns a mutable bitmap with the specified width and height.  Its
756     * initial density is determined from the given {@link DisplayMetrics}.
757     *
758     * @param display  Display metrics for the display this bitmap will be
759     *                 drawn on.
760     * @param width    The width of the bitmap
761     * @param height   The height of the bitmap
762     * @param config   The bitmap config to create.
763     * @throws IllegalArgumentException if the width or height are <= 0
764     */
765    public static Bitmap createBitmap(DisplayMetrics display, int width,
766            int height, Config config) {
767        return createBitmap(display, width, height, config, true);
768    }
769
770    /**
771     * Returns a mutable bitmap with the specified width and height.  Its
772     * initial density is as per {@link #getDensity}.
773     *
774     * @param width    The width of the bitmap
775     * @param height   The height of the bitmap
776     * @param config   The bitmap config to create.
777     * @param hasAlpha If the bitmap is ARGB_8888 this flag can be used to mark the
778     *                 bitmap as opaque. Doing so will clear the bitmap in black
779     *                 instead of transparent.
780     *
781     * @throws IllegalArgumentException if the width or height are <= 0
782     */
783    private static Bitmap createBitmap(int width, int height, Config config, boolean hasAlpha) {
784        return createBitmap(null, width, height, config, hasAlpha);
785    }
786
787    /**
788     * Returns a mutable bitmap with the specified width and height.  Its
789     * initial density is determined from the given {@link DisplayMetrics}.
790     *
791     * @param display  Display metrics for the display this bitmap will be
792     *                 drawn on.
793     * @param width    The width of the bitmap
794     * @param height   The height of the bitmap
795     * @param config   The bitmap config to create.
796     * @param hasAlpha If the bitmap is ARGB_8888 this flag can be used to mark the
797     *                 bitmap as opaque. Doing so will clear the bitmap in black
798     *                 instead of transparent.
799     *
800     * @throws IllegalArgumentException if the width or height are <= 0
801     */
802    private static Bitmap createBitmap(DisplayMetrics display, int width, int height,
803            Config config, boolean hasAlpha) {
804        if (width <= 0 || height <= 0) {
805            throw new IllegalArgumentException("width and height must be > 0");
806        }
807        Bitmap bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true);
808        if (display != null) {
809            bm.mDensity = display.densityDpi;
810        }
811        bm.setHasAlpha(hasAlpha);
812        if (config == Config.ARGB_8888 && !hasAlpha) {
813            nativeErase(bm.mFinalizer.mNativeBitmap, 0xff000000);
814        }
815        // No need to initialize the bitmap to zeroes with other configs;
816        // it is backed by a VM byte array which is by definition preinitialized
817        // to all zeroes.
818        return bm;
819    }
820
821    /**
822     * Returns a immutable bitmap with the specified width and height, with each
823     * pixel value set to the corresponding value in the colors array.  Its
824     * initial density is as per {@link #getDensity}.
825     *
826     * @param colors   Array of {@link Color} used to initialize the pixels.
827     * @param offset   Number of values to skip before the first color in the
828     *                 array of colors.
829     * @param stride   Number of colors in the array between rows (must be >=
830     *                 width or <= -width).
831     * @param width    The width of the bitmap
832     * @param height   The height of the bitmap
833     * @param config   The bitmap config to create. If the config does not
834     *                 support per-pixel alpha (e.g. RGB_565), then the alpha
835     *                 bytes in the colors[] will be ignored (assumed to be FF)
836     * @throws IllegalArgumentException if the width or height are <= 0, or if
837     *         the color array's length is less than the number of pixels.
838     */
839    public static Bitmap createBitmap(int colors[], int offset, int stride,
840            int width, int height, Config config) {
841        return createBitmap(null, colors, offset, stride, width, height, config);
842    }
843
844    /**
845     * Returns a immutable bitmap with the specified width and height, with each
846     * pixel value set to the corresponding value in the colors array.  Its
847     * initial density is determined from the given {@link DisplayMetrics}.
848     *
849     * @param display  Display metrics for the display this bitmap will be
850     *                 drawn on.
851     * @param colors   Array of {@link Color} used to initialize the pixels.
852     * @param offset   Number of values to skip before the first color in the
853     *                 array of colors.
854     * @param stride   Number of colors in the array between rows (must be >=
855     *                 width or <= -width).
856     * @param width    The width of the bitmap
857     * @param height   The height of the bitmap
858     * @param config   The bitmap config to create. If the config does not
859     *                 support per-pixel alpha (e.g. RGB_565), then the alpha
860     *                 bytes in the colors[] will be ignored (assumed to be FF)
861     * @throws IllegalArgumentException if the width or height are <= 0, or if
862     *         the color array's length is less than the number of pixels.
863     */
864    public static Bitmap createBitmap(DisplayMetrics display, int colors[],
865            int offset, int stride, int width, int height, Config config) {
866
867        checkWidthHeight(width, height);
868        if (Math.abs(stride) < width) {
869            throw new IllegalArgumentException("abs(stride) must be >= width");
870        }
871        int lastScanline = offset + (height - 1) * stride;
872        int length = colors.length;
873        if (offset < 0 || (offset + width > length) || lastScanline < 0 ||
874                (lastScanline + width > length)) {
875            throw new ArrayIndexOutOfBoundsException();
876        }
877        if (width <= 0 || height <= 0) {
878            throw new IllegalArgumentException("width and height must be > 0");
879        }
880        Bitmap bm = nativeCreate(colors, offset, stride, width, height,
881                            config.nativeInt, false);
882        if (display != null) {
883            bm.mDensity = display.densityDpi;
884        }
885        return bm;
886    }
887
888    /**
889     * Returns a immutable bitmap with the specified width and height, with each
890     * pixel value set to the corresponding value in the colors array.  Its
891     * initial density is as per {@link #getDensity}.
892     *
893     * @param colors   Array of {@link Color} used to initialize the pixels.
894     *                 This array must be at least as large as width * height.
895     * @param width    The width of the bitmap
896     * @param height   The height of the bitmap
897     * @param config   The bitmap config to create. If the config does not
898     *                 support per-pixel alpha (e.g. RGB_565), then the alpha
899     *                 bytes in the colors[] will be ignored (assumed to be FF)
900     * @throws IllegalArgumentException if the width or height are <= 0, or if
901     *         the color array's length is less than the number of pixels.
902     */
903    public static Bitmap createBitmap(int colors[], int width, int height, Config config) {
904        return createBitmap(null, colors, 0, width, width, height, config);
905    }
906
907    /**
908     * Returns a immutable bitmap with the specified width and height, with each
909     * pixel value set to the corresponding value in the colors array.  Its
910     * initial density is determined from the given {@link DisplayMetrics}.
911     *
912     * @param display  Display metrics for the display this bitmap will be
913     *                 drawn on.
914     * @param colors   Array of {@link Color} used to initialize the pixels.
915     *                 This array must be at least as large as width * height.
916     * @param width    The width of the bitmap
917     * @param height   The height of the bitmap
918     * @param config   The bitmap config to create. If the config does not
919     *                 support per-pixel alpha (e.g. RGB_565), then the alpha
920     *                 bytes in the colors[] will be ignored (assumed to be FF)
921     * @throws IllegalArgumentException if the width or height are <= 0, or if
922     *         the color array's length is less than the number of pixels.
923     */
924    public static Bitmap createBitmap(DisplayMetrics display, int colors[],
925            int width, int height, Config config) {
926        return createBitmap(display, colors, 0, width, width, height, config);
927    }
928
929    /**
930     * Returns an optional array of private data, used by the UI system for
931     * some bitmaps. Not intended to be called by applications.
932     */
933    public byte[] getNinePatchChunk() {
934        return mNinePatchChunk;
935    }
936
937    /**
938     * Populates a rectangle with the bitmap's optical insets.
939     *
940     * @param outInsets Rect to populate with optical insets
941     * @hide
942     */
943    public void getOpticalInsets(@NonNull Rect outInsets) {
944        if (mNinePatchInsets == null) {
945            outInsets.setEmpty();
946        } else {
947            outInsets.set(mNinePatchInsets.opticalRect);
948        }
949    }
950
951    /** @hide */
952    public NinePatch.InsetStruct getNinePatchInsets() {
953        return mNinePatchInsets;
954    }
955
956    /**
957     * Specifies the known formats a bitmap can be compressed into
958     */
959    public enum CompressFormat {
960        JPEG    (0),
961        PNG     (1),
962        WEBP    (2);
963
964        CompressFormat(int nativeInt) {
965            this.nativeInt = nativeInt;
966        }
967        final int nativeInt;
968    }
969
970    /**
971     * Number of bytes of temp storage we use for communicating between the
972     * native compressor and the java OutputStream.
973     */
974    private final static int WORKING_COMPRESS_STORAGE = 4096;
975
976    /**
977     * Write a compressed version of the bitmap to the specified outputstream.
978     * If this returns true, the bitmap can be reconstructed by passing a
979     * corresponding inputstream to BitmapFactory.decodeStream(). Note: not
980     * all Formats support all bitmap configs directly, so it is possible that
981     * the returned bitmap from BitmapFactory could be in a different bitdepth,
982     * and/or may have lost per-pixel alpha (e.g. JPEG only supports opaque
983     * pixels).
984     *
985     * @param format   The format of the compressed image
986     * @param quality  Hint to the compressor, 0-100. 0 meaning compress for
987     *                 small size, 100 meaning compress for max quality. Some
988     *                 formats, like PNG which is lossless, will ignore the
989     *                 quality setting
990     * @param stream   The outputstream to write the compressed data.
991     * @return true if successfully compressed to the specified stream.
992     */
993    public boolean compress(CompressFormat format, int quality, OutputStream stream) {
994        checkRecycled("Can't compress a recycled bitmap");
995        // do explicit check before calling the native method
996        if (stream == null) {
997            throw new NullPointerException();
998        }
999        if (quality < 0 || quality > 100) {
1000            throw new IllegalArgumentException("quality must be 0..100");
1001        }
1002        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "Bitmap.compress");
1003        boolean result = nativeCompress(mFinalizer.mNativeBitmap, format.nativeInt,
1004                quality, stream, new byte[WORKING_COMPRESS_STORAGE]);
1005        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
1006        return result;
1007    }
1008
1009    /**
1010     * Returns true if the bitmap is marked as mutable (i.e.&nbsp;can be drawn into)
1011     */
1012    public final boolean isMutable() {
1013        return mIsMutable;
1014    }
1015
1016    /**
1017     * <p>Indicates whether pixels stored in this bitmaps are stored pre-multiplied.
1018     * When a pixel is pre-multiplied, the RGB components have been multiplied by
1019     * the alpha component. For instance, if the original color is a 50%
1020     * translucent red <code>(128, 255, 0, 0)</code>, the pre-multiplied form is
1021     * <code>(128, 128, 0, 0)</code>.</p>
1022     *
1023     * <p>This method always returns false if {@link #getConfig()} is
1024     * {@link Bitmap.Config#RGB_565}.</p>
1025     *
1026     * <p>The return value is undefined if {@link #getConfig()} is
1027     * {@link Bitmap.Config#ALPHA_8}.</p>
1028     *
1029     * <p>This method only returns true if {@link #hasAlpha()} returns true.
1030     * A bitmap with no alpha channel can be used both as a pre-multiplied and
1031     * as a non pre-multiplied bitmap.</p>
1032     *
1033     * <p>Only pre-multiplied bitmaps may be drawn by the view system or
1034     * {@link Canvas}. If a non-pre-multiplied bitmap with an alpha channel is
1035     * drawn to a Canvas, a RuntimeException will be thrown.</p>
1036     *
1037     * @return true if the underlying pixels have been pre-multiplied, false
1038     *         otherwise
1039     *
1040     * @see Bitmap#setPremultiplied(boolean)
1041     * @see BitmapFactory.Options#inPremultiplied
1042     */
1043    public final boolean isPremultiplied() {
1044        if (mRecycled) return false;
1045        return nativeIsPremultiplied(mFinalizer.mNativeBitmap);
1046    }
1047
1048    /**
1049     * Sets whether the bitmap should treat its data as pre-multiplied.
1050     *
1051     * <p>Bitmaps are always treated as pre-multiplied by the view system and
1052     * {@link Canvas} for performance reasons. Storing un-pre-multiplied data in
1053     * a Bitmap (through {@link #setPixel}, {@link #setPixels}, or {@link
1054     * BitmapFactory.Options#inPremultiplied BitmapFactory.Options.inPremultiplied})
1055     * can lead to incorrect blending if drawn by the framework.</p>
1056     *
1057     * <p>This method will not affect the behavior of a bitmap without an alpha
1058     * channel, or if {@link #hasAlpha()} returns false.</p>
1059     *
1060     * <p>Calling {@link #createBitmap} or {@link #createScaledBitmap} with a source
1061     * Bitmap whose colors are not pre-multiplied may result in a RuntimeException,
1062     * since those functions require drawing the source, which is not supported for
1063     * un-pre-multiplied Bitmaps.</p>
1064     *
1065     * @see Bitmap#isPremultiplied()
1066     * @see BitmapFactory.Options#inPremultiplied
1067     */
1068    public final void setPremultiplied(boolean premultiplied) {
1069        checkRecycled("setPremultiplied called on a recycled bitmap");
1070        mRequestPremultiplied = premultiplied;
1071        nativeSetPremultiplied(mFinalizer.mNativeBitmap, premultiplied);
1072    }
1073
1074    /** Returns the bitmap's width */
1075    public final int getWidth() {
1076        return mWidth;
1077    }
1078
1079    /** Returns the bitmap's height */
1080    public final int getHeight() {
1081        return mHeight;
1082    }
1083
1084    /**
1085     * Convenience for calling {@link #getScaledWidth(int)} with the target
1086     * density of the given {@link Canvas}.
1087     */
1088    public int getScaledWidth(Canvas canvas) {
1089        return scaleFromDensity(getWidth(), mDensity, canvas.mDensity);
1090    }
1091
1092    /**
1093     * Convenience for calling {@link #getScaledHeight(int)} with the target
1094     * density of the given {@link Canvas}.
1095     */
1096    public int getScaledHeight(Canvas canvas) {
1097        return scaleFromDensity(getHeight(), mDensity, canvas.mDensity);
1098    }
1099
1100    /**
1101     * Convenience for calling {@link #getScaledWidth(int)} with the target
1102     * density of the given {@link DisplayMetrics}.
1103     */
1104    public int getScaledWidth(DisplayMetrics metrics) {
1105        return scaleFromDensity(getWidth(), mDensity, metrics.densityDpi);
1106    }
1107
1108    /**
1109     * Convenience for calling {@link #getScaledHeight(int)} with the target
1110     * density of the given {@link DisplayMetrics}.
1111     */
1112    public int getScaledHeight(DisplayMetrics metrics) {
1113        return scaleFromDensity(getHeight(), mDensity, metrics.densityDpi);
1114    }
1115
1116    /**
1117     * Convenience method that returns the width of this bitmap divided
1118     * by the density scale factor.
1119     *
1120     * @param targetDensity The density of the target canvas of the bitmap.
1121     * @return The scaled width of this bitmap, according to the density scale factor.
1122     */
1123    public int getScaledWidth(int targetDensity) {
1124        return scaleFromDensity(getWidth(), mDensity, targetDensity);
1125    }
1126
1127    /**
1128     * Convenience method that returns the height of this bitmap divided
1129     * by the density scale factor.
1130     *
1131     * @param targetDensity The density of the target canvas of the bitmap.
1132     * @return The scaled height of this bitmap, according to the density scale factor.
1133     */
1134    public int getScaledHeight(int targetDensity) {
1135        return scaleFromDensity(getHeight(), mDensity, targetDensity);
1136    }
1137
1138    /**
1139     * @hide
1140     */
1141    static public int scaleFromDensity(int size, int sdensity, int tdensity) {
1142        if (sdensity == DENSITY_NONE || tdensity == DENSITY_NONE || sdensity == tdensity) {
1143            return size;
1144        }
1145
1146        // Scale by tdensity / sdensity, rounding up.
1147        return ((size * tdensity) + (sdensity >> 1)) / sdensity;
1148    }
1149
1150    /**
1151     * Return the number of bytes between rows in the bitmap's pixels. Note that
1152     * this refers to the pixels as stored natively by the bitmap. If you call
1153     * getPixels() or setPixels(), then the pixels are uniformly treated as
1154     * 32bit values, packed according to the Color class.
1155     *
1156     * <p>As of {@link android.os.Build.VERSION_CODES#KITKAT}, this method
1157     * should not be used to calculate the memory usage of the bitmap. Instead,
1158     * see {@link #getAllocationByteCount()}.
1159     *
1160     * @return number of bytes between rows of the native bitmap pixels.
1161     */
1162    public final int getRowBytes() {
1163        return nativeRowBytes(mFinalizer.mNativeBitmap);
1164    }
1165
1166    /**
1167     * Returns the minimum number of bytes that can be used to store this bitmap's pixels.
1168     *
1169     * <p>As of {@link android.os.Build.VERSION_CODES#KITKAT}, the result of this method can
1170     * no longer be used to determine memory usage of a bitmap. See {@link
1171     * #getAllocationByteCount()}.</p>
1172     */
1173    public final int getByteCount() {
1174        // int result permits bitmaps up to 46,340 x 46,340
1175        return getRowBytes() * getHeight();
1176    }
1177
1178    /**
1179     * Returns the size of the allocated memory used to store this bitmap's pixels.
1180     *
1181     * <p>This can be larger than the result of {@link #getByteCount()} if a bitmap is reused to
1182     * decode other bitmaps of smaller size, or by manual reconfiguration. See {@link
1183     * #reconfigure(int, int, Config)}, {@link #setWidth(int)}, {@link #setHeight(int)}, {@link
1184     * #setConfig(Bitmap.Config)}, and {@link BitmapFactory.Options#inBitmap
1185     * BitmapFactory.Options.inBitmap}. If a bitmap is not modified in this way, this value will be
1186     * the same as that returned by {@link #getByteCount()}.</p>
1187     *
1188     * <p>This value will not change over the lifetime of a Bitmap.</p>
1189     *
1190     * @see #reconfigure(int, int, Config)
1191     */
1192    public final int getAllocationByteCount() {
1193        if (mBuffer == null) {
1194            // native backed bitmaps don't support reconfiguration,
1195            // so alloc size is always content size
1196            return getByteCount();
1197        }
1198        return mBuffer.length;
1199    }
1200
1201    /**
1202     * If the bitmap's internal config is in one of the public formats, return
1203     * that config, otherwise return null.
1204     */
1205    public final Config getConfig() {
1206        if (mRecycled) return Config.ARGB_8888;
1207        return Config.nativeToConfig(nativeConfig(mFinalizer.mNativeBitmap));
1208    }
1209
1210    /** Returns true if the bitmap's config supports per-pixel alpha, and
1211     * if the pixels may contain non-opaque alpha values. For some configs,
1212     * this is always false (e.g. RGB_565), since they do not support per-pixel
1213     * alpha. However, for configs that do, the bitmap may be flagged to be
1214     * known that all of its pixels are opaque. In this case hasAlpha() will
1215     * also return false. If a config such as ARGB_8888 is not so flagged,
1216     * it will return true by default.
1217     */
1218    public final boolean hasAlpha() {
1219        if (mRecycled) return false;
1220        return nativeHasAlpha(mFinalizer.mNativeBitmap);
1221    }
1222
1223    /**
1224     * Tell the bitmap if all of the pixels are known to be opaque (false)
1225     * or if some of the pixels may contain non-opaque alpha values (true).
1226     * Note, for some configs (e.g. RGB_565) this call is ignored, since it
1227     * does not support per-pixel alpha values.
1228     *
1229     * This is meant as a drawing hint, as in some cases a bitmap that is known
1230     * to be opaque can take a faster drawing case than one that may have
1231     * non-opaque per-pixel alpha values.
1232     */
1233    public void setHasAlpha(boolean hasAlpha) {
1234        checkRecycled("setHasAlpha called on a recycled bitmap");
1235        nativeSetHasAlpha(mFinalizer.mNativeBitmap, hasAlpha, mRequestPremultiplied);
1236    }
1237
1238    /**
1239     * Indicates whether the renderer responsible for drawing this
1240     * bitmap should attempt to use mipmaps when this bitmap is drawn
1241     * scaled down.
1242     *
1243     * If you know that you are going to draw this bitmap at less than
1244     * 50% of its original size, you may be able to obtain a higher
1245     * quality
1246     *
1247     * This property is only a suggestion that can be ignored by the
1248     * renderer. It is not guaranteed to have any effect.
1249     *
1250     * @return true if the renderer should attempt to use mipmaps,
1251     *         false otherwise
1252     *
1253     * @see #setHasMipMap(boolean)
1254     */
1255    public final boolean hasMipMap() {
1256        if (mRecycled) return false;
1257        return nativeHasMipMap(mFinalizer.mNativeBitmap);
1258    }
1259
1260    /**
1261     * Set a hint for the renderer responsible for drawing this bitmap
1262     * indicating that it should attempt to use mipmaps when this bitmap
1263     * is drawn scaled down.
1264     *
1265     * If you know that you are going to draw this bitmap at less than
1266     * 50% of its original size, you may be able to obtain a higher
1267     * quality by turning this property on.
1268     *
1269     * Note that if the renderer respects this hint it might have to
1270     * allocate extra memory to hold the mipmap levels for this bitmap.
1271     *
1272     * This property is only a suggestion that can be ignored by the
1273     * renderer. It is not guaranteed to have any effect.
1274     *
1275     * @param hasMipMap indicates whether the renderer should attempt
1276     *                  to use mipmaps
1277     *
1278     * @see #hasMipMap()
1279     */
1280    public final void setHasMipMap(boolean hasMipMap) {
1281        checkRecycled("setHasMipMap called on a recycled bitmap");
1282        nativeSetHasMipMap(mFinalizer.mNativeBitmap, hasMipMap);
1283    }
1284
1285    /**
1286     * Fills the bitmap's pixels with the specified {@link Color}.
1287     *
1288     * @throws IllegalStateException if the bitmap is not mutable.
1289     */
1290    public void eraseColor(@ColorInt int c) {
1291        checkRecycled("Can't erase a recycled bitmap");
1292        if (!isMutable()) {
1293            throw new IllegalStateException("cannot erase immutable bitmaps");
1294        }
1295        nativeErase(mFinalizer.mNativeBitmap, c);
1296    }
1297
1298    /**
1299     * Returns the {@link Color} at the specified location. Throws an exception
1300     * if x or y are out of bounds (negative or >= to the width or height
1301     * respectively). The returned color is a non-premultiplied ARGB value.
1302     *
1303     * @param x    The x coordinate (0...width-1) of the pixel to return
1304     * @param y    The y coordinate (0...height-1) of the pixel to return
1305     * @return     The argb {@link Color} at the specified coordinate
1306     * @throws IllegalArgumentException if x, y exceed the bitmap's bounds
1307     */
1308    @ColorInt
1309    public int getPixel(int x, int y) {
1310        checkRecycled("Can't call getPixel() on a recycled bitmap");
1311        checkPixelAccess(x, y);
1312        return nativeGetPixel(mFinalizer.mNativeBitmap, x, y);
1313    }
1314
1315    /**
1316     * Returns in pixels[] a copy of the data in the bitmap. Each value is
1317     * a packed int representing a {@link Color}. The stride parameter allows
1318     * the caller to allow for gaps in the returned pixels array between
1319     * rows. For normal packed results, just pass width for the stride value.
1320     * The returned colors are non-premultiplied ARGB values.
1321     *
1322     * @param pixels   The array to receive the bitmap's colors
1323     * @param offset   The first index to write into pixels[]
1324     * @param stride   The number of entries in pixels[] to skip between
1325     *                 rows (must be >= bitmap's width). Can be negative.
1326     * @param x        The x coordinate of the first pixel to read from
1327     *                 the bitmap
1328     * @param y        The y coordinate of the first pixel to read from
1329     *                 the bitmap
1330     * @param width    The number of pixels to read from each row
1331     * @param height   The number of rows to read
1332     *
1333     * @throws IllegalArgumentException if x, y, width, height exceed the
1334     *         bounds of the bitmap, or if abs(stride) < width.
1335     * @throws ArrayIndexOutOfBoundsException if the pixels array is too small
1336     *         to receive the specified number of pixels.
1337     */
1338    public void getPixels(@ColorInt int[] pixels, int offset, int stride,
1339                          int x, int y, int width, int height) {
1340        checkRecycled("Can't call getPixels() on a recycled bitmap");
1341        if (width == 0 || height == 0) {
1342            return; // nothing to do
1343        }
1344        checkPixelsAccess(x, y, width, height, offset, stride, pixels);
1345        nativeGetPixels(mFinalizer.mNativeBitmap, pixels, offset, stride,
1346                        x, y, width, height);
1347    }
1348
1349    /**
1350     * Shared code to check for illegal arguments passed to getPixel()
1351     * or setPixel()
1352     *
1353     * @param x x coordinate of the pixel
1354     * @param y y coordinate of the pixel
1355     */
1356    private void checkPixelAccess(int x, int y) {
1357        checkXYSign(x, y);
1358        if (x >= getWidth()) {
1359            throw new IllegalArgumentException("x must be < bitmap.width()");
1360        }
1361        if (y >= getHeight()) {
1362            throw new IllegalArgumentException("y must be < bitmap.height()");
1363        }
1364    }
1365
1366    /**
1367     * Shared code to check for illegal arguments passed to getPixels()
1368     * or setPixels()
1369     *
1370     * @param x left edge of the area of pixels to access
1371     * @param y top edge of the area of pixels to access
1372     * @param width width of the area of pixels to access
1373     * @param height height of the area of pixels to access
1374     * @param offset offset into pixels[] array
1375     * @param stride number of elements in pixels[] between each logical row
1376     * @param pixels array to hold the area of pixels being accessed
1377    */
1378    private void checkPixelsAccess(int x, int y, int width, int height,
1379                                   int offset, int stride, int pixels[]) {
1380        checkXYSign(x, y);
1381        if (width < 0) {
1382            throw new IllegalArgumentException("width must be >= 0");
1383        }
1384        if (height < 0) {
1385            throw new IllegalArgumentException("height must be >= 0");
1386        }
1387        if (x + width > getWidth()) {
1388            throw new IllegalArgumentException(
1389                    "x + width must be <= bitmap.width()");
1390        }
1391        if (y + height > getHeight()) {
1392            throw new IllegalArgumentException(
1393                    "y + height must be <= bitmap.height()");
1394        }
1395        if (Math.abs(stride) < width) {
1396            throw new IllegalArgumentException("abs(stride) must be >= width");
1397        }
1398        int lastScanline = offset + (height - 1) * stride;
1399        int length = pixels.length;
1400        if (offset < 0 || (offset + width > length)
1401                || lastScanline < 0
1402                || (lastScanline + width > length)) {
1403            throw new ArrayIndexOutOfBoundsException();
1404        }
1405    }
1406
1407    /**
1408     * <p>Write the specified {@link Color} into the bitmap (assuming it is
1409     * mutable) at the x,y coordinate. The color must be a
1410     * non-premultiplied ARGB value.</p>
1411     *
1412     * @param x     The x coordinate of the pixel to replace (0...width-1)
1413     * @param y     The y coordinate of the pixel to replace (0...height-1)
1414     * @param color The ARGB color to write into the bitmap
1415     *
1416     * @throws IllegalStateException if the bitmap is not mutable
1417     * @throws IllegalArgumentException if x, y are outside of the bitmap's
1418     *         bounds.
1419     */
1420    public void setPixel(int x, int y, @ColorInt int color) {
1421        checkRecycled("Can't call setPixel() on a recycled bitmap");
1422        if (!isMutable()) {
1423            throw new IllegalStateException();
1424        }
1425        checkPixelAccess(x, y);
1426        nativeSetPixel(mFinalizer.mNativeBitmap, x, y, color);
1427    }
1428
1429    /**
1430     * <p>Replace pixels in the bitmap with the colors in the array. Each element
1431     * in the array is a packed int prepresenting a non-premultiplied ARGB
1432     * {@link Color}.</p>
1433     *
1434     * @param pixels   The colors to write to the bitmap
1435     * @param offset   The index of the first color to read from pixels[]
1436     * @param stride   The number of colors in pixels[] to skip between rows.
1437     *                 Normally this value will be the same as the width of
1438     *                 the bitmap, but it can be larger (or negative).
1439     * @param x        The x coordinate of the first pixel to write to in
1440     *                 the bitmap.
1441     * @param y        The y coordinate of the first pixel to write to in
1442     *                 the bitmap.
1443     * @param width    The number of colors to copy from pixels[] per row
1444     * @param height   The number of rows to write to the bitmap
1445     *
1446     * @throws IllegalStateException if the bitmap is not mutable
1447     * @throws IllegalArgumentException if x, y, width, height are outside of
1448     *         the bitmap's bounds.
1449     * @throws ArrayIndexOutOfBoundsException if the pixels array is too small
1450     *         to receive the specified number of pixels.
1451     */
1452    public void setPixels(@ColorInt int[] pixels, int offset, int stride,
1453            int x, int y, int width, int height) {
1454        checkRecycled("Can't call setPixels() on a recycled bitmap");
1455        if (!isMutable()) {
1456            throw new IllegalStateException();
1457        }
1458        if (width == 0 || height == 0) {
1459            return; // nothing to do
1460        }
1461        checkPixelsAccess(x, y, width, height, offset, stride, pixels);
1462        nativeSetPixels(mFinalizer.mNativeBitmap, pixels, offset, stride,
1463                        x, y, width, height);
1464    }
1465
1466    public static final Parcelable.Creator<Bitmap> CREATOR
1467            = new Parcelable.Creator<Bitmap>() {
1468        /**
1469         * Rebuilds a bitmap previously stored with writeToParcel().
1470         *
1471         * @param p    Parcel object to read the bitmap from
1472         * @return a new bitmap created from the data in the parcel
1473         */
1474        public Bitmap createFromParcel(Parcel p) {
1475            Bitmap bm = nativeCreateFromParcel(p);
1476            if (bm == null) {
1477                throw new RuntimeException("Failed to unparcel Bitmap");
1478            }
1479            return bm;
1480        }
1481        public Bitmap[] newArray(int size) {
1482            return new Bitmap[size];
1483        }
1484    };
1485
1486    /**
1487     * No special parcel contents.
1488     */
1489    public int describeContents() {
1490        return 0;
1491    }
1492
1493    /**
1494     * Write the bitmap and its pixels to the parcel. The bitmap can be
1495     * rebuilt from the parcel by calling CREATOR.createFromParcel().
1496     * @param p    Parcel object to write the bitmap data into
1497     */
1498    public void writeToParcel(Parcel p, int flags) {
1499        checkRecycled("Can't parcel a recycled bitmap");
1500        if (!nativeWriteToParcel(mFinalizer.mNativeBitmap, mIsMutable, mDensity, p)) {
1501            throw new RuntimeException("native writeToParcel failed");
1502        }
1503    }
1504
1505    /**
1506     * Returns a new bitmap that captures the alpha values of the original.
1507     * This may be drawn with Canvas.drawBitmap(), where the color(s) will be
1508     * taken from the paint that is passed to the draw call.
1509     *
1510     * @return new bitmap containing the alpha channel of the original bitmap.
1511     */
1512    @CheckResult
1513    public Bitmap extractAlpha() {
1514        return extractAlpha(null, null);
1515    }
1516
1517    /**
1518     * Returns a new bitmap that captures the alpha values of the original.
1519     * These values may be affected by the optional Paint parameter, which
1520     * can contain its own alpha, and may also contain a MaskFilter which
1521     * could change the actual dimensions of the resulting bitmap (e.g.
1522     * a blur maskfilter might enlarge the resulting bitmap). If offsetXY
1523     * is not null, it returns the amount to offset the returned bitmap so
1524     * that it will logically align with the original. For example, if the
1525     * paint contains a blur of radius 2, then offsetXY[] would contains
1526     * -2, -2, so that drawing the alpha bitmap offset by (-2, -2) and then
1527     * drawing the original would result in the blur visually aligning with
1528     * the original.
1529     *
1530     * <p>The initial density of the returned bitmap is the same as the original's.
1531     *
1532     * @param paint Optional paint used to modify the alpha values in the
1533     *              resulting bitmap. Pass null for default behavior.
1534     * @param offsetXY Optional array that returns the X (index 0) and Y
1535     *                 (index 1) offset needed to position the returned bitmap
1536     *                 so that it visually lines up with the original.
1537     * @return new bitmap containing the (optionally modified by paint) alpha
1538     *         channel of the original bitmap. This may be drawn with
1539     *         Canvas.drawBitmap(), where the color(s) will be taken from the
1540     *         paint that is passed to the draw call.
1541     */
1542    @CheckResult
1543    public Bitmap extractAlpha(Paint paint, int[] offsetXY) {
1544        checkRecycled("Can't extractAlpha on a recycled bitmap");
1545        long nativePaint = paint != null ? paint.getNativeInstance() : 0;
1546        Bitmap bm = nativeExtractAlpha(mFinalizer.mNativeBitmap, nativePaint, offsetXY);
1547        if (bm == null) {
1548            throw new RuntimeException("Failed to extractAlpha on Bitmap");
1549        }
1550        bm.mDensity = mDensity;
1551        return bm;
1552    }
1553
1554    /**
1555     *  Given another bitmap, return true if it has the same dimensions, config,
1556     *  and pixel data as this bitmap. If any of those differ, return false.
1557     *  If other is null, return false.
1558     */
1559    public boolean sameAs(Bitmap other) {
1560        return this == other || (other != null
1561                && nativeSameAs(mFinalizer.mNativeBitmap, other.mFinalizer.mNativeBitmap));
1562    }
1563
1564    /**
1565     * Rebuilds any caches associated with the bitmap that are used for
1566     * drawing it. In the case of purgeable bitmaps, this call will attempt to
1567     * ensure that the pixels have been decoded.
1568     * If this is called on more than one bitmap in sequence, the priority is
1569     * given in LRU order (i.e. the last bitmap called will be given highest
1570     * priority).
1571     *
1572     * For bitmaps with no associated caches, this call is effectively a no-op,
1573     * and therefore is harmless.
1574     */
1575    public void prepareToDraw() {
1576        // TODO: Consider having this start an async upload?
1577        // With inPurgeable no-op'd there's currently no use for this
1578        // method, but it could have interesting future uses.
1579    }
1580
1581    /**
1582     * Refs the underlying SkPixelRef and returns a pointer to it.
1583     *
1584     * @hide
1585     * */
1586    public final long refSkPixelRef() {
1587        return nativeRefPixelRef(mNativePtr);
1588    }
1589
1590    private static class BitmapFinalizer {
1591        private long mNativeBitmap;
1592
1593        // Native memory allocated for the duration of the Bitmap,
1594        // if pixel data allocated into native memory, instead of java byte[]
1595        private int mNativeAllocationByteCount;
1596
1597        BitmapFinalizer(long nativeBitmap) {
1598            mNativeBitmap = nativeBitmap;
1599        }
1600
1601        public void setNativeAllocationByteCount(int nativeByteCount) {
1602            if (mNativeAllocationByteCount != 0) {
1603                VMRuntime.getRuntime().registerNativeFree(mNativeAllocationByteCount);
1604            }
1605            mNativeAllocationByteCount = nativeByteCount;
1606            if (mNativeAllocationByteCount != 0) {
1607                VMRuntime.getRuntime().registerNativeAllocation(mNativeAllocationByteCount);
1608            }
1609        }
1610
1611        @Override
1612        public void finalize() {
1613            try {
1614                super.finalize();
1615            } catch (Throwable t) {
1616                // Ignore
1617            } finally {
1618                setNativeAllocationByteCount(0);
1619                nativeDestructor(mNativeBitmap);
1620                mNativeBitmap = 0;
1621            }
1622        }
1623    }
1624
1625    //////////// native methods
1626
1627    private static native Bitmap nativeCreate(int[] colors, int offset,
1628                                              int stride, int width, int height,
1629                                              int nativeConfig, boolean mutable);
1630    private static native Bitmap nativeCopy(long nativeSrcBitmap, int nativeConfig,
1631                                            boolean isMutable);
1632    private static native void nativeDestructor(long nativeBitmap);
1633    private static native boolean nativeRecycle(long nativeBitmap);
1634    private static native void nativeReconfigure(long nativeBitmap, int width, int height,
1635                                                 int config, int allocSize,
1636                                                 boolean isPremultiplied);
1637
1638    private static native boolean nativeCompress(long nativeBitmap, int format,
1639                                            int quality, OutputStream stream,
1640                                            byte[] tempStorage);
1641    private static native void nativeErase(long nativeBitmap, int color);
1642    private static native int nativeRowBytes(long nativeBitmap);
1643    private static native int nativeConfig(long nativeBitmap);
1644
1645    private static native int nativeGetPixel(long nativeBitmap, int x, int y);
1646    private static native void nativeGetPixels(long nativeBitmap, int[] pixels,
1647                                               int offset, int stride, int x, int y,
1648                                               int width, int height);
1649
1650    private static native void nativeSetPixel(long nativeBitmap, int x, int y, int color);
1651    private static native void nativeSetPixels(long nativeBitmap, int[] colors,
1652                                               int offset, int stride, int x, int y,
1653                                               int width, int height);
1654    private static native void nativeCopyPixelsToBuffer(long nativeBitmap,
1655                                                        Buffer dst);
1656    private static native void nativeCopyPixelsFromBuffer(long nativeBitmap, Buffer src);
1657    private static native int nativeGenerationId(long nativeBitmap);
1658
1659    private static native Bitmap nativeCreateFromParcel(Parcel p);
1660    // returns true on success
1661    private static native boolean nativeWriteToParcel(long nativeBitmap,
1662                                                      boolean isMutable,
1663                                                      int density,
1664                                                      Parcel p);
1665    // returns a new bitmap built from the native bitmap's alpha, and the paint
1666    private static native Bitmap nativeExtractAlpha(long nativeBitmap,
1667                                                    long nativePaint,
1668                                                    int[] offsetXY);
1669
1670    private static native boolean nativeHasAlpha(long nativeBitmap);
1671    private static native boolean nativeIsPremultiplied(long nativeBitmap);
1672    private static native void nativeSetPremultiplied(long nativeBitmap,
1673                                                      boolean isPremul);
1674    private static native void nativeSetHasAlpha(long nativeBitmap,
1675                                                 boolean hasAlpha,
1676                                                 boolean requestPremul);
1677    private static native boolean nativeHasMipMap(long nativeBitmap);
1678    private static native void nativeSetHasMipMap(long nativeBitmap, boolean hasMipMap);
1679    private static native boolean nativeSameAs(long nativeBitmap0, long nativeBitmap1);
1680    private static native long nativeRefPixelRef(long nativeBitmap);
1681}
1682