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