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