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