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.annotation.CheckResult;
     20 import android.annotation.ColorInt;
     21 import android.annotation.NonNull;
     22 import android.annotation.Nullable;
     23 import android.annotation.Size;
     24 import android.content.res.ResourcesImpl;
     25 import android.os.Parcel;
     26 import android.os.Parcelable;
     27 import android.os.StrictMode;
     28 import android.os.Trace;
     29 import android.util.DisplayMetrics;
     30 import android.util.Log;
     31 import libcore.util.NativeAllocationRegistry;
     32 
     33 import java.io.OutputStream;
     34 import java.nio.Buffer;
     35 import java.nio.ByteBuffer;
     36 import java.nio.IntBuffer;
     37 import java.nio.ShortBuffer;
     38 
     39 public final class Bitmap implements Parcelable {
     40     private static final String TAG = "Bitmap";
     41 
     42     /**
     43      * Indicates that the bitmap was created for an unknown pixel density.
     44      *
     45      * @see Bitmap#getDensity()
     46      * @see Bitmap#setDensity(int)
     47      */
     48     public static final int DENSITY_NONE = 0;
     49 
     50     // Estimated size of the Bitmap native allocation, not including
     51     // pixel data.
     52     private static final long NATIVE_ALLOCATION_SIZE = 32;
     53 
     54     // Convenience for JNI access
     55     private final long mNativePtr;
     56 
     57     private final boolean mIsMutable;
     58 
     59     /**
     60      * Represents whether the Bitmap's content is requested to be pre-multiplied.
     61      * Note that isPremultiplied() does not directly return this value, because
     62      * isPremultiplied() may never return true for a 565 Bitmap or a bitmap
     63      * without alpha.
     64      *
     65      * setPremultiplied() does directly set the value so that setConfig() and
     66      * setPremultiplied() aren't order dependent, despite being setters.
     67      *
     68      * The native bitmap's premultiplication state is kept up to date by
     69      * pushing down this preference for every config change.
     70      */
     71     private boolean mRequestPremultiplied;
     72 
     73     private byte[] mNinePatchChunk; // may be null
     74     private NinePatch.InsetStruct mNinePatchInsets; // may be null
     75     private int mWidth;
     76     private int mHeight;
     77     private boolean mRecycled;
     78 
     79     private ColorSpace mColorSpace;
     80 
     81     /** @hide */
     82     public int mDensity = getDefaultDensity();
     83 
     84     private static volatile int sDefaultDensity = -1;
     85 
     86     /** @hide Used only when ResourcesImpl.TRACE_FOR_DETAILED_PRELOAD is true. */
     87     public static volatile int sPreloadTracingNumInstantiatedBitmaps;
     88 
     89     /** @hide Used only when ResourcesImpl.TRACE_FOR_DETAILED_PRELOAD is true. */
     90     public static volatile long sPreloadTracingTotalBitmapsSize;
     91 
     92     /**
     93      * For backwards compatibility, allows the app layer to change the default
     94      * density when running old apps.
     95      * @hide
     96      */
     97     public static void setDefaultDensity(int density) {
     98         sDefaultDensity = density;
     99     }
    100 
    101     @SuppressWarnings("deprecation")
    102     static int getDefaultDensity() {
    103         if (sDefaultDensity >= 0) {
    104             return sDefaultDensity;
    105         }
    106         sDefaultDensity = DisplayMetrics.DENSITY_DEVICE;
    107         return sDefaultDensity;
    108     }
    109 
    110     /**
    111      * Private constructor that must received an already allocated native bitmap
    112      * int (pointer).
    113      */
    114     // called from JNI
    115     Bitmap(long nativeBitmap, int width, int height, int density,
    116             boolean isMutable, boolean requestPremultiplied,
    117             byte[] ninePatchChunk, NinePatch.InsetStruct ninePatchInsets) {
    118         if (nativeBitmap == 0) {
    119             throw new RuntimeException("internal error: native bitmap is 0");
    120         }
    121 
    122         mWidth = width;
    123         mHeight = height;
    124         mIsMutable = isMutable;
    125         mRequestPremultiplied = requestPremultiplied;
    126 
    127         mNinePatchChunk = ninePatchChunk;
    128         mNinePatchInsets = ninePatchInsets;
    129         if (density >= 0) {
    130             mDensity = density;
    131         }
    132 
    133         mNativePtr = nativeBitmap;
    134         long nativeSize = NATIVE_ALLOCATION_SIZE + getAllocationByteCount();
    135         NativeAllocationRegistry registry = new NativeAllocationRegistry(
    136             Bitmap.class.getClassLoader(), nativeGetNativeFinalizer(), nativeSize);
    137         registry.registerNativeAllocation(this, nativeBitmap);
    138 
    139         if (ResourcesImpl.TRACE_FOR_DETAILED_PRELOAD) {
    140             sPreloadTracingNumInstantiatedBitmaps++;
    141             sPreloadTracingTotalBitmapsSize += nativeSize;
    142         }
    143     }
    144 
    145     /**
    146      * Return the pointer to the native object.
    147      * @hide
    148      */
    149     public long getNativeInstance() {
    150         return mNativePtr;
    151     }
    152 
    153     /**
    154      * Native bitmap has been reconfigured, so set premult and cached
    155      * width/height values
    156      */
    157     @SuppressWarnings("unused") // called from JNI
    158     void reinit(int width, int height, boolean requestPremultiplied) {
    159         mWidth = width;
    160         mHeight = height;
    161         mRequestPremultiplied = requestPremultiplied;
    162         mColorSpace = null;
    163     }
    164 
    165     /**
    166      * <p>Returns the density for this bitmap.</p>
    167      *
    168      * <p>The default density is the same density as the current display,
    169      * unless the current application does not support different screen
    170      * densities in which case it is
    171      * {@link android.util.DisplayMetrics#DENSITY_DEFAULT}.  Note that
    172      * compatibility mode is determined by the application that was initially
    173      * loaded into a process -- applications that share the same process should
    174      * all have the same compatibility, or ensure they explicitly set the
    175      * density of their bitmaps appropriately.</p>
    176      *
    177      * @return A scaling factor of the default density or {@link #DENSITY_NONE}
    178      *         if the scaling factor is unknown.
    179      *
    180      * @see #setDensity(int)
    181      * @see android.util.DisplayMetrics#DENSITY_DEFAULT
    182      * @see android.util.DisplayMetrics#densityDpi
    183      * @see #DENSITY_NONE
    184      */
    185     public int getDensity() {
    186         if (mRecycled) {
    187             Log.w(TAG, "Called getDensity() on a recycle()'d bitmap! This is undefined behavior!");
    188         }
    189         return mDensity;
    190     }
    191 
    192     /**
    193      * <p>Specifies the density for this bitmap.  When the bitmap is
    194      * drawn to a Canvas that also has a density, it will be scaled
    195      * appropriately.</p>
    196      *
    197      * @param density The density scaling factor to use with this bitmap or
    198      *        {@link #DENSITY_NONE} if the density is unknown.
    199      *
    200      * @see #getDensity()
    201      * @see android.util.DisplayMetrics#DENSITY_DEFAULT
    202      * @see android.util.DisplayMetrics#densityDpi
    203      * @see #DENSITY_NONE
    204      */
    205     public void setDensity(int density) {
    206         mDensity = density;
    207     }
    208 
    209     /**
    210      * <p>Modifies the bitmap to have a specified width, height, and {@link
    211      * Config}, without affecting the underlying allocation backing the bitmap.
    212      * Bitmap pixel data is not re-initialized for the new configuration.</p>
    213      *
    214      * <p>This method can be used to avoid allocating a new bitmap, instead
    215      * reusing an existing bitmap's allocation for a new configuration of equal
    216      * or lesser size. If the Bitmap's allocation isn't large enough to support
    217      * the new configuration, an IllegalArgumentException will be thrown and the
    218      * bitmap will not be modified.</p>
    219      *
    220      * <p>The result of {@link #getByteCount()} will reflect the new configuration,
    221      * while {@link #getAllocationByteCount()} will reflect that of the initial
    222      * configuration.</p>
    223      *
    224      * <p>Note: This may change this result of hasAlpha(). When converting to 565,
    225      * the new bitmap will always be considered opaque. When converting from 565,
    226      * the new bitmap will be considered non-opaque, and will respect the value
    227      * set by setPremultiplied().</p>
    228      *
    229      * <p>WARNING: This method should NOT be called on a bitmap currently in use
    230      * by the view system, Canvas, or the AndroidBitmap NDK API. It does not
    231      * make guarantees about how the underlying pixel buffer is remapped to the
    232      * new config, just that the allocation is reused. Additionally, the view
    233      * system does not account for bitmap properties being modifying during use,
    234      * e.g. while attached to drawables.</p>
    235      *
    236      * <p>In order to safely ensure that a Bitmap is no longer in use by the
    237      * View system it is necessary to wait for a draw pass to occur after
    238      * invalidate()'ing any view that had previously drawn the Bitmap in the last
    239      * draw pass due to hardware acceleration's caching of draw commands. As
    240      * an example, here is how this can be done for an ImageView:
    241      * <pre class="prettyprint">
    242      *      ImageView myImageView = ...;
    243      *      final Bitmap myBitmap = ...;
    244      *      myImageView.setImageDrawable(null);
    245      *      myImageView.post(new Runnable() {
    246      *          public void run() {
    247      *              // myBitmap is now no longer in use by the ImageView
    248      *              // and can be safely reconfigured.
    249      *              myBitmap.reconfigure(...);
    250      *          }
    251      *      });
    252      * </pre></p>
    253      *
    254      * @see #setWidth(int)
    255      * @see #setHeight(int)
    256      * @see #setConfig(Config)
    257      */
    258     public void reconfigure(int width, int height, Config config) {
    259         checkRecycled("Can't call reconfigure() on a recycled bitmap");
    260         if (width <= 0 || height <= 0) {
    261             throw new IllegalArgumentException("width and height must be > 0");
    262         }
    263         if (!isMutable()) {
    264             throw new IllegalStateException("only mutable bitmaps may be reconfigured");
    265         }
    266 
    267         nativeReconfigure(mNativePtr, width, height, config.nativeInt, mRequestPremultiplied);
    268         mWidth = width;
    269         mHeight = height;
    270         mColorSpace = null;
    271     }
    272 
    273     /**
    274      * <p>Convenience method for calling {@link #reconfigure(int, int, Config)}
    275      * with the current height and config.</p>
    276      *
    277      * <p>WARNING: this method should not be used on bitmaps currently used by
    278      * the view system, see {@link #reconfigure(int, int, Config)} for more
    279      * details.</p>
    280      *
    281      * @see #reconfigure(int, int, Config)
    282      * @see #setHeight(int)
    283      * @see #setConfig(Config)
    284      */
    285     public void setWidth(int width) {
    286         reconfigure(width, getHeight(), getConfig());
    287     }
    288 
    289     /**
    290      * <p>Convenience method for calling {@link #reconfigure(int, int, Config)}
    291      * with the current width and config.</p>
    292      *
    293      * <p>WARNING: this method should not be used on bitmaps currently used by
    294      * the view system, see {@link #reconfigure(int, int, Config)} for more
    295      * details.</p>
    296      *
    297      * @see #reconfigure(int, int, Config)
    298      * @see #setWidth(int)
    299      * @see #setConfig(Config)
    300      */
    301     public void setHeight(int height) {
    302         reconfigure(getWidth(), height, getConfig());
    303     }
    304 
    305     /**
    306      * <p>Convenience method for calling {@link #reconfigure(int, int, Config)}
    307      * with the current height and width.</p>
    308      *
    309      * <p>WARNING: this method should not be used on bitmaps currently used by
    310      * the view system, see {@link #reconfigure(int, int, Config)} for more
    311      * details.</p>
    312      *
    313      * @see #reconfigure(int, int, Config)
    314      * @see #setWidth(int)
    315      * @see #setHeight(int)
    316      */
    317     public void setConfig(Config config) {
    318         reconfigure(getWidth(), getHeight(), config);
    319     }
    320 
    321     /**
    322      * Sets the nine patch chunk.
    323      *
    324      * @param chunk The definition of the nine patch
    325      *
    326      * @hide
    327      */
    328     public void setNinePatchChunk(byte[] chunk) {
    329         mNinePatchChunk = chunk;
    330     }
    331 
    332     /**
    333      * Free the native object associated with this bitmap, and clear the
    334      * reference to the pixel data. This will not free the pixel data synchronously;
    335      * it simply allows it to be garbage collected if there are no other references.
    336      * The bitmap is marked as "dead", meaning it will throw an exception if
    337      * getPixels() or setPixels() is called, and will draw nothing. This operation
    338      * cannot be reversed, so it should only be called if you are sure there are no
    339      * further uses for the bitmap. This is an advanced call, and normally need
    340      * not be called, since the normal GC process will free up this memory when
    341      * there are no more references to this bitmap.
    342      */
    343     public void recycle() {
    344         if (!mRecycled && mNativePtr != 0) {
    345             if (nativeRecycle(mNativePtr)) {
    346                 // return value indicates whether native pixel object was actually recycled.
    347                 // false indicates that it is still in use at the native level and these
    348                 // objects should not be collected now. They will be collected later when the
    349                 // Bitmap itself is collected.
    350                 mNinePatchChunk = null;
    351             }
    352             mRecycled = true;
    353         }
    354     }
    355 
    356     /**
    357      * Returns true if this bitmap has been recycled. If so, then it is an error
    358      * to try to access its pixels, and the bitmap will not draw.
    359      *
    360      * @return true if the bitmap has been recycled
    361      */
    362     public final boolean isRecycled() {
    363         return mRecycled;
    364     }
    365 
    366     /**
    367      * Returns the generation ID of this bitmap. The generation ID changes
    368      * whenever the bitmap is modified. This can be used as an efficient way to
    369      * check if a bitmap has changed.
    370      *
    371      * @return The current generation ID for this bitmap.
    372      */
    373     public int getGenerationId() {
    374         if (mRecycled) {
    375             Log.w(TAG, "Called getGenerationId() on a recycle()'d bitmap! This is undefined behavior!");
    376         }
    377         return nativeGenerationId(mNativePtr);
    378     }
    379 
    380     /**
    381      * This is called by methods that want to throw an exception if the bitmap
    382      * has already been recycled.
    383      */
    384     private void checkRecycled(String errorMessage) {
    385         if (mRecycled) {
    386             throw new IllegalStateException(errorMessage);
    387         }
    388     }
    389 
    390     /**
    391      * This is called by methods that want to throw an exception if the bitmap
    392      * is {@link Config#HARDWARE}.
    393      */
    394     private void checkHardware(String errorMessage) {
    395         if (getConfig() == Config.HARDWARE) {
    396             throw new IllegalStateException(errorMessage);
    397         }
    398     }
    399 
    400     /**
    401      * Common code for checking that x and y are >= 0
    402      *
    403      * @param x x coordinate to ensure is >= 0
    404      * @param y y coordinate to ensure is >= 0
    405      */
    406     private static void checkXYSign(int x, int y) {
    407         if (x < 0) {
    408             throw new IllegalArgumentException("x must be >= 0");
    409         }
    410         if (y < 0) {
    411             throw new IllegalArgumentException("y must be >= 0");
    412         }
    413     }
    414 
    415     /**
    416      * Common code for checking that width and height are > 0
    417      *
    418      * @param width  width to ensure is > 0
    419      * @param height height to ensure is > 0
    420      */
    421     private static void checkWidthHeight(int width, int height) {
    422         if (width <= 0) {
    423             throw new IllegalArgumentException("width must be > 0");
    424         }
    425         if (height <= 0) {
    426             throw new IllegalArgumentException("height must be > 0");
    427         }
    428     }
    429 
    430     /**
    431      * Possible bitmap configurations. A bitmap configuration describes
    432      * how pixels are stored. This affects the quality (color depth) as
    433      * well as the ability to display transparent/translucent colors.
    434      */
    435     public enum Config {
    436         // these native values must match up with the enum in SkBitmap.h
    437 
    438         /**
    439          * Each pixel is stored as a single translucency (alpha) channel.
    440          * This is very useful to efficiently store masks for instance.
    441          * No color information is stored.
    442          * With this configuration, each pixel requires 1 byte of memory.
    443          */
    444         ALPHA_8     (1),
    445 
    446         /**
    447          * Each pixel is stored on 2 bytes and only the RGB channels are
    448          * encoded: red is stored with 5 bits of precision (32 possible
    449          * values), green is stored with 6 bits of precision (64 possible
    450          * values) and blue is stored with 5 bits of precision.
    451          *
    452          * This configuration can produce slight visual artifacts depending
    453          * on the configuration of the source. For instance, without
    454          * dithering, the result might show a greenish tint. To get better
    455          * results dithering should be applied.
    456          *
    457          * This configuration may be useful when using opaque bitmaps
    458          * that do not require high color fidelity.
    459          */
    460         RGB_565     (3),
    461 
    462         /**
    463          * Each pixel is stored on 2 bytes. The three RGB color channels
    464          * and the alpha channel (translucency) are stored with a 4 bits
    465          * precision (16 possible values.)
    466          *
    467          * This configuration is mostly useful if the application needs
    468          * to store translucency information but also needs to save
    469          * memory.
    470          *
    471          * It is recommended to use {@link #ARGB_8888} instead of this
    472          * configuration.
    473          *
    474          * Note: as of {@link android.os.Build.VERSION_CODES#KITKAT},
    475          * any bitmap created with this configuration will be created
    476          * using {@link #ARGB_8888} instead.
    477          *
    478          * @deprecated Because of the poor quality of this configuration,
    479          *             it is advised to use {@link #ARGB_8888} instead.
    480          */
    481         @Deprecated
    482         ARGB_4444   (4),
    483 
    484         /**
    485          * Each pixel is stored on 4 bytes. Each channel (RGB and alpha
    486          * for translucency) is stored with 8 bits of precision (256
    487          * possible values.)
    488          *
    489          * This configuration is very flexible and offers the best
    490          * quality. It should be used whenever possible.
    491          */
    492         ARGB_8888   (5),
    493 
    494         /**
    495          * Each pixels is stored on 8 bytes. Each channel (RGB and alpha
    496          * for translucency) is stored as a
    497          * {@link android.util.Half half-precision floating point value}.
    498          *
    499          * This configuration is particularly suited for wide-gamut and
    500          * HDR content.
    501          */
    502         RGBA_F16    (6),
    503 
    504         /**
    505          * Special configuration, when bitmap is stored only in graphic memory.
    506          * Bitmaps in this configuration are always immutable.
    507          *
    508          * It is optimal for cases, when the only operation with the bitmap is to draw it on a
    509          * screen.
    510          */
    511         HARDWARE    (7);
    512 
    513         final int nativeInt;
    514 
    515         private static Config sConfigs[] = {
    516             null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888, RGBA_F16, HARDWARE
    517         };
    518 
    519         Config(int ni) {
    520             this.nativeInt = ni;
    521         }
    522 
    523         static Config nativeToConfig(int ni) {
    524             return sConfigs[ni];
    525         }
    526     }
    527 
    528     /**
    529      * <p>Copy the bitmap's pixels into the specified buffer (allocated by the
    530      * caller). An exception is thrown if the buffer is not large enough to
    531      * hold all of the pixels (taking into account the number of bytes per
    532      * pixel) or if the Buffer subclass is not one of the support types
    533      * (ByteBuffer, ShortBuffer, IntBuffer).</p>
    534      * <p>The content of the bitmap is copied into the buffer as-is. This means
    535      * that if this bitmap stores its pixels pre-multiplied
    536      * (see {@link #isPremultiplied()}, the values in the buffer will also be
    537      * pre-multiplied. The pixels remain in the color space of the bitmap.</p>
    538      * <p>After this method returns, the current position of the buffer is
    539      * updated: the position is incremented by the number of elements written
    540      * in the buffer.</p>
    541      * @throws IllegalStateException if the bitmap's config is {@link Config#HARDWARE}
    542      */
    543     public void copyPixelsToBuffer(Buffer dst) {
    544         checkHardware("unable to copyPixelsToBuffer, "
    545                 + "pixel access is not supported on Config#HARDWARE bitmaps");
    546         int elements = dst.remaining();
    547         int shift;
    548         if (dst instanceof ByteBuffer) {
    549             shift = 0;
    550         } else if (dst instanceof ShortBuffer) {
    551             shift = 1;
    552         } else if (dst instanceof IntBuffer) {
    553             shift = 2;
    554         } else {
    555             throw new RuntimeException("unsupported Buffer subclass");
    556         }
    557 
    558         long bufferSize = (long)elements << shift;
    559         long pixelSize = getByteCount();
    560 
    561         if (bufferSize < pixelSize) {
    562             throw new RuntimeException("Buffer not large enough for pixels");
    563         }
    564 
    565         nativeCopyPixelsToBuffer(mNativePtr, dst);
    566 
    567         // now update the buffer's position
    568         int position = dst.position();
    569         position += pixelSize >> shift;
    570         dst.position(position);
    571     }
    572 
    573     /**
    574      * <p>Copy the pixels from the buffer, beginning at the current position,
    575      * overwriting the bitmap's pixels. The data in the buffer is not changed
    576      * in any way (unlike setPixels(), which converts from unpremultipled 32bit
    577      * to whatever the bitmap's native format is. The pixels in the source
    578      * buffer are assumed to be in the bitmap's color space.</p>
    579      * <p>After this method returns, the current position of the buffer is
    580      * updated: the position is incremented by the number of elements read from
    581      * the buffer. If you need to read the bitmap from the buffer again you must
    582      * first rewind the buffer.</p>
    583      * @throws IllegalStateException if the bitmap's config is {@link Config#HARDWARE}
    584      */
    585     public void copyPixelsFromBuffer(Buffer src) {
    586         checkRecycled("copyPixelsFromBuffer called on recycled bitmap");
    587         checkHardware("unable to copyPixelsFromBuffer, Config#HARDWARE bitmaps are immutable");
    588 
    589         int elements = src.remaining();
    590         int shift;
    591         if (src instanceof ByteBuffer) {
    592             shift = 0;
    593         } else if (src instanceof ShortBuffer) {
    594             shift = 1;
    595         } else if (src instanceof IntBuffer) {
    596             shift = 2;
    597         } else {
    598             throw new RuntimeException("unsupported Buffer subclass");
    599         }
    600 
    601         long bufferBytes = (long) elements << shift;
    602         long bitmapBytes = getByteCount();
    603 
    604         if (bufferBytes < bitmapBytes) {
    605             throw new RuntimeException("Buffer not large enough for pixels");
    606         }
    607 
    608         nativeCopyPixelsFromBuffer(mNativePtr, src);
    609 
    610         // now update the buffer's position
    611         int position = src.position();
    612         position += bitmapBytes >> shift;
    613         src.position(position);
    614     }
    615 
    616     private void noteHardwareBitmapSlowCall() {
    617         if (getConfig() == Config.HARDWARE) {
    618             StrictMode.noteSlowCall("Warning: attempt to read pixels from hardware "
    619                     + "bitmap, which is very slow operation");
    620         }
    621     }
    622 
    623     /**
    624      * Tries to make a new bitmap based on the dimensions of this bitmap,
    625      * setting the new bitmap's config to the one specified, and then copying
    626      * this bitmap's pixels into the new bitmap. If the conversion is not
    627      * supported, or the allocator fails, then this returns NULL.  The returned
    628      * bitmap has the same density and color space as the original.
    629      *
    630      * @param config    The desired config for the resulting bitmap
    631      * @param isMutable True if the resulting bitmap should be mutable (i.e.
    632      *                  its pixels can be modified)
    633      * @return the new bitmap, or null if the copy could not be made.
    634      * @throws IllegalArgumentException if config is {@link Config#HARDWARE} and isMutable is true
    635      */
    636     public Bitmap copy(Config config, boolean isMutable) {
    637         checkRecycled("Can't copy a recycled bitmap");
    638         if (config == Config.HARDWARE && isMutable) {
    639             throw new IllegalArgumentException("Hardware bitmaps are always immutable");
    640         }
    641         noteHardwareBitmapSlowCall();
    642         Bitmap b = nativeCopy(mNativePtr, config.nativeInt, isMutable);
    643         if (b != null) {
    644             b.setPremultiplied(mRequestPremultiplied);
    645             b.mDensity = mDensity;
    646         }
    647         return b;
    648     }
    649 
    650     /**
    651      * Creates a new immutable bitmap backed by ashmem which can efficiently
    652      * be passed between processes. The bitmap is assumed to be in the sRGB
    653      * color space.
    654      *
    655      * @hide
    656      */
    657     public Bitmap createAshmemBitmap() {
    658         checkRecycled("Can't copy a recycled bitmap");
    659         noteHardwareBitmapSlowCall();
    660         Bitmap b = nativeCopyAshmem(mNativePtr);
    661         if (b != null) {
    662             b.setPremultiplied(mRequestPremultiplied);
    663             b.mDensity = mDensity;
    664         }
    665         return b;
    666     }
    667 
    668     /**
    669      * Creates a new immutable bitmap backed by ashmem which can efficiently
    670      * be passed between processes. The bitmap is assumed to be in the sRGB
    671      * color space.
    672      *
    673      * @hide
    674      */
    675     public Bitmap createAshmemBitmap(Config config) {
    676         checkRecycled("Can't copy a recycled bitmap");
    677         noteHardwareBitmapSlowCall();
    678         Bitmap b = nativeCopyAshmemConfig(mNativePtr, config.nativeInt);
    679         if (b != null) {
    680             b.setPremultiplied(mRequestPremultiplied);
    681             b.mDensity = mDensity;
    682         }
    683         return b;
    684     }
    685 
    686     /**
    687      * Create hardware bitmap backed GraphicBuffer.
    688      *
    689      * @return Bitmap or null if this GraphicBuffer has unsupported PixelFormat.
    690      *         currently PIXEL_FORMAT_RGBA_8888 is the only supported format
    691      * @hide
    692      */
    693     public static Bitmap createHardwareBitmap(@NonNull GraphicBuffer graphicBuffer) {
    694         return nativeCreateHardwareBitmap(graphicBuffer);
    695     }
    696 
    697     /**
    698      * Creates a new bitmap, scaled from an existing bitmap, when possible. If the
    699      * specified width and height are the same as the current width and height of
    700      * the source bitmap, the source bitmap is returned and no new bitmap is
    701      * created.
    702      *
    703      * @param src       The source bitmap.
    704      * @param dstWidth  The new bitmap's desired width.
    705      * @param dstHeight The new bitmap's desired height.
    706      * @param filter    true if the source should be filtered.
    707      * @return The new scaled bitmap or the source bitmap if no scaling is required.
    708      * @throws IllegalArgumentException if width is <= 0, or height is <= 0
    709      */
    710     public static Bitmap createScaledBitmap(@NonNull Bitmap src, int dstWidth, int dstHeight,
    711             boolean filter) {
    712         Matrix m = new Matrix();
    713 
    714         final int width = src.getWidth();
    715         final int height = src.getHeight();
    716         if (width != dstWidth || height != dstHeight) {
    717             final float sx = dstWidth / (float) width;
    718             final float sy = dstHeight / (float) height;
    719             m.setScale(sx, sy);
    720         }
    721         return Bitmap.createBitmap(src, 0, 0, width, height, m, filter);
    722     }
    723 
    724     /**
    725      * Returns an immutable bitmap from the source bitmap. The new bitmap may
    726      * be the same object as source, or a copy may have been made.  It is
    727      * initialized with the same density and color space as the original bitmap.
    728      */
    729     public static Bitmap createBitmap(@NonNull Bitmap src) {
    730         return createBitmap(src, 0, 0, src.getWidth(), src.getHeight());
    731     }
    732 
    733     /**
    734      * Returns an immutable bitmap from the specified subset of the source
    735      * bitmap. The new bitmap may be the same object as source, or a copy may
    736      * have been made. It is initialized with the same density and color space
    737      * as the original bitmap.
    738      *
    739      * @param source   The bitmap we are subsetting
    740      * @param x        The x coordinate of the first pixel in source
    741      * @param y        The y coordinate of the first pixel in source
    742      * @param width    The number of pixels in each row
    743      * @param height   The number of rows
    744      * @return A copy of a subset of the source bitmap or the source bitmap itself.
    745      * @throws IllegalArgumentException if the x, y, width, height values are
    746      *         outside of the dimensions of the source bitmap, or width is <= 0,
    747      *         or height is <= 0
    748      */
    749     public static Bitmap createBitmap(@NonNull Bitmap source, int x, int y, int width, int height) {
    750         return createBitmap(source, x, y, width, height, null, false);
    751     }
    752 
    753     /**
    754      * Returns an immutable bitmap from subset of the source bitmap,
    755      * transformed by the optional matrix. The new bitmap may be the
    756      * same object as source, or a copy may have been made. It is
    757      * initialized with the same density and color space as the original
    758      * bitmap.
    759      *
    760      * If the source bitmap is immutable and the requested subset is the
    761      * same as the source bitmap itself, then the source bitmap is
    762      * returned and no new bitmap is created.
    763      *
    764      * @param source   The bitmap we are subsetting
    765      * @param x        The x coordinate of the first pixel in source
    766      * @param y        The y coordinate of the first pixel in source
    767      * @param width    The number of pixels in each row
    768      * @param height   The number of rows
    769      * @param m        Optional matrix to be applied to the pixels
    770      * @param filter   true if the source should be filtered.
    771      *                   Only applies if the matrix contains more than just
    772      *                   translation.
    773      * @return A bitmap that represents the specified subset of source
    774      * @throws IllegalArgumentException if the x, y, width, height values are
    775      *         outside of the dimensions of the source bitmap, or width is <= 0,
    776      *         or height is <= 0
    777      */
    778     public static Bitmap createBitmap(@NonNull Bitmap source, int x, int y, int width, int height,
    779             @Nullable Matrix m, boolean filter) {
    780 
    781         checkXYSign(x, y);
    782         checkWidthHeight(width, height);
    783         if (x + width > source.getWidth()) {
    784             throw new IllegalArgumentException("x + width must be <= bitmap.width()");
    785         }
    786         if (y + height > source.getHeight()) {
    787             throw new IllegalArgumentException("y + height must be <= bitmap.height()");
    788         }
    789 
    790         // check if we can just return our argument unchanged
    791         if (!source.isMutable() && x == 0 && y == 0 && width == source.getWidth() &&
    792                 height == source.getHeight() && (m == null || m.isIdentity())) {
    793             return source;
    794         }
    795 
    796         boolean isHardware = source.getConfig() == Config.HARDWARE;
    797         if (isHardware) {
    798             source.noteHardwareBitmapSlowCall();
    799             source = nativeCopyPreserveInternalConfig(source.mNativePtr);
    800         }
    801 
    802         int neww = width;
    803         int newh = height;
    804         Bitmap bitmap;
    805         Paint paint;
    806 
    807         Rect srcR = new Rect(x, y, x + width, y + height);
    808         RectF dstR = new RectF(0, 0, width, height);
    809         RectF deviceR = new RectF();
    810 
    811         Config newConfig = Config.ARGB_8888;
    812         final Config config = source.getConfig();
    813         // GIF files generate null configs, assume ARGB_8888
    814         if (config != null) {
    815             switch (config) {
    816                 case RGB_565:
    817                     newConfig = Config.RGB_565;
    818                     break;
    819                 case ALPHA_8:
    820                     newConfig = Config.ALPHA_8;
    821                     break;
    822                 case RGBA_F16:
    823                     newConfig = Config.RGBA_F16;
    824                     break;
    825                 //noinspection deprecation
    826                 case ARGB_4444:
    827                 case ARGB_8888:
    828                 default:
    829                     newConfig = Config.ARGB_8888;
    830                     break;
    831             }
    832         }
    833 
    834         if (m == null || m.isIdentity()) {
    835             bitmap = createBitmap(neww, newh, newConfig, source.hasAlpha());
    836             paint = null;   // not needed
    837         } else {
    838             final boolean transformed = !m.rectStaysRect();
    839 
    840             m.mapRect(deviceR, dstR);
    841 
    842             neww = Math.round(deviceR.width());
    843             newh = Math.round(deviceR.height());
    844 
    845             Config transformedConfig = newConfig;
    846             if (transformed) {
    847                 if (transformedConfig != Config.ARGB_8888 && transformedConfig != Config.RGBA_F16) {
    848                     transformedConfig = Config.ARGB_8888;
    849                 }
    850             }
    851             bitmap = createBitmap(neww, newh, transformedConfig, transformed || source.hasAlpha());
    852 
    853             paint = new Paint();
    854             paint.setFilterBitmap(filter);
    855             if (transformed) {
    856                 paint.setAntiAlias(true);
    857             }
    858         }
    859 
    860         nativeCopyColorSpace(source.mNativePtr, bitmap.mNativePtr);
    861 
    862         // The new bitmap was created from a known bitmap source so assume that
    863         // they use the same density
    864         bitmap.mDensity = source.mDensity;
    865         bitmap.setHasAlpha(source.hasAlpha());
    866         bitmap.setPremultiplied(source.mRequestPremultiplied);
    867 
    868         Canvas canvas = new Canvas(bitmap);
    869         canvas.translate(-deviceR.left, -deviceR.top);
    870         canvas.concat(m);
    871         canvas.drawBitmap(source, srcR, dstR, paint);
    872         canvas.setBitmap(null);
    873         if (isHardware) {
    874             return bitmap.copy(Config.HARDWARE, false);
    875         }
    876         return bitmap;
    877     }
    878 
    879     /**
    880      * Returns a mutable bitmap with the specified width and height.  Its
    881      * initial density is as per {@link #getDensity}. The newly created
    882      * bitmap is in the {@link ColorSpace.Named#SRGB sRGB} color space.
    883      *
    884      * @param width    The width of the bitmap
    885      * @param height   The height of the bitmap
    886      * @param config   The bitmap config to create.
    887      * @throws IllegalArgumentException if the width or height are <= 0, or if
    888      *         Config is Config.HARDWARE, because hardware bitmaps are always immutable
    889      */
    890     public static Bitmap createBitmap(int width, int height, @NonNull Config config) {
    891         return createBitmap(width, height, config, true);
    892     }
    893 
    894     /**
    895      * Returns a mutable bitmap with the specified width and height.  Its
    896      * initial density is determined from the given {@link DisplayMetrics}.
    897      * The newly created bitmap is in the {@link ColorSpace.Named#SRGB sRGB}
    898      * color space.
    899      *
    900      * @param display  Display metrics for the display this bitmap will be
    901      *                 drawn on.
    902      * @param width    The width of the bitmap
    903      * @param height   The height of the bitmap
    904      * @param config   The bitmap config to create.
    905      * @throws IllegalArgumentException if the width or height are <= 0, or if
    906      *         Config is Config.HARDWARE, because hardware bitmaps are always immutable
    907      */
    908     public static Bitmap createBitmap(@Nullable DisplayMetrics display, int width,
    909             int height, @NonNull Config config) {
    910         return createBitmap(display, width, height, config, true);
    911     }
    912 
    913     /**
    914      * Returns a mutable bitmap with the specified width and height.  Its
    915      * initial density is as per {@link #getDensity}. The newly created
    916      * bitmap is in the {@link ColorSpace.Named#SRGB sRGB} color space.
    917      *
    918      * @param width    The width of the bitmap
    919      * @param height   The height of the bitmap
    920      * @param config   The bitmap config to create.
    921      * @param hasAlpha If the bitmap is ARGB_8888 or RGBA_16F this flag can be used to
    922      *                 mark the bitmap as opaque. Doing so will clear the bitmap in black
    923      *                 instead of transparent.
    924      *
    925      * @throws IllegalArgumentException if the width or height are <= 0, or if
    926      *         Config is Config.HARDWARE, because hardware bitmaps are always immutable
    927      */
    928     public static Bitmap createBitmap(int width, int height,
    929             @NonNull Config config, boolean hasAlpha) {
    930         return createBitmap(null, width, height, config, hasAlpha);
    931     }
    932 
    933     /**
    934      * Returns a mutable bitmap with the specified width and height.  Its
    935      * initial density is as per {@link #getDensity}.
    936      *
    937      * @param width    The width of the bitmap
    938      * @param height   The height of the bitmap
    939      * @param config   The bitmap config to create.
    940      * @param hasAlpha If the bitmap is ARGB_8888 or RGBA_16F this flag can be used to
    941      *                 mark the bitmap as opaque. Doing so will clear the bitmap in black
    942      *                 instead of transparent.
    943      * @param colorSpace The color space of the bitmap. If the config is {@link Config#RGBA_F16},
    944      *                   {@link ColorSpace.Named#EXTENDED_SRGB scRGB} is assumed, and if the
    945      *                   config is not {@link Config#ARGB_8888}, {@link ColorSpace.Named#SRGB sRGB}
    946      *                   is assumed.
    947      *
    948      * @throws IllegalArgumentException if the width or height are <= 0, if
    949      *         Config is Config.HARDWARE (because hardware bitmaps are always
    950      *         immutable), if the specified color space is not {@link ColorSpace.Model#RGB RGB},
    951      *         if the specified color space's transfer function is not an
    952      *         {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}, or if
    953      *         the color space is null
    954      */
    955     public static Bitmap createBitmap(int width, int height, @NonNull Config config,
    956             boolean hasAlpha, @NonNull ColorSpace colorSpace) {
    957         return createBitmap(null, width, height, config, hasAlpha, colorSpace);
    958     }
    959 
    960     /**
    961      * Returns a mutable bitmap with the specified width and height.  Its
    962      * initial density is determined from the given {@link DisplayMetrics}.
    963      * The newly created bitmap is in the {@link ColorSpace.Named#SRGB sRGB}
    964      * color space.
    965      *
    966      * @param display  Display metrics for the display this bitmap will be
    967      *                 drawn on.
    968      * @param width    The width of the bitmap
    969      * @param height   The height of the bitmap
    970      * @param config   The bitmap config to create.
    971      * @param hasAlpha If the bitmap is ARGB_8888 or RGBA_16F this flag can be used to
    972      *                 mark the bitmap as opaque. Doing so will clear the bitmap in black
    973      *                 instead of transparent.
    974      *
    975      * @throws IllegalArgumentException if the width or height are <= 0, or if
    976      *         Config is Config.HARDWARE, because hardware bitmaps are always immutable
    977      */
    978     public static Bitmap createBitmap(@Nullable DisplayMetrics display, int width, int height,
    979             @NonNull Config config, boolean hasAlpha) {
    980         return createBitmap(display, width, height, config, hasAlpha,
    981                 ColorSpace.get(ColorSpace.Named.SRGB));
    982     }
    983 
    984     /**
    985      * Returns a mutable bitmap with the specified width and height.  Its
    986      * initial density is determined from the given {@link DisplayMetrics}.
    987      * The newly created bitmap is in the {@link ColorSpace.Named#SRGB sRGB}
    988      * color space.
    989      *
    990      * @param display  Display metrics for the display this bitmap will be
    991      *                 drawn on.
    992      * @param width    The width of the bitmap
    993      * @param height   The height of the bitmap
    994      * @param config   The bitmap config to create.
    995      * @param hasAlpha If the bitmap is ARGB_8888 or RGBA_16F this flag can be used to
    996      *                 mark the bitmap as opaque. Doing so will clear the bitmap in black
    997      *                 instead of transparent.
    998      * @param colorSpace The color space of the bitmap. If the config is {@link Config#RGBA_F16},
    999      *                   {@link ColorSpace.Named#EXTENDED_SRGB scRGB} is assumed, and if the
   1000      *                   config is not {@link Config#ARGB_8888}, {@link ColorSpace.Named#SRGB sRGB}
   1001      *                   is assumed.
   1002      *
   1003      * @throws IllegalArgumentException if the width or height are <= 0, if
   1004      *         Config is Config.HARDWARE (because hardware bitmaps are always
   1005      *         immutable), if the specified color space is not {@link ColorSpace.Model#RGB RGB},
   1006      *         if the specified color space's transfer function is not an
   1007      *         {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}, or if
   1008      *         the color space is null
   1009      */
   1010     public static Bitmap createBitmap(@Nullable DisplayMetrics display, int width, int height,
   1011             @NonNull Config config, boolean hasAlpha, @NonNull ColorSpace colorSpace) {
   1012         if (width <= 0 || height <= 0) {
   1013             throw new IllegalArgumentException("width and height must be > 0");
   1014         }
   1015         if (config == Config.HARDWARE) {
   1016             throw new IllegalArgumentException("can't create mutable bitmap with Config.HARDWARE");
   1017         }
   1018         if (colorSpace == null) {
   1019             throw new IllegalArgumentException("can't create bitmap without a color space");
   1020         }
   1021 
   1022         Bitmap bm;
   1023         // nullptr color spaces have a particular meaning in native and are interpreted as sRGB
   1024         // (we also avoid the unnecessary extra work of the else branch)
   1025         if (config != Config.ARGB_8888 || colorSpace == ColorSpace.get(ColorSpace.Named.SRGB)) {
   1026             bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true, null, null);
   1027         } else {
   1028             if (!(colorSpace instanceof ColorSpace.Rgb)) {
   1029                 throw new IllegalArgumentException("colorSpace must be an RGB color space");
   1030             }
   1031             ColorSpace.Rgb rgb = (ColorSpace.Rgb) colorSpace;
   1032             ColorSpace.Rgb.TransferParameters parameters = rgb.getTransferParameters();
   1033             if (parameters == null) {
   1034                 throw new IllegalArgumentException("colorSpace must use an ICC "
   1035                         + "parametric transfer function");
   1036             }
   1037 
   1038             ColorSpace.Rgb d50 = (ColorSpace.Rgb) ColorSpace.adapt(rgb, ColorSpace.ILLUMINANT_D50);
   1039             bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true,
   1040                     d50.getTransform(), parameters);
   1041         }
   1042 
   1043         if (display != null) {
   1044             bm.mDensity = display.densityDpi;
   1045         }
   1046         bm.setHasAlpha(hasAlpha);
   1047         if ((config == Config.ARGB_8888 || config == Config.RGBA_F16) && !hasAlpha) {
   1048             nativeErase(bm.mNativePtr, 0xff000000);
   1049         }
   1050         // No need to initialize the bitmap to zeroes with other configs;
   1051         // it is backed by a VM byte array which is by definition preinitialized
   1052         // to all zeroes.
   1053         return bm;
   1054     }
   1055 
   1056     /**
   1057      * Returns a immutable bitmap with the specified width and height, with each
   1058      * pixel value set to the corresponding value in the colors array.  Its
   1059      * initial density is as per {@link #getDensity}. The newly created
   1060      * bitmap is in the {@link ColorSpace.Named#SRGB sRGB} color space.
   1061      *
   1062      * @param colors   Array of sRGB {@link Color colors} used to initialize the pixels.
   1063      * @param offset   Number of values to skip before the first color in the
   1064      *                 array of colors.
   1065      * @param stride   Number of colors in the array between rows (must be >=
   1066      *                 width or <= -width).
   1067      * @param width    The width of the bitmap
   1068      * @param height   The height of the bitmap
   1069      * @param config   The bitmap config to create. If the config does not
   1070      *                 support per-pixel alpha (e.g. RGB_565), then the alpha
   1071      *                 bytes in the colors[] will be ignored (assumed to be FF)
   1072      * @throws IllegalArgumentException if the width or height are <= 0, or if
   1073      *         the color array's length is less than the number of pixels.
   1074      */
   1075     public static Bitmap createBitmap(@NonNull @ColorInt int[] colors, int offset, int stride,
   1076             int width, int height, @NonNull Config config) {
   1077         return createBitmap(null, colors, offset, stride, width, height, config);
   1078     }
   1079 
   1080     /**
   1081      * Returns a immutable bitmap with the specified width and height, with each
   1082      * pixel value set to the corresponding value in the colors array.  Its
   1083      * initial density is determined from the given {@link DisplayMetrics}.
   1084      * The newly created bitmap is in the {@link ColorSpace.Named#SRGB sRGB}
   1085      * color space.
   1086      *
   1087      * @param display  Display metrics for the display this bitmap will be
   1088      *                 drawn on.
   1089      * @param colors   Array of sRGB {@link Color colors} used to initialize the pixels.
   1090      * @param offset   Number of values to skip before the first color in the
   1091      *                 array of colors.
   1092      * @param stride   Number of colors in the array between rows (must be >=
   1093      *                 width or <= -width).
   1094      * @param width    The width of the bitmap
   1095      * @param height   The height of the bitmap
   1096      * @param config   The bitmap config to create. If the config does not
   1097      *                 support per-pixel alpha (e.g. RGB_565), then the alpha
   1098      *                 bytes in the colors[] will be ignored (assumed to be FF)
   1099      * @throws IllegalArgumentException if the width or height are <= 0, or if
   1100      *         the color array's length is less than the number of pixels.
   1101      */
   1102     public static Bitmap createBitmap(@NonNull DisplayMetrics display,
   1103             @NonNull @ColorInt int[] colors, int offset, int stride,
   1104             int width, int height, @NonNull Config config) {
   1105 
   1106         checkWidthHeight(width, height);
   1107         if (Math.abs(stride) < width) {
   1108             throw new IllegalArgumentException("abs(stride) must be >= width");
   1109         }
   1110         int lastScanline = offset + (height - 1) * stride;
   1111         int length = colors.length;
   1112         if (offset < 0 || (offset + width > length) || lastScanline < 0 ||
   1113                 (lastScanline + width > length)) {
   1114             throw new ArrayIndexOutOfBoundsException();
   1115         }
   1116         if (width <= 0 || height <= 0) {
   1117             throw new IllegalArgumentException("width and height must be > 0");
   1118         }
   1119         Bitmap bm = nativeCreate(colors, offset, stride, width, height,
   1120                             config.nativeInt, false, null, null);
   1121         if (display != null) {
   1122             bm.mDensity = display.densityDpi;
   1123         }
   1124         return bm;
   1125     }
   1126 
   1127     /**
   1128      * Returns a immutable bitmap with the specified width and height, with each
   1129      * pixel value set to the corresponding value in the colors array.  Its
   1130      * initial density is as per {@link #getDensity}. The newly created
   1131      * bitmap is in the {@link ColorSpace.Named#SRGB sRGB} color space.
   1132      *
   1133      * @param colors   Array of sRGB {@link Color colors} used to initialize the pixels.
   1134      *                 This array must be at least as large as width * height.
   1135      * @param width    The width of the bitmap
   1136      * @param height   The height of the bitmap
   1137      * @param config   The bitmap config to create. If the config does not
   1138      *                 support per-pixel alpha (e.g. RGB_565), then the alpha
   1139      *                 bytes in the colors[] will be ignored (assumed to be FF)
   1140      * @throws IllegalArgumentException if the width or height are <= 0, or if
   1141      *         the color array's length is less than the number of pixels.
   1142      */
   1143     public static Bitmap createBitmap(@NonNull @ColorInt int[] colors,
   1144             int width, int height, Config config) {
   1145         return createBitmap(null, colors, 0, width, width, height, config);
   1146     }
   1147 
   1148     /**
   1149      * Returns a immutable bitmap with the specified width and height, with each
   1150      * pixel value set to the corresponding value in the colors array.  Its
   1151      * initial density is determined from the given {@link DisplayMetrics}.
   1152      * The newly created bitmap is in the {@link ColorSpace.Named#SRGB sRGB}
   1153      * color space.
   1154      *
   1155      * @param display  Display metrics for the display this bitmap will be
   1156      *                 drawn on.
   1157      * @param colors   Array of sRGB {@link Color colors} used to initialize the pixels.
   1158      *                 This array must be at least as large as width * height.
   1159      * @param width    The width of the bitmap
   1160      * @param height   The height of the bitmap
   1161      * @param config   The bitmap config to create. If the config does not
   1162      *                 support per-pixel alpha (e.g. RGB_565), then the alpha
   1163      *                 bytes in the colors[] will be ignored (assumed to be FF)
   1164      * @throws IllegalArgumentException if the width or height are <= 0, or if
   1165      *         the color array's length is less than the number of pixels.
   1166      */
   1167     public static Bitmap createBitmap(@Nullable DisplayMetrics display,
   1168             @NonNull @ColorInt int colors[], int width, int height, @NonNull Config config) {
   1169         return createBitmap(display, colors, 0, width, width, height, config);
   1170     }
   1171 
   1172     /**
   1173      * Returns an optional array of private data, used by the UI system for
   1174      * some bitmaps. Not intended to be called by applications.
   1175      */
   1176     public byte[] getNinePatchChunk() {
   1177         return mNinePatchChunk;
   1178     }
   1179 
   1180     /**
   1181      * Populates a rectangle with the bitmap's optical insets.
   1182      *
   1183      * @param outInsets Rect to populate with optical insets
   1184      * @hide
   1185      */
   1186     public void getOpticalInsets(@NonNull Rect outInsets) {
   1187         if (mNinePatchInsets == null) {
   1188             outInsets.setEmpty();
   1189         } else {
   1190             outInsets.set(mNinePatchInsets.opticalRect);
   1191         }
   1192     }
   1193 
   1194     /** @hide */
   1195     public NinePatch.InsetStruct getNinePatchInsets() {
   1196         return mNinePatchInsets;
   1197     }
   1198 
   1199     /**
   1200      * Specifies the known formats a bitmap can be compressed into
   1201      */
   1202     public enum CompressFormat {
   1203         JPEG    (0),
   1204         PNG     (1),
   1205         WEBP    (2);
   1206 
   1207         CompressFormat(int nativeInt) {
   1208             this.nativeInt = nativeInt;
   1209         }
   1210         final int nativeInt;
   1211     }
   1212 
   1213     /**
   1214      * Number of bytes of temp storage we use for communicating between the
   1215      * native compressor and the java OutputStream.
   1216      */
   1217     private final static int WORKING_COMPRESS_STORAGE = 4096;
   1218 
   1219     /**
   1220      * Write a compressed version of the bitmap to the specified outputstream.
   1221      * If this returns true, the bitmap can be reconstructed by passing a
   1222      * corresponding inputstream to BitmapFactory.decodeStream(). Note: not
   1223      * all Formats support all bitmap configs directly, so it is possible that
   1224      * the returned bitmap from BitmapFactory could be in a different bitdepth,
   1225      * and/or may have lost per-pixel alpha (e.g. JPEG only supports opaque
   1226      * pixels).
   1227      *
   1228      * @param format   The format of the compressed image
   1229      * @param quality  Hint to the compressor, 0-100. 0 meaning compress for
   1230      *                 small size, 100 meaning compress for max quality. Some
   1231      *                 formats, like PNG which is lossless, will ignore the
   1232      *                 quality setting
   1233      * @param stream   The outputstream to write the compressed data.
   1234      * @return true if successfully compressed to the specified stream.
   1235      */
   1236     public boolean compress(CompressFormat format, int quality, OutputStream stream) {
   1237         checkRecycled("Can't compress a recycled bitmap");
   1238         // do explicit check before calling the native method
   1239         if (stream == null) {
   1240             throw new NullPointerException();
   1241         }
   1242         if (quality < 0 || quality > 100) {
   1243             throw new IllegalArgumentException("quality must be 0..100");
   1244         }
   1245         StrictMode.noteSlowCall("Compression of a bitmap is slow");
   1246         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "Bitmap.compress");
   1247         boolean result = nativeCompress(mNativePtr, format.nativeInt,
   1248                 quality, stream, new byte[WORKING_COMPRESS_STORAGE]);
   1249         Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
   1250         return result;
   1251     }
   1252 
   1253     /**
   1254      * Returns true if the bitmap is marked as mutable (i.e.&nbsp;can be drawn into)
   1255      */
   1256     public final boolean isMutable() {
   1257         return mIsMutable;
   1258     }
   1259 
   1260     /**
   1261      * <p>Indicates whether pixels stored in this bitmaps are stored pre-multiplied.
   1262      * When a pixel is pre-multiplied, the RGB components have been multiplied by
   1263      * the alpha component. For instance, if the original color is a 50%
   1264      * translucent red <code>(128, 255, 0, 0)</code>, the pre-multiplied form is
   1265      * <code>(128, 128, 0, 0)</code>.</p>
   1266      *
   1267      * <p>This method always returns false if {@link #getConfig()} is
   1268      * {@link Bitmap.Config#RGB_565}.</p>
   1269      *
   1270      * <p>The return value is undefined if {@link #getConfig()} is
   1271      * {@link Bitmap.Config#ALPHA_8}.</p>
   1272      *
   1273      * <p>This method only returns true if {@link #hasAlpha()} returns true.
   1274      * A bitmap with no alpha channel can be used both as a pre-multiplied and
   1275      * as a non pre-multiplied bitmap.</p>
   1276      *
   1277      * <p>Only pre-multiplied bitmaps may be drawn by the view system or
   1278      * {@link Canvas}. If a non-pre-multiplied bitmap with an alpha channel is
   1279      * drawn to a Canvas, a RuntimeException will be thrown.</p>
   1280      *
   1281      * @return true if the underlying pixels have been pre-multiplied, false
   1282      *         otherwise
   1283      *
   1284      * @see Bitmap#setPremultiplied(boolean)
   1285      * @see BitmapFactory.Options#inPremultiplied
   1286      */
   1287     public final boolean isPremultiplied() {
   1288         if (mRecycled) {
   1289             Log.w(TAG, "Called isPremultiplied() on a recycle()'d bitmap! This is undefined behavior!");
   1290         }
   1291         return nativeIsPremultiplied(mNativePtr);
   1292     }
   1293 
   1294     /**
   1295      * Sets whether the bitmap should treat its data as pre-multiplied.
   1296      *
   1297      * <p>Bitmaps are always treated as pre-multiplied by the view system and
   1298      * {@link Canvas} for performance reasons. Storing un-pre-multiplied data in
   1299      * a Bitmap (through {@link #setPixel}, {@link #setPixels}, or {@link
   1300      * BitmapFactory.Options#inPremultiplied BitmapFactory.Options.inPremultiplied})
   1301      * can lead to incorrect blending if drawn by the framework.</p>
   1302      *
   1303      * <p>This method will not affect the behavior of a bitmap without an alpha
   1304      * channel, or if {@link #hasAlpha()} returns false.</p>
   1305      *
   1306      * <p>Calling {@link #createBitmap} or {@link #createScaledBitmap} with a source
   1307      * Bitmap whose colors are not pre-multiplied may result in a RuntimeException,
   1308      * since those functions require drawing the source, which is not supported for
   1309      * un-pre-multiplied Bitmaps.</p>
   1310      *
   1311      * @see Bitmap#isPremultiplied()
   1312      * @see BitmapFactory.Options#inPremultiplied
   1313      */
   1314     public final void setPremultiplied(boolean premultiplied) {
   1315         checkRecycled("setPremultiplied called on a recycled bitmap");
   1316         mRequestPremultiplied = premultiplied;
   1317         nativeSetPremultiplied(mNativePtr, premultiplied);
   1318     }
   1319 
   1320     /** Returns the bitmap's width */
   1321     public final int getWidth() {
   1322         if (mRecycled) {
   1323             Log.w(TAG, "Called getWidth() on a recycle()'d bitmap! This is undefined behavior!");
   1324         }
   1325         return mWidth;
   1326     }
   1327 
   1328     /** Returns the bitmap's height */
   1329     public final int getHeight() {
   1330         if (mRecycled) {
   1331             Log.w(TAG, "Called getHeight() on a recycle()'d bitmap! This is undefined behavior!");
   1332         }
   1333         return mHeight;
   1334     }
   1335 
   1336     /**
   1337      * Convenience for calling {@link #getScaledWidth(int)} with the target
   1338      * density of the given {@link Canvas}.
   1339      */
   1340     public int getScaledWidth(Canvas canvas) {
   1341         return scaleFromDensity(getWidth(), mDensity, canvas.mDensity);
   1342     }
   1343 
   1344     /**
   1345      * Convenience for calling {@link #getScaledHeight(int)} with the target
   1346      * density of the given {@link Canvas}.
   1347      */
   1348     public int getScaledHeight(Canvas canvas) {
   1349         return scaleFromDensity(getHeight(), mDensity, canvas.mDensity);
   1350     }
   1351 
   1352     /**
   1353      * Convenience for calling {@link #getScaledWidth(int)} with the target
   1354      * density of the given {@link DisplayMetrics}.
   1355      */
   1356     public int getScaledWidth(DisplayMetrics metrics) {
   1357         return scaleFromDensity(getWidth(), mDensity, metrics.densityDpi);
   1358     }
   1359 
   1360     /**
   1361      * Convenience for calling {@link #getScaledHeight(int)} with the target
   1362      * density of the given {@link DisplayMetrics}.
   1363      */
   1364     public int getScaledHeight(DisplayMetrics metrics) {
   1365         return scaleFromDensity(getHeight(), mDensity, metrics.densityDpi);
   1366     }
   1367 
   1368     /**
   1369      * Convenience method that returns the width of this bitmap divided
   1370      * by the density scale factor.
   1371      *
   1372      * @param targetDensity The density of the target canvas of the bitmap.
   1373      * @return The scaled width of this bitmap, according to the density scale factor.
   1374      */
   1375     public int getScaledWidth(int targetDensity) {
   1376         return scaleFromDensity(getWidth(), mDensity, targetDensity);
   1377     }
   1378 
   1379     /**
   1380      * Convenience method that returns the height of this bitmap divided
   1381      * by the density scale factor.
   1382      *
   1383      * @param targetDensity The density of the target canvas of the bitmap.
   1384      * @return The scaled height of this bitmap, according to the density scale factor.
   1385      */
   1386     public int getScaledHeight(int targetDensity) {
   1387         return scaleFromDensity(getHeight(), mDensity, targetDensity);
   1388     }
   1389 
   1390     /**
   1391      * @hide
   1392      */
   1393     static public int scaleFromDensity(int size, int sdensity, int tdensity) {
   1394         if (sdensity == DENSITY_NONE || tdensity == DENSITY_NONE || sdensity == tdensity) {
   1395             return size;
   1396         }
   1397 
   1398         // Scale by tdensity / sdensity, rounding up.
   1399         return ((size * tdensity) + (sdensity >> 1)) / sdensity;
   1400     }
   1401 
   1402     /**
   1403      * Return the number of bytes between rows in the bitmap's pixels. Note that
   1404      * this refers to the pixels as stored natively by the bitmap. If you call
   1405      * getPixels() or setPixels(), then the pixels are uniformly treated as
   1406      * 32bit values, packed according to the Color class.
   1407      *
   1408      * <p>As of {@link android.os.Build.VERSION_CODES#KITKAT}, this method
   1409      * should not be used to calculate the memory usage of the bitmap. Instead,
   1410      * see {@link #getAllocationByteCount()}.
   1411      *
   1412      * @return number of bytes between rows of the native bitmap pixels.
   1413      */
   1414     public final int getRowBytes() {
   1415         if (mRecycled) {
   1416             Log.w(TAG, "Called getRowBytes() on a recycle()'d bitmap! This is undefined behavior!");
   1417         }
   1418         return nativeRowBytes(mNativePtr);
   1419     }
   1420 
   1421     /**
   1422      * Returns the minimum number of bytes that can be used to store this bitmap's pixels.
   1423      *
   1424      * <p>As of {@link android.os.Build.VERSION_CODES#KITKAT}, the result of this method can
   1425      * no longer be used to determine memory usage of a bitmap. See {@link
   1426      * #getAllocationByteCount()}.</p>
   1427      */
   1428     public final int getByteCount() {
   1429         if (mRecycled) {
   1430             Log.w(TAG, "Called getByteCount() on a recycle()'d bitmap! "
   1431                     + "This is undefined behavior!");
   1432             return 0;
   1433         }
   1434         // int result permits bitmaps up to 46,340 x 46,340
   1435         return getRowBytes() * getHeight();
   1436     }
   1437 
   1438     /**
   1439      * Returns the size of the allocated memory used to store this bitmap's pixels.
   1440      *
   1441      * <p>This can be larger than the result of {@link #getByteCount()} if a bitmap is reused to
   1442      * decode other bitmaps of smaller size, or by manual reconfiguration. See {@link
   1443      * #reconfigure(int, int, Config)}, {@link #setWidth(int)}, {@link #setHeight(int)}, {@link
   1444      * #setConfig(Bitmap.Config)}, and {@link BitmapFactory.Options#inBitmap
   1445      * BitmapFactory.Options.inBitmap}. If a bitmap is not modified in this way, this value will be
   1446      * the same as that returned by {@link #getByteCount()}.</p>
   1447      *
   1448      * <p>This value will not change over the lifetime of a Bitmap.</p>
   1449      *
   1450      * @see #reconfigure(int, int, Config)
   1451      */
   1452     public final int getAllocationByteCount() {
   1453         if (mRecycled) {
   1454             Log.w(TAG, "Called getAllocationByteCount() on a recycle()'d bitmap! "
   1455                     + "This is undefined behavior!");
   1456             return 0;
   1457         }
   1458         return nativeGetAllocationByteCount(mNativePtr);
   1459     }
   1460 
   1461     /**
   1462      * If the bitmap's internal config is in one of the public formats, return
   1463      * that config, otherwise return null.
   1464      */
   1465     public final Config getConfig() {
   1466         if (mRecycled) {
   1467             Log.w(TAG, "Called getConfig() on a recycle()'d bitmap! This is undefined behavior!");
   1468         }
   1469         return Config.nativeToConfig(nativeConfig(mNativePtr));
   1470     }
   1471 
   1472     /** Returns true if the bitmap's config supports per-pixel alpha, and
   1473      * if the pixels may contain non-opaque alpha values. For some configs,
   1474      * this is always false (e.g. RGB_565), since they do not support per-pixel
   1475      * alpha. However, for configs that do, the bitmap may be flagged to be
   1476      * known that all of its pixels are opaque. In this case hasAlpha() will
   1477      * also return false. If a config such as ARGB_8888 is not so flagged,
   1478      * it will return true by default.
   1479      */
   1480     public final boolean hasAlpha() {
   1481         if (mRecycled) {
   1482             Log.w(TAG, "Called hasAlpha() on a recycle()'d bitmap! This is undefined behavior!");
   1483         }
   1484         return nativeHasAlpha(mNativePtr);
   1485     }
   1486 
   1487     /**
   1488      * Tell the bitmap if all of the pixels are known to be opaque (false)
   1489      * or if some of the pixels may contain non-opaque alpha values (true).
   1490      * Note, for some configs (e.g. RGB_565) this call is ignored, since it
   1491      * does not support per-pixel alpha values.
   1492      *
   1493      * This is meant as a drawing hint, as in some cases a bitmap that is known
   1494      * to be opaque can take a faster drawing case than one that may have
   1495      * non-opaque per-pixel alpha values.
   1496      */
   1497     public void setHasAlpha(boolean hasAlpha) {
   1498         checkRecycled("setHasAlpha called on a recycled bitmap");
   1499         nativeSetHasAlpha(mNativePtr, hasAlpha, mRequestPremultiplied);
   1500     }
   1501 
   1502     /**
   1503      * Indicates whether the renderer responsible for drawing this
   1504      * bitmap should attempt to use mipmaps when this bitmap is drawn
   1505      * scaled down.
   1506      *
   1507      * If you know that you are going to draw this bitmap at less than
   1508      * 50% of its original size, you may be able to obtain a higher
   1509      * quality
   1510      *
   1511      * This property is only a suggestion that can be ignored by the
   1512      * renderer. It is not guaranteed to have any effect.
   1513      *
   1514      * @return true if the renderer should attempt to use mipmaps,
   1515      *         false otherwise
   1516      *
   1517      * @see #setHasMipMap(boolean)
   1518      */
   1519     public final boolean hasMipMap() {
   1520         if (mRecycled) {
   1521             Log.w(TAG, "Called hasMipMap() on a recycle()'d bitmap! This is undefined behavior!");
   1522         }
   1523         return nativeHasMipMap(mNativePtr);
   1524     }
   1525 
   1526     /**
   1527      * Set a hint for the renderer responsible for drawing this bitmap
   1528      * indicating that it should attempt to use mipmaps when this bitmap
   1529      * is drawn scaled down.
   1530      *
   1531      * If you know that you are going to draw this bitmap at less than
   1532      * 50% of its original size, you may be able to obtain a higher
   1533      * quality by turning this property on.
   1534      *
   1535      * Note that if the renderer respects this hint it might have to
   1536      * allocate extra memory to hold the mipmap levels for this bitmap.
   1537      *
   1538      * This property is only a suggestion that can be ignored by the
   1539      * renderer. It is not guaranteed to have any effect.
   1540      *
   1541      * @param hasMipMap indicates whether the renderer should attempt
   1542      *                  to use mipmaps
   1543      *
   1544      * @see #hasMipMap()
   1545      */
   1546     public final void setHasMipMap(boolean hasMipMap) {
   1547         checkRecycled("setHasMipMap called on a recycled bitmap");
   1548         nativeSetHasMipMap(mNativePtr, hasMipMap);
   1549     }
   1550 
   1551     /**
   1552      * Returns the color space associated with this bitmap. If the color
   1553      * space is unknown, this method returns null.
   1554      */
   1555     @Nullable
   1556     public final ColorSpace getColorSpace() {
   1557         // A reconfigure can change the configuration and rgba16f is
   1558         // always linear scRGB at this time
   1559         if (getConfig() == Config.RGBA_F16) {
   1560             // Reset the color space for potential future reconfigurations
   1561             mColorSpace = null;
   1562             return ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB);
   1563         }
   1564 
   1565         // Cache the color space retrieval since it can be fairly expensive
   1566         if (mColorSpace == null) {
   1567             if (nativeIsSRGB(mNativePtr)) {
   1568                 mColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
   1569             } else {
   1570                 float[] xyz = new float[9];
   1571                 float[] params = new float[7];
   1572 
   1573                 boolean hasColorSpace = nativeGetColorSpace(mNativePtr, xyz, params);
   1574                 if (hasColorSpace) {
   1575                     ColorSpace.Rgb.TransferParameters parameters =
   1576                             new ColorSpace.Rgb.TransferParameters(
   1577                                     params[0], params[1], params[2],
   1578                                     params[3], params[4], params[5], params[6]);
   1579                     ColorSpace cs = ColorSpace.match(xyz, parameters);
   1580                     if (cs != null) {
   1581                         mColorSpace = cs;
   1582                     } else {
   1583                         mColorSpace = new ColorSpace.Rgb("Unknown", xyz, parameters);
   1584                     }
   1585                 }
   1586             }
   1587         }
   1588 
   1589         return mColorSpace;
   1590     }
   1591 
   1592     /**
   1593      * Fills the bitmap's pixels with the specified {@link Color}.
   1594      *
   1595      * @throws IllegalStateException if the bitmap is not mutable.
   1596      */
   1597     public void eraseColor(@ColorInt int c) {
   1598         checkRecycled("Can't erase a recycled bitmap");
   1599         if (!isMutable()) {
   1600             throw new IllegalStateException("cannot erase immutable bitmaps");
   1601         }
   1602         nativeErase(mNativePtr, c);
   1603     }
   1604 
   1605     /**
   1606      * Returns the {@link Color} at the specified location. Throws an exception
   1607      * if x or y are out of bounds (negative or >= to the width or height
   1608      * respectively). The returned color is a non-premultiplied ARGB value in
   1609      * the {@link ColorSpace.Named#SRGB sRGB} color space.
   1610      *
   1611      * @param x    The x coordinate (0...width-1) of the pixel to return
   1612      * @param y    The y coordinate (0...height-1) of the pixel to return
   1613      * @return     The argb {@link Color} at the specified coordinate
   1614      * @throws IllegalArgumentException if x, y exceed the bitmap's bounds
   1615      * @throws IllegalStateException if the bitmap's config is {@link Config#HARDWARE}
   1616      */
   1617     @ColorInt
   1618     public int getPixel(int x, int y) {
   1619         checkRecycled("Can't call getPixel() on a recycled bitmap");
   1620         checkHardware("unable to getPixel(), "
   1621                 + "pixel access is not supported on Config#HARDWARE bitmaps");
   1622         checkPixelAccess(x, y);
   1623         return nativeGetPixel(mNativePtr, x, y);
   1624     }
   1625 
   1626     /**
   1627      * Returns in pixels[] a copy of the data in the bitmap. Each value is
   1628      * a packed int representing a {@link Color}. The stride parameter allows
   1629      * the caller to allow for gaps in the returned pixels array between
   1630      * rows. For normal packed results, just pass width for the stride value.
   1631      * The returned colors are non-premultiplied ARGB values in the
   1632      * {@link ColorSpace.Named#SRGB sRGB} color space.
   1633      *
   1634      * @param pixels   The array to receive the bitmap's colors
   1635      * @param offset   The first index to write into pixels[]
   1636      * @param stride   The number of entries in pixels[] to skip between
   1637      *                 rows (must be >= bitmap's width). Can be negative.
   1638      * @param x        The x coordinate of the first pixel to read from
   1639      *                 the bitmap
   1640      * @param y        The y coordinate of the first pixel to read from
   1641      *                 the bitmap
   1642      * @param width    The number of pixels to read from each row
   1643      * @param height   The number of rows to read
   1644      *
   1645      * @throws IllegalArgumentException if x, y, width, height exceed the
   1646      *         bounds of the bitmap, or if abs(stride) < width.
   1647      * @throws ArrayIndexOutOfBoundsException if the pixels array is too small
   1648      *         to receive the specified number of pixels.
   1649      * @throws IllegalStateException if the bitmap's config is {@link Config#HARDWARE}
   1650      */
   1651     public void getPixels(@ColorInt int[] pixels, int offset, int stride,
   1652                           int x, int y, int width, int height) {
   1653         checkRecycled("Can't call getPixels() on a recycled bitmap");
   1654         checkHardware("unable to getPixels(), "
   1655                 + "pixel access is not supported on Config#HARDWARE bitmaps");
   1656         if (width == 0 || height == 0) {
   1657             return; // nothing to do
   1658         }
   1659         checkPixelsAccess(x, y, width, height, offset, stride, pixels);
   1660         nativeGetPixels(mNativePtr, pixels, offset, stride,
   1661                         x, y, width, height);
   1662     }
   1663 
   1664     /**
   1665      * Shared code to check for illegal arguments passed to getPixel()
   1666      * or setPixel()
   1667      *
   1668      * @param x x coordinate of the pixel
   1669      * @param y y coordinate of the pixel
   1670      */
   1671     private void checkPixelAccess(int x, int y) {
   1672         checkXYSign(x, y);
   1673         if (x >= getWidth()) {
   1674             throw new IllegalArgumentException("x must be < bitmap.width()");
   1675         }
   1676         if (y >= getHeight()) {
   1677             throw new IllegalArgumentException("y must be < bitmap.height()");
   1678         }
   1679     }
   1680 
   1681     /**
   1682      * Shared code to check for illegal arguments passed to getPixels()
   1683      * or setPixels()
   1684      *
   1685      * @param x left edge of the area of pixels to access
   1686      * @param y top edge of the area of pixels to access
   1687      * @param width width of the area of pixels to access
   1688      * @param height height of the area of pixels to access
   1689      * @param offset offset into pixels[] array
   1690      * @param stride number of elements in pixels[] between each logical row
   1691      * @param pixels array to hold the area of pixels being accessed
   1692     */
   1693     private void checkPixelsAccess(int x, int y, int width, int height,
   1694                                    int offset, int stride, int pixels[]) {
   1695         checkXYSign(x, y);
   1696         if (width < 0) {
   1697             throw new IllegalArgumentException("width must be >= 0");
   1698         }
   1699         if (height < 0) {
   1700             throw new IllegalArgumentException("height must be >= 0");
   1701         }
   1702         if (x + width > getWidth()) {
   1703             throw new IllegalArgumentException(
   1704                     "x + width must be <= bitmap.width()");
   1705         }
   1706         if (y + height > getHeight()) {
   1707             throw new IllegalArgumentException(
   1708                     "y + height must be <= bitmap.height()");
   1709         }
   1710         if (Math.abs(stride) < width) {
   1711             throw new IllegalArgumentException("abs(stride) must be >= width");
   1712         }
   1713         int lastScanline = offset + (height - 1) * stride;
   1714         int length = pixels.length;
   1715         if (offset < 0 || (offset + width > length)
   1716                 || lastScanline < 0
   1717                 || (lastScanline + width > length)) {
   1718             throw new ArrayIndexOutOfBoundsException();
   1719         }
   1720     }
   1721 
   1722     /**
   1723      * <p>Write the specified {@link Color} into the bitmap (assuming it is
   1724      * mutable) at the x,y coordinate. The color must be a
   1725      * non-premultiplied ARGB value in the {@link ColorSpace.Named#SRGB sRGB}
   1726      * color space.</p>
   1727      *
   1728      * @param x     The x coordinate of the pixel to replace (0...width-1)
   1729      * @param y     The y coordinate of the pixel to replace (0...height-1)
   1730      * @param color The ARGB color to write into the bitmap
   1731      *
   1732      * @throws IllegalStateException if the bitmap is not mutable
   1733      * @throws IllegalArgumentException if x, y are outside of the bitmap's
   1734      *         bounds.
   1735      */
   1736     public void setPixel(int x, int y, @ColorInt int color) {
   1737         checkRecycled("Can't call setPixel() on a recycled bitmap");
   1738         if (!isMutable()) {
   1739             throw new IllegalStateException();
   1740         }
   1741         checkPixelAccess(x, y);
   1742         nativeSetPixel(mNativePtr, x, y, color);
   1743     }
   1744 
   1745     /**
   1746      * <p>Replace pixels in the bitmap with the colors in the array. Each element
   1747      * in the array is a packed int representing a non-premultiplied ARGB
   1748      * {@link Color} in the {@link ColorSpace.Named#SRGB sRGB} color space.</p>
   1749      *
   1750      * @param pixels   The colors to write to the bitmap
   1751      * @param offset   The index of the first color to read from pixels[]
   1752      * @param stride   The number of colors in pixels[] to skip between rows.
   1753      *                 Normally this value will be the same as the width of
   1754      *                 the bitmap, but it can be larger (or negative).
   1755      * @param x        The x coordinate of the first pixel to write to in
   1756      *                 the bitmap.
   1757      * @param y        The y coordinate of the first pixel to write to in
   1758      *                 the bitmap.
   1759      * @param width    The number of colors to copy from pixels[] per row
   1760      * @param height   The number of rows to write to the bitmap
   1761      *
   1762      * @throws IllegalStateException if the bitmap is not mutable
   1763      * @throws IllegalArgumentException if x, y, width, height are outside of
   1764      *         the bitmap's bounds.
   1765      * @throws ArrayIndexOutOfBoundsException if the pixels array is too small
   1766      *         to receive the specified number of pixels.
   1767      */
   1768     public void setPixels(@ColorInt int[] pixels, int offset, int stride,
   1769             int x, int y, int width, int height) {
   1770         checkRecycled("Can't call setPixels() on a recycled bitmap");
   1771         if (!isMutable()) {
   1772             throw new IllegalStateException();
   1773         }
   1774         if (width == 0 || height == 0) {
   1775             return; // nothing to do
   1776         }
   1777         checkPixelsAccess(x, y, width, height, offset, stride, pixels);
   1778         nativeSetPixels(mNativePtr, pixels, offset, stride,
   1779                         x, y, width, height);
   1780     }
   1781 
   1782     public static final Parcelable.Creator<Bitmap> CREATOR
   1783             = new Parcelable.Creator<Bitmap>() {
   1784         /**
   1785          * Rebuilds a bitmap previously stored with writeToParcel().
   1786          *
   1787          * @param p    Parcel object to read the bitmap from
   1788          * @return a new bitmap created from the data in the parcel
   1789          */
   1790         public Bitmap createFromParcel(Parcel p) {
   1791             Bitmap bm = nativeCreateFromParcel(p);
   1792             if (bm == null) {
   1793                 throw new RuntimeException("Failed to unparcel Bitmap");
   1794             }
   1795             return bm;
   1796         }
   1797         public Bitmap[] newArray(int size) {
   1798             return new Bitmap[size];
   1799         }
   1800     };
   1801 
   1802     /**
   1803      * No special parcel contents.
   1804      */
   1805     public int describeContents() {
   1806         return 0;
   1807     }
   1808 
   1809     /**
   1810      * Write the bitmap and its pixels to the parcel. The bitmap can be
   1811      * rebuilt from the parcel by calling CREATOR.createFromParcel().
   1812      *
   1813      * If this bitmap is {@link Config#HARDWARE}, it may be unparceled with a different pixel
   1814      * format (e.g. 565, 8888), but the content will be preserved to the best quality permitted
   1815      * by the final pixel format
   1816      * @param p    Parcel object to write the bitmap data into
   1817      */
   1818     public void writeToParcel(Parcel p, int flags) {
   1819         checkRecycled("Can't parcel a recycled bitmap");
   1820         noteHardwareBitmapSlowCall();
   1821         if (!nativeWriteToParcel(mNativePtr, mIsMutable, mDensity, p)) {
   1822             throw new RuntimeException("native writeToParcel failed");
   1823         }
   1824     }
   1825 
   1826     /**
   1827      * Returns a new bitmap that captures the alpha values of the original.
   1828      * This may be drawn with Canvas.drawBitmap(), where the color(s) will be
   1829      * taken from the paint that is passed to the draw call.
   1830      *
   1831      * @return new bitmap containing the alpha channel of the original bitmap.
   1832      */
   1833     @CheckResult
   1834     public Bitmap extractAlpha() {
   1835         return extractAlpha(null, null);
   1836     }
   1837 
   1838     /**
   1839      * Returns a new bitmap that captures the alpha values of the original.
   1840      * These values may be affected by the optional Paint parameter, which
   1841      * can contain its own alpha, and may also contain a MaskFilter which
   1842      * could change the actual dimensions of the resulting bitmap (e.g.
   1843      * a blur maskfilter might enlarge the resulting bitmap). If offsetXY
   1844      * is not null, it returns the amount to offset the returned bitmap so
   1845      * that it will logically align with the original. For example, if the
   1846      * paint contains a blur of radius 2, then offsetXY[] would contains
   1847      * -2, -2, so that drawing the alpha bitmap offset by (-2, -2) and then
   1848      * drawing the original would result in the blur visually aligning with
   1849      * the original.
   1850      *
   1851      * <p>The initial density of the returned bitmap is the same as the original's.
   1852      *
   1853      * @param paint Optional paint used to modify the alpha values in the
   1854      *              resulting bitmap. Pass null for default behavior.
   1855      * @param offsetXY Optional array that returns the X (index 0) and Y
   1856      *                 (index 1) offset needed to position the returned bitmap
   1857      *                 so that it visually lines up with the original.
   1858      * @return new bitmap containing the (optionally modified by paint) alpha
   1859      *         channel of the original bitmap. This may be drawn with
   1860      *         Canvas.drawBitmap(), where the color(s) will be taken from the
   1861      *         paint that is passed to the draw call.
   1862      */
   1863     @CheckResult
   1864     public Bitmap extractAlpha(Paint paint, int[] offsetXY) {
   1865         checkRecycled("Can't extractAlpha on a recycled bitmap");
   1866         long nativePaint = paint != null ? paint.getNativeInstance() : 0;
   1867         noteHardwareBitmapSlowCall();
   1868         Bitmap bm = nativeExtractAlpha(mNativePtr, nativePaint, offsetXY);
   1869         if (bm == null) {
   1870             throw new RuntimeException("Failed to extractAlpha on Bitmap");
   1871         }
   1872         bm.mDensity = mDensity;
   1873         return bm;
   1874     }
   1875 
   1876     /**
   1877      *  Given another bitmap, return true if it has the same dimensions, config,
   1878      *  and pixel data as this bitmap. If any of those differ, return false.
   1879      *  If other is null, return false.
   1880      */
   1881     public boolean sameAs(Bitmap other) {
   1882         checkRecycled("Can't call sameAs on a recycled bitmap!");
   1883         noteHardwareBitmapSlowCall();
   1884         if (this == other) return true;
   1885         if (other == null) return false;
   1886         other.noteHardwareBitmapSlowCall();
   1887         if (other.isRecycled()) {
   1888             throw new IllegalArgumentException("Can't compare to a recycled bitmap!");
   1889         }
   1890         return nativeSameAs(mNativePtr, other.mNativePtr);
   1891     }
   1892 
   1893     /**
   1894      * Builds caches associated with the bitmap that are used for drawing it.
   1895      *
   1896      * <p>Starting in {@link android.os.Build.VERSION_CODES#N}, this call initiates an asynchronous
   1897      * upload to the GPU on RenderThread, if the Bitmap is not already uploaded. With Hardware
   1898      * Acceleration, Bitmaps must be uploaded to the GPU in order to be rendered. This is done by
   1899      * default the first time a Bitmap is drawn, but the process can take several milliseconds,
   1900      * depending on the size of the Bitmap. Each time a Bitmap is modified and drawn again, it must
   1901      * be re-uploaded.</p>
   1902      *
   1903      * <p>Calling this method in advance can save time in the first frame it's used. For example, it
   1904      * is recommended to call this on an image decoding worker thread when a decoded Bitmap is about
   1905      * to be displayed. It is recommended to make any pre-draw modifications to the Bitmap before
   1906      * calling this method, so the cached, uploaded copy may be reused without re-uploading.</p>
   1907      *
   1908      * In {@link android.os.Build.VERSION_CODES#KITKAT} and below, for purgeable bitmaps, this call
   1909      * would attempt to ensure that the pixels have been decoded.
   1910      */
   1911     public void prepareToDraw() {
   1912         checkRecycled("Can't prepareToDraw on a recycled bitmap!");
   1913         // Kick off an update/upload of the bitmap outside of the normal
   1914         // draw path.
   1915         nativePrepareToDraw(mNativePtr);
   1916     }
   1917 
   1918     /**
   1919      *
   1920      * @return {@link GraphicBuffer} which is internally used by hardware bitmap
   1921      * @hide
   1922      */
   1923     public GraphicBuffer createGraphicBufferHandle() {
   1924         return nativeCreateGraphicBufferHandle(mNativePtr);
   1925     }
   1926 
   1927     //////////// native methods
   1928 
   1929     private static native Bitmap nativeCreate(int[] colors, int offset,
   1930                                               int stride, int width, int height,
   1931                                               int nativeConfig, boolean mutable,
   1932                                               @Nullable @Size(9) float[] xyzD50,
   1933                                               @Nullable ColorSpace.Rgb.TransferParameters p);
   1934     private static native Bitmap nativeCopy(long nativeSrcBitmap, int nativeConfig,
   1935                                             boolean isMutable);
   1936     private static native Bitmap nativeCopyAshmem(long nativeSrcBitmap);
   1937     private static native Bitmap nativeCopyAshmemConfig(long nativeSrcBitmap, int nativeConfig);
   1938     private static native long nativeGetNativeFinalizer();
   1939     private static native boolean nativeRecycle(long nativeBitmap);
   1940     private static native void nativeReconfigure(long nativeBitmap, int width, int height,
   1941                                                  int config, boolean isPremultiplied);
   1942 
   1943     private static native boolean nativeCompress(long nativeBitmap, int format,
   1944                                             int quality, OutputStream stream,
   1945                                             byte[] tempStorage);
   1946     private static native void nativeErase(long nativeBitmap, int color);
   1947     private static native int nativeRowBytes(long nativeBitmap);
   1948     private static native int nativeConfig(long nativeBitmap);
   1949 
   1950     private static native int nativeGetPixel(long nativeBitmap, int x, int y);
   1951     private static native void nativeGetPixels(long nativeBitmap, int[] pixels,
   1952                                                int offset, int stride, int x, int y,
   1953                                                int width, int height);
   1954 
   1955     private static native void nativeSetPixel(long nativeBitmap, int x, int y, int color);
   1956     private static native void nativeSetPixels(long nativeBitmap, int[] colors,
   1957                                                int offset, int stride, int x, int y,
   1958                                                int width, int height);
   1959     private static native void nativeCopyPixelsToBuffer(long nativeBitmap,
   1960                                                         Buffer dst);
   1961     private static native void nativeCopyPixelsFromBuffer(long nativeBitmap, Buffer src);
   1962     private static native int nativeGenerationId(long nativeBitmap);
   1963 
   1964     private static native Bitmap nativeCreateFromParcel(Parcel p);
   1965     // returns true on success
   1966     private static native boolean nativeWriteToParcel(long nativeBitmap,
   1967                                                       boolean isMutable,
   1968                                                       int density,
   1969                                                       Parcel p);
   1970     // returns a new bitmap built from the native bitmap's alpha, and the paint
   1971     private static native Bitmap nativeExtractAlpha(long nativeBitmap,
   1972                                                     long nativePaint,
   1973                                                     int[] offsetXY);
   1974 
   1975     private static native boolean nativeHasAlpha(long nativeBitmap);
   1976     private static native boolean nativeIsPremultiplied(long nativeBitmap);
   1977     private static native void nativeSetPremultiplied(long nativeBitmap,
   1978                                                       boolean isPremul);
   1979     private static native void nativeSetHasAlpha(long nativeBitmap,
   1980                                                  boolean hasAlpha,
   1981                                                  boolean requestPremul);
   1982     private static native boolean nativeHasMipMap(long nativeBitmap);
   1983     private static native void nativeSetHasMipMap(long nativeBitmap, boolean hasMipMap);
   1984     private static native boolean nativeSameAs(long nativeBitmap0, long nativeBitmap1);
   1985     private static native void nativePrepareToDraw(long nativeBitmap);
   1986     private static native int nativeGetAllocationByteCount(long nativeBitmap);
   1987     private static native Bitmap nativeCopyPreserveInternalConfig(long nativeBitmap);
   1988     private static native Bitmap nativeCreateHardwareBitmap(GraphicBuffer buffer);
   1989     private static native GraphicBuffer nativeCreateGraphicBufferHandle(long nativeBitmap);
   1990     private static native boolean nativeGetColorSpace(long nativePtr, float[] xyz, float[] params);
   1991     private static native boolean nativeIsSRGB(long nativePtr);
   1992     private static native void nativeCopyColorSpace(long srcBitmap, long dstBitmap);
   1993 }
   1994