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