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             nativeErase(bm.mNativeBitmap, 0xff000000);
    608             nativeSetHasAlpha(bm.mNativeBitmap, hasAlpha);
    609         } else {
    610             // No need to initialize it to zeroes; it is backed by a VM byte array
    611             // which is by definition preinitialized to all zeroes.
    612             //
    613             //nativeErase(bm.mNativeBitmap, 0);
    614         }
    615         return bm;
    616     }
    617 
    618     /**
    619      * Returns a immutable bitmap with the specified width and height, with each
    620      * pixel value set to the corresponding value in the colors array.  Its
    621      * initial density is as per {@link #getDensity}.
    622      *
    623      * @param colors   Array of {@link Color} used to initialize the pixels.
    624      * @param offset   Number of values to skip before the first color in the
    625      *                 array of colors.
    626      * @param stride   Number of colors in the array between rows (must be >=
    627      *                 width or <= -width).
    628      * @param width    The width of the bitmap
    629      * @param height   The height of the bitmap
    630      * @param config   The bitmap config to create. If the config does not
    631      *                 support per-pixel alpha (e.g. RGB_565), then the alpha
    632      *                 bytes in the colors[] will be ignored (assumed to be FF)
    633      * @throws IllegalArgumentException if the width or height are <= 0, or if
    634      *         the color array's length is less than the number of pixels.
    635      */
    636     public static Bitmap createBitmap(int colors[], int offset, int stride,
    637             int width, int height, Config config) {
    638 
    639         checkWidthHeight(width, height);
    640         if (Math.abs(stride) < width) {
    641             throw new IllegalArgumentException("abs(stride) must be >= width");
    642         }
    643         int lastScanline = offset + (height - 1) * stride;
    644         int length = colors.length;
    645         if (offset < 0 || (offset + width > length) || lastScanline < 0 ||
    646                 (lastScanline + width > length)) {
    647             throw new ArrayIndexOutOfBoundsException();
    648         }
    649         if (width <= 0 || height <= 0) {
    650             throw new IllegalArgumentException("width and height must be > 0");
    651         }
    652         return nativeCreate(colors, offset, stride, width, height,
    653                             config.nativeInt, false);
    654     }
    655 
    656     /**
    657      * Returns a immutable bitmap with the specified width and height, with each
    658      * pixel value set to the corresponding value in the colors array.  Its
    659      * initial density is as per {@link #getDensity}.
    660      *
    661      * @param colors   Array of {@link Color} used to initialize the pixels.
    662      *                 This array must be at least as large as width * height.
    663      * @param width    The width of the bitmap
    664      * @param height   The height of the bitmap
    665      * @param config   The bitmap config to create. If the config does not
    666      *                 support per-pixel alpha (e.g. RGB_565), then the alpha
    667      *                 bytes in the colors[] will be ignored (assumed to be FF)
    668      * @throws IllegalArgumentException if the width or height are <= 0, or if
    669      *         the color array's length is less than the number of pixels.
    670      */
    671     public static Bitmap createBitmap(int colors[], int width, int height, Config config) {
    672         return createBitmap(colors, 0, width, width, height, config);
    673     }
    674 
    675     /**
    676      * Returns an optional array of private data, used by the UI system for
    677      * some bitmaps. Not intended to be called by applications.
    678      */
    679     public byte[] getNinePatchChunk() {
    680         return mNinePatchChunk;
    681     }
    682 
    683     /**
    684      * Specifies the known formats a bitmap can be compressed into
    685      */
    686     public enum CompressFormat {
    687         JPEG    (0),
    688         PNG     (1),
    689         WEBP    (2);
    690 
    691         CompressFormat(int nativeInt) {
    692             this.nativeInt = nativeInt;
    693         }
    694         final int nativeInt;
    695     }
    696 
    697     /**
    698      * Number of bytes of temp storage we use for communicating between the
    699      * native compressor and the java OutputStream.
    700      */
    701     private final static int WORKING_COMPRESS_STORAGE = 4096;
    702 
    703     /**
    704      * Write a compressed version of the bitmap to the specified outputstream.
    705      * If this returns true, the bitmap can be reconstructed by passing a
    706      * corresponding inputstream to BitmapFactory.decodeStream(). Note: not
    707      * all Formats support all bitmap configs directly, so it is possible that
    708      * the returned bitmap from BitmapFactory could be in a different bitdepth,
    709      * and/or may have lost per-pixel alpha (e.g. JPEG only supports opaque
    710      * pixels).
    711      *
    712      * @param format   The format of the compressed image
    713      * @param quality  Hint to the compressor, 0-100. 0 meaning compress for
    714      *                 small size, 100 meaning compress for max quality. Some
    715      *                 formats, like PNG which is lossless, will ignore the
    716      *                 quality setting
    717      * @param stream   The outputstream to write the compressed data.
    718      * @return true if successfully compressed to the specified stream.
    719      */
    720     public boolean compress(CompressFormat format, int quality, OutputStream stream) {
    721         checkRecycled("Can't compress a recycled bitmap");
    722         // do explicit check before calling the native method
    723         if (stream == null) {
    724             throw new NullPointerException();
    725         }
    726         if (quality < 0 || quality > 100) {
    727             throw new IllegalArgumentException("quality must be 0..100");
    728         }
    729         return nativeCompress(mNativeBitmap, format.nativeInt, quality,
    730                               stream, new byte[WORKING_COMPRESS_STORAGE]);
    731     }
    732 
    733     /**
    734      * Returns true if the bitmap is marked as mutable (i.e. can be drawn into)
    735      */
    736     public final boolean isMutable() {
    737         return mIsMutable;
    738     }
    739 
    740     /** Returns the bitmap's width */
    741     public final int getWidth() {
    742         return mWidth == -1 ? mWidth = nativeWidth(mNativeBitmap) : mWidth;
    743     }
    744 
    745     /** Returns the bitmap's height */
    746     public final int getHeight() {
    747         return mHeight == -1 ? mHeight = nativeHeight(mNativeBitmap) : mHeight;
    748     }
    749 
    750     /**
    751      * Convenience for calling {@link #getScaledWidth(int)} with the target
    752      * density of the given {@link Canvas}.
    753      */
    754     public int getScaledWidth(Canvas canvas) {
    755         return scaleFromDensity(getWidth(), mDensity, canvas.mDensity);
    756     }
    757 
    758     /**
    759      * Convenience for calling {@link #getScaledHeight(int)} with the target
    760      * density of the given {@link Canvas}.
    761      */
    762     public int getScaledHeight(Canvas canvas) {
    763         return scaleFromDensity(getHeight(), mDensity, canvas.mDensity);
    764     }
    765 
    766     /**
    767      * Convenience for calling {@link #getScaledWidth(int)} with the target
    768      * density of the given {@link DisplayMetrics}.
    769      */
    770     public int getScaledWidth(DisplayMetrics metrics) {
    771         return scaleFromDensity(getWidth(), mDensity, metrics.densityDpi);
    772     }
    773 
    774     /**
    775      * Convenience for calling {@link #getScaledHeight(int)} with the target
    776      * density of the given {@link DisplayMetrics}.
    777      */
    778     public int getScaledHeight(DisplayMetrics metrics) {
    779         return scaleFromDensity(getHeight(), mDensity, metrics.densityDpi);
    780     }
    781 
    782     /**
    783      * Convenience method that returns the width of this bitmap divided
    784      * by the density scale factor.
    785      *
    786      * @param targetDensity The density of the target canvas of the bitmap.
    787      * @return The scaled width of this bitmap, according to the density scale factor.
    788      */
    789     public int getScaledWidth(int targetDensity) {
    790         return scaleFromDensity(getWidth(), mDensity, targetDensity);
    791     }
    792 
    793     /**
    794      * Convenience method that returns the height of this bitmap divided
    795      * by the density scale factor.
    796      *
    797      * @param targetDensity The density of the target canvas of the bitmap.
    798      * @return The scaled height of this bitmap, according to the density scale factor.
    799      */
    800     public int getScaledHeight(int targetDensity) {
    801         return scaleFromDensity(getHeight(), mDensity, targetDensity);
    802     }
    803 
    804     /**
    805      * @hide
    806      */
    807     static public int scaleFromDensity(int size, int sdensity, int tdensity) {
    808         if (sdensity == DENSITY_NONE || sdensity == tdensity) {
    809             return size;
    810         }
    811 
    812         // Scale by tdensity / sdensity, rounding up.
    813         return ((size * tdensity) + (sdensity >> 1)) / sdensity;
    814     }
    815 
    816     /**
    817      * Return the number of bytes between rows in the bitmap's pixels. Note that
    818      * this refers to the pixels as stored natively by the bitmap. If you call
    819      * getPixels() or setPixels(), then the pixels are uniformly treated as
    820      * 32bit values, packed according to the Color class.
    821      *
    822      * @return number of bytes between rows of the native bitmap pixels.
    823      */
    824     public final int getRowBytes() {
    825         return nativeRowBytes(mNativeBitmap);
    826     }
    827 
    828     /**
    829      * Returns the number of bytes used to store this bitmap's pixels.
    830      */
    831     public final int getByteCount() {
    832         // int result permits bitmaps up to 46,340 x 46,340
    833         return getRowBytes() * getHeight();
    834     }
    835 
    836     /**
    837      * If the bitmap's internal config is in one of the public formats, return
    838      * that config, otherwise return null.
    839      */
    840     public final Config getConfig() {
    841         return Config.nativeToConfig(nativeConfig(mNativeBitmap));
    842     }
    843 
    844     /** Returns true if the bitmap's config supports per-pixel alpha, and
    845      * if the pixels may contain non-opaque alpha values. For some configs,
    846      * this is always false (e.g. RGB_565), since they do not support per-pixel
    847      * alpha. However, for configs that do, the bitmap may be flagged to be
    848      * known that all of its pixels are opaque. In this case hasAlpha() will
    849      * also return false. If a config such as ARGB_8888 is not so flagged,
    850      * it will return true by default.
    851      */
    852     public final boolean hasAlpha() {
    853         return nativeHasAlpha(mNativeBitmap);
    854     }
    855 
    856     /**
    857      * Tell the bitmap if all of the pixels are known to be opaque (false)
    858      * or if some of the pixels may contain non-opaque alpha values (true).
    859      * Note, for some configs (e.g. RGB_565) this call is ignored, since it
    860      * does not support per-pixel alpha values.
    861      *
    862      * This is meant as a drawing hint, as in some cases a bitmap that is known
    863      * to be opaque can take a faster drawing case than one that may have
    864      * non-opaque per-pixel alpha values.
    865      */
    866     public void setHasAlpha(boolean hasAlpha) {
    867         nativeSetHasAlpha(mNativeBitmap, hasAlpha);
    868     }
    869 
    870     /**
    871      * Fills the bitmap's pixels with the specified {@link Color}.
    872      *
    873      * @throws IllegalStateException if the bitmap is not mutable.
    874      */
    875     public void eraseColor(int c) {
    876         checkRecycled("Can't erase a recycled bitmap");
    877         if (!isMutable()) {
    878             throw new IllegalStateException("cannot erase immutable bitmaps");
    879         }
    880         nativeErase(mNativeBitmap, c);
    881     }
    882 
    883     /**
    884      * Returns the {@link Color} at the specified location. Throws an exception
    885      * if x or y are out of bounds (negative or >= to the width or height
    886      * respectively).
    887      *
    888      * @param x    The x coordinate (0...width-1) of the pixel to return
    889      * @param y    The y coordinate (0...height-1) of the pixel to return
    890      * @return     The argb {@link Color} at the specified coordinate
    891      * @throws IllegalArgumentException if x, y exceed the bitmap's bounds
    892      */
    893     public int getPixel(int x, int y) {
    894         checkRecycled("Can't call getPixel() on a recycled bitmap");
    895         checkPixelAccess(x, y);
    896         return nativeGetPixel(mNativeBitmap, x, y);
    897     }
    898 
    899     /**
    900      * Returns in pixels[] a copy of the data in the bitmap. Each value is
    901      * a packed int representing a {@link Color}. The stride parameter allows
    902      * the caller to allow for gaps in the returned pixels array between
    903      * rows. For normal packed results, just pass width for the stride value.
    904      *
    905      * @param pixels   The array to receive the bitmap's colors
    906      * @param offset   The first index to write into pixels[]
    907      * @param stride   The number of entries in pixels[] to skip between
    908      *                 rows (must be >= bitmap's width). Can be negative.
    909      * @param x        The x coordinate of the first pixel to read from
    910      *                 the bitmap
    911      * @param y        The y coordinate of the first pixel to read from
    912      *                 the bitmap
    913      * @param width    The number of pixels to read from each row
    914      * @param height   The number of rows to read
    915      * @throws IllegalArgumentException if x, y, width, height exceed the
    916      *         bounds of the bitmap, or if abs(stride) < width.
    917      * @throws ArrayIndexOutOfBoundsException if the pixels array is too small
    918      *         to receive the specified number of pixels.
    919      */
    920     public void getPixels(int[] pixels, int offset, int stride,
    921                           int x, int y, int width, int height) {
    922         checkRecycled("Can't call getPixels() on a recycled bitmap");
    923         if (width == 0 || height == 0) {
    924             return; // nothing to do
    925         }
    926         checkPixelsAccess(x, y, width, height, offset, stride, pixels);
    927         nativeGetPixels(mNativeBitmap, pixels, offset, stride,
    928                         x, y, width, height);
    929     }
    930 
    931     /**
    932      * Shared code to check for illegal arguments passed to getPixel()
    933      * or setPixel()
    934      * @param x x coordinate of the pixel
    935      * @param y y coordinate of the pixel
    936      */
    937     private void checkPixelAccess(int x, int y) {
    938         checkXYSign(x, y);
    939         if (x >= getWidth()) {
    940             throw new IllegalArgumentException("x must be < bitmap.width()");
    941         }
    942         if (y >= getHeight()) {
    943             throw new IllegalArgumentException("y must be < bitmap.height()");
    944         }
    945     }
    946 
    947     /**
    948      * Shared code to check for illegal arguments passed to getPixels()
    949      * or setPixels()
    950      *
    951      * @param x left edge of the area of pixels to access
    952      * @param y top edge of the area of pixels to access
    953      * @param width width of the area of pixels to access
    954      * @param height height of the area of pixels to access
    955      * @param offset offset into pixels[] array
    956      * @param stride number of elements in pixels[] between each logical row
    957      * @param pixels array to hold the area of pixels being accessed
    958     */
    959     private void checkPixelsAccess(int x, int y, int width, int height,
    960                                    int offset, int stride, int pixels[]) {
    961         checkXYSign(x, y);
    962         if (width < 0) {
    963             throw new IllegalArgumentException("width must be >= 0");
    964         }
    965         if (height < 0) {
    966             throw new IllegalArgumentException("height must be >= 0");
    967         }
    968         if (x + width > getWidth()) {
    969             throw new IllegalArgumentException(
    970                     "x + width must be <= bitmap.width()");
    971         }
    972         if (y + height > getHeight()) {
    973             throw new IllegalArgumentException(
    974                     "y + height must be <= bitmap.height()");
    975         }
    976         if (Math.abs(stride) < width) {
    977             throw new IllegalArgumentException("abs(stride) must be >= width");
    978         }
    979         int lastScanline = offset + (height - 1) * stride;
    980         int length = pixels.length;
    981         if (offset < 0 || (offset + width > length)
    982                 || lastScanline < 0
    983                 || (lastScanline + width > length)) {
    984             throw new ArrayIndexOutOfBoundsException();
    985         }
    986     }
    987 
    988     /**
    989      * Write the specified {@link Color} into the bitmap (assuming it is
    990      * mutable) at the x,y coordinate.
    991      *
    992      * @param x     The x coordinate of the pixel to replace (0...width-1)
    993      * @param y     The y coordinate of the pixel to replace (0...height-1)
    994      * @param color The {@link Color} to write into the bitmap
    995      * @throws IllegalStateException if the bitmap is not mutable
    996      * @throws IllegalArgumentException if x, y are outside of the bitmap's
    997      *         bounds.
    998      */
    999     public void setPixel(int x, int y, int color) {
   1000         checkRecycled("Can't call setPixel() on a recycled bitmap");
   1001         if (!isMutable()) {
   1002             throw new IllegalStateException();
   1003         }
   1004         checkPixelAccess(x, y);
   1005         nativeSetPixel(mNativeBitmap, x, y, color);
   1006     }
   1007 
   1008     /**
   1009      * Replace pixels in the bitmap with the colors in the array. Each element
   1010      * in the array is a packed int prepresenting a {@link Color}
   1011      *
   1012      * @param pixels   The colors to write to the bitmap
   1013      * @param offset   The index of the first color to read from pixels[]
   1014      * @param stride   The number of colors in pixels[] to skip between rows.
   1015      *                 Normally this value will be the same as the width of
   1016      *                 the bitmap, but it can be larger (or negative).
   1017      * @param x        The x coordinate of the first pixel to write to in
   1018      *                 the bitmap.
   1019      * @param y        The y coordinate of the first pixel to write to in
   1020      *                 the bitmap.
   1021      * @param width    The number of colors to copy from pixels[] per row
   1022      * @param height   The number of rows to write to the bitmap
   1023      * @throws IllegalStateException if the bitmap is not mutable
   1024      * @throws IllegalArgumentException if x, y, width, height are outside of
   1025      *         the bitmap's bounds.
   1026      * @throws ArrayIndexOutOfBoundsException if the pixels array is too small
   1027      *         to receive the specified number of pixels.
   1028      */
   1029     public void setPixels(int[] pixels, int offset, int stride,
   1030                           int x, int y, int width, int height) {
   1031         checkRecycled("Can't call setPixels() on a recycled bitmap");
   1032         if (!isMutable()) {
   1033             throw new IllegalStateException();
   1034         }
   1035         if (width == 0 || height == 0) {
   1036             return; // nothing to do
   1037         }
   1038         checkPixelsAccess(x, y, width, height, offset, stride, pixels);
   1039         nativeSetPixels(mNativeBitmap, pixels, offset, stride,
   1040                         x, y, width, height);
   1041     }
   1042 
   1043     public static final Parcelable.Creator<Bitmap> CREATOR
   1044             = new Parcelable.Creator<Bitmap>() {
   1045         /**
   1046          * Rebuilds a bitmap previously stored with writeToParcel().
   1047          *
   1048          * @param p    Parcel object to read the bitmap from
   1049          * @return a new bitmap created from the data in the parcel
   1050          */
   1051         public Bitmap createFromParcel(Parcel p) {
   1052             Bitmap bm = nativeCreateFromParcel(p);
   1053             if (bm == null) {
   1054                 throw new RuntimeException("Failed to unparcel Bitmap");
   1055             }
   1056             return bm;
   1057         }
   1058         public Bitmap[] newArray(int size) {
   1059             return new Bitmap[size];
   1060         }
   1061     };
   1062 
   1063     /**
   1064      * No special parcel contents.
   1065      */
   1066     public int describeContents() {
   1067         return 0;
   1068     }
   1069 
   1070     /**
   1071      * Write the bitmap and its pixels to the parcel. The bitmap can be
   1072      * rebuilt from the parcel by calling CREATOR.createFromParcel().
   1073      * @param p    Parcel object to write the bitmap data into
   1074      */
   1075     public void writeToParcel(Parcel p, int flags) {
   1076         checkRecycled("Can't parcel a recycled bitmap");
   1077         if (!nativeWriteToParcel(mNativeBitmap, mIsMutable, mDensity, p)) {
   1078             throw new RuntimeException("native writeToParcel failed");
   1079         }
   1080     }
   1081 
   1082     /**
   1083      * Returns a new bitmap that captures the alpha values of the original.
   1084      * This may be drawn with Canvas.drawBitmap(), where the color(s) will be
   1085      * taken from the paint that is passed to the draw call.
   1086      *
   1087      * @return new bitmap containing the alpha channel of the original bitmap.
   1088      */
   1089     public Bitmap extractAlpha() {
   1090         return extractAlpha(null, null);
   1091     }
   1092 
   1093     /**
   1094      * Returns a new bitmap that captures the alpha values of the original.
   1095      * These values may be affected by the optional Paint parameter, which
   1096      * can contain its own alpha, and may also contain a MaskFilter which
   1097      * could change the actual dimensions of the resulting bitmap (e.g.
   1098      * a blur maskfilter might enlarge the resulting bitmap). If offsetXY
   1099      * is not null, it returns the amount to offset the returned bitmap so
   1100      * that it will logically align with the original. For example, if the
   1101      * paint contains a blur of radius 2, then offsetXY[] would contains
   1102      * -2, -2, so that drawing the alpha bitmap offset by (-2, -2) and then
   1103      * drawing the original would result in the blur visually aligning with
   1104      * the original.
   1105      *
   1106      * <p>The initial density of the returned bitmap is the same as the original's.
   1107      *
   1108      * @param paint Optional paint used to modify the alpha values in the
   1109      *              resulting bitmap. Pass null for default behavior.
   1110      * @param offsetXY Optional array that returns the X (index 0) and Y
   1111      *                 (index 1) offset needed to position the returned bitmap
   1112      *                 so that it visually lines up with the original.
   1113      * @return new bitmap containing the (optionally modified by paint) alpha
   1114      *         channel of the original bitmap. This may be drawn with
   1115      *         Canvas.drawBitmap(), where the color(s) will be taken from the
   1116      *         paint that is passed to the draw call.
   1117      */
   1118     public Bitmap extractAlpha(Paint paint, int[] offsetXY) {
   1119         checkRecycled("Can't extractAlpha on a recycled bitmap");
   1120         int nativePaint = paint != null ? paint.mNativePaint : 0;
   1121         Bitmap bm = nativeExtractAlpha(mNativeBitmap, nativePaint, offsetXY);
   1122         if (bm == null) {
   1123             throw new RuntimeException("Failed to extractAlpha on Bitmap");
   1124         }
   1125         bm.mDensity = mDensity;
   1126         return bm;
   1127     }
   1128 
   1129     /**
   1130      *  Given another bitmap, return true if it has the same dimensions, config,
   1131      *  and pixel data as this bitmap. If any of those differ, return false.
   1132      *  If other is null, return false.
   1133      */
   1134     public boolean sameAs(Bitmap other) {
   1135         return this == other || (other != null && nativeSameAs(mNativeBitmap, other.mNativeBitmap));
   1136     }
   1137 
   1138     /**
   1139      * Rebuilds any caches associated with the bitmap that are used for
   1140      * drawing it. In the case of purgeable bitmaps, this call will attempt to
   1141      * ensure that the pixels have been decoded.
   1142      * If this is called on more than one bitmap in sequence, the priority is
   1143      * given in LRU order (i.e. the last bitmap called will be given highest
   1144      * priority).
   1145      *
   1146      * For bitmaps with no associated caches, this call is effectively a no-op,
   1147      * and therefore is harmless.
   1148      */
   1149     public void prepareToDraw() {
   1150         nativePrepareToDraw(mNativeBitmap);
   1151     }
   1152 
   1153     private static class BitmapFinalizer {
   1154         private final int mNativeBitmap;
   1155 
   1156         BitmapFinalizer(int nativeBitmap) {
   1157             mNativeBitmap = nativeBitmap;
   1158         }
   1159 
   1160         @Override
   1161         public void finalize() {
   1162             try {
   1163                 super.finalize();
   1164             } catch (Throwable t) {
   1165                 // Ignore
   1166             } finally {
   1167                 nativeDestructor(mNativeBitmap);
   1168             }
   1169         }
   1170     }
   1171 
   1172     //////////// native methods
   1173 
   1174     private static native Bitmap nativeCreate(int[] colors, int offset,
   1175                                               int stride, int width, int height,
   1176                                             int nativeConfig, boolean mutable);
   1177     private static native Bitmap nativeCopy(int srcBitmap, int nativeConfig,
   1178                                             boolean isMutable);
   1179     private static native void nativeDestructor(int nativeBitmap);
   1180     private static native void nativeRecycle(int nativeBitmap);
   1181 
   1182     private static native boolean nativeCompress(int nativeBitmap, int format,
   1183                                             int quality, OutputStream stream,
   1184                                             byte[] tempStorage);
   1185     private static native void nativeErase(int nativeBitmap, int color);
   1186     private static native int nativeWidth(int nativeBitmap);
   1187     private static native int nativeHeight(int nativeBitmap);
   1188     private static native int nativeRowBytes(int nativeBitmap);
   1189     private static native int nativeConfig(int nativeBitmap);
   1190     private static native boolean nativeHasAlpha(int nativeBitmap);
   1191 
   1192     private static native int nativeGetPixel(int nativeBitmap, int x, int y);
   1193     private static native void nativeGetPixels(int nativeBitmap, int[] pixels,
   1194                                                int offset, int stride, int x,
   1195                                                int y, int width, int height);
   1196 
   1197     private static native void nativeSetPixel(int nativeBitmap, int x, int y,
   1198                                               int color);
   1199     private static native void nativeSetPixels(int nativeBitmap, int[] colors,
   1200                                                int offset, int stride, int x,
   1201                                                int y, int width, int height);
   1202     private static native void nativeCopyPixelsToBuffer(int nativeBitmap,
   1203                                                         Buffer dst);
   1204     private static native void nativeCopyPixelsFromBuffer(int nb, Buffer src);
   1205     private static native int nativeGenerationId(int nativeBitmap);
   1206 
   1207     private static native Bitmap nativeCreateFromParcel(Parcel p);
   1208     // returns true on success
   1209     private static native boolean nativeWriteToParcel(int nativeBitmap,
   1210                                                       boolean isMutable,
   1211                                                       int density,
   1212                                                       Parcel p);
   1213     // returns a new bitmap built from the native bitmap's alpha, and the paint
   1214     private static native Bitmap nativeExtractAlpha(int nativeBitmap,
   1215                                                     int nativePaint,
   1216                                                     int[] offsetXY);
   1217 
   1218     private static native void nativePrepareToDraw(int nativeBitmap);
   1219     private static native void nativeSetHasAlpha(int nBitmap, boolean hasAlpha);
   1220     private static native boolean nativeSameAs(int nb0, int nb1);
   1221 
   1222     /* package */ final int ni() {
   1223         return mNativeBitmap;
   1224     }
   1225 }
   1226