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.ColorLong;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.WorkerThread;
25 import android.compat.annotation.UnsupportedAppUsage;
26 import android.hardware.HardwareBuffer;
27 import android.os.Build;
28 import android.os.Parcel;
29 import android.os.ParcelFileDescriptor;
30 import android.os.Parcelable;
31 import android.os.SharedMemory;
32 import android.os.StrictMode;
33 import android.os.Trace;
34 import android.util.DisplayMetrics;
35 import android.util.Half;
36 import android.util.Log;
37 import android.view.ThreadedRenderer;
38 
39 import dalvik.annotation.optimization.CriticalNative;
40 
41 import libcore.util.NativeAllocationRegistry;
42 
43 import java.io.IOException;
44 import java.io.OutputStream;
45 import java.lang.ref.WeakReference;
46 import java.nio.Buffer;
47 import java.nio.ByteBuffer;
48 import java.nio.IntBuffer;
49 import java.nio.ShortBuffer;
50 
51 public final class Bitmap implements Parcelable {
52     private static final String TAG = "Bitmap";
53 
54     /**
55      * Indicates that the bitmap was created for an unknown pixel density.
56      *
57      * @see Bitmap#getDensity()
58      * @see Bitmap#setDensity(int)
59      */
60     public static final int DENSITY_NONE = 0;
61 
62     // Estimated size of the Bitmap native allocation, not including
63     // pixel data.
64     private static final long NATIVE_ALLOCATION_SIZE = 32;
65 
66     // Convenience for JNI access
67     @UnsupportedAppUsage
68     private final long mNativePtr;
69 
70     /**
71      * Represents whether the Bitmap's content is requested to be pre-multiplied.
72      * Note that isPremultiplied() does not directly return this value, because
73      * isPremultiplied() may never return true for a 565 Bitmap or a bitmap
74      * without alpha.
75      *
76      * setPremultiplied() does directly set the value so that setConfig() and
77      * setPremultiplied() aren't order dependent, despite being setters.
78      *
79      * The native bitmap's premultiplication state is kept up to date by
80      * pushing down this preference for every config change.
81      */
82     private boolean mRequestPremultiplied;
83 
84     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769491)
85     private byte[] mNinePatchChunk; // may be null
86     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
87     private NinePatch.InsetStruct mNinePatchInsets; // may be null
88     @UnsupportedAppUsage
89     private int mWidth;
90     @UnsupportedAppUsage
91     private int mHeight;
92     private WeakReference<HardwareBuffer> mHardwareBuffer;
93     private boolean mRecycled;
94 
95     private ColorSpace mColorSpace;
96     private Gainmap mGainmap;
97 
98     /*package*/ int mDensity = getDefaultDensity();
99 
100     private static volatile int sDefaultDensity = -1;
101 
102     /**
103      * For backwards compatibility, allows the app layer to change the default
104      * density when running old apps.
105      * @hide
106      */
107     @UnsupportedAppUsage
setDefaultDensity(int density)108     public static void setDefaultDensity(int density) {
109         sDefaultDensity = density;
110     }
111 
112     @SuppressWarnings("deprecation")
113     @UnsupportedAppUsage
getDefaultDensity()114     static int getDefaultDensity() {
115         if (sDefaultDensity >= 0) {
116             return sDefaultDensity;
117         }
118         sDefaultDensity = DisplayMetrics.DENSITY_DEVICE;
119         return sDefaultDensity;
120     }
121 
122     /**
123      * Private constructor that must receive an already allocated native bitmap
124      * int (pointer).
125      */
126     // JNI now calls the version below this one. This is preserved due to UnsupportedAppUsage.
127     @UnsupportedAppUsage(maxTargetSdk = 28)
Bitmap(long nativeBitmap, int width, int height, int density, boolean requestPremultiplied, byte[] ninePatchChunk, NinePatch.InsetStruct ninePatchInsets)128     Bitmap(long nativeBitmap, int width, int height, int density,
129             boolean requestPremultiplied, byte[] ninePatchChunk,
130             NinePatch.InsetStruct ninePatchInsets) {
131         this(nativeBitmap, width, height, density, requestPremultiplied, ninePatchChunk,
132                 ninePatchInsets, true);
133     }
134 
135     // called from JNI and Bitmap_Delegate.
Bitmap(long nativeBitmap, int width, int height, int density, boolean requestPremultiplied, byte[] ninePatchChunk, NinePatch.InsetStruct ninePatchInsets, boolean fromMalloc)136     Bitmap(long nativeBitmap, int width, int height, int density,
137             boolean requestPremultiplied, byte[] ninePatchChunk,
138             NinePatch.InsetStruct ninePatchInsets, boolean fromMalloc) {
139         if (nativeBitmap == 0) {
140             throw new RuntimeException("internal error: native bitmap is 0");
141         }
142 
143         mWidth = width;
144         mHeight = height;
145         mRequestPremultiplied = requestPremultiplied;
146 
147         mNinePatchChunk = ninePatchChunk;
148         mNinePatchInsets = ninePatchInsets;
149         if (density >= 0) {
150             mDensity = density;
151         }
152 
153         mNativePtr = nativeBitmap;
154 
155         final int allocationByteCount = getAllocationByteCount();
156         NativeAllocationRegistry registry;
157         if (fromMalloc) {
158             registry = NativeAllocationRegistry.createMalloced(
159                     Bitmap.class.getClassLoader(), nativeGetNativeFinalizer(), allocationByteCount);
160         } else {
161             registry = NativeAllocationRegistry.createNonmalloced(
162                     Bitmap.class.getClassLoader(), nativeGetNativeFinalizer(), allocationByteCount);
163         }
164         registry.registerNativeAllocation(this, nativeBitmap);
165     }
166 
167     /**
168      * Return the pointer to the native object.
169      *
170      * @hide
171      * Must be public for access from android.graphics.pdf,
172      * but must not be called from outside the UI module.
173      */
getNativeInstance()174     public long getNativeInstance() {
175         return mNativePtr;
176     }
177 
178     /**
179      * Native bitmap has been reconfigured, so set premult and cached
180      * width/height values
181      */
182     @SuppressWarnings("unused") // called from JNI
183     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
reinit(int width, int height, boolean requestPremultiplied)184     void reinit(int width, int height, boolean requestPremultiplied) {
185         mWidth = width;
186         mHeight = height;
187         mRequestPremultiplied = requestPremultiplied;
188         mColorSpace = null;
189     }
190 
191     /**
192      * <p>Returns the density for this bitmap.</p>
193      *
194      * <p>The default density is the same density as the current display,
195      * unless the current application does not support different screen
196      * densities in which case it is
197      * {@link android.util.DisplayMetrics#DENSITY_DEFAULT}.  Note that
198      * compatibility mode is determined by the application that was initially
199      * loaded into a process -- applications that share the same process should
200      * all have the same compatibility, or ensure they explicitly set the
201      * density of their bitmaps appropriately.</p>
202      *
203      * @return A scaling factor of the default density or {@link #DENSITY_NONE}
204      *         if the scaling factor is unknown.
205      *
206      * @see #setDensity(int)
207      * @see android.util.DisplayMetrics#DENSITY_DEFAULT
208      * @see android.util.DisplayMetrics#densityDpi
209      * @see #DENSITY_NONE
210      */
getDensity()211     public int getDensity() {
212         if (mRecycled) {
213             Log.w(TAG, "Called getDensity() on a recycle()'d bitmap! This is undefined behavior!");
214         }
215         return mDensity;
216     }
217 
218     /**
219      * <p>Specifies the density for this bitmap.  When the bitmap is
220      * drawn to a Canvas that also has a density, it will be scaled
221      * appropriately.</p>
222      *
223      * @param density The density scaling factor to use with this bitmap or
224      *        {@link #DENSITY_NONE} if the density is unknown.
225      *
226      * @see #getDensity()
227      * @see android.util.DisplayMetrics#DENSITY_DEFAULT
228      * @see android.util.DisplayMetrics#densityDpi
229      * @see #DENSITY_NONE
230      */
setDensity(int density)231     public void setDensity(int density) {
232         mDensity = density;
233     }
234 
235     /**
236      * <p>Modifies the bitmap to have a specified width, height, and {@link
237      * Config}, without affecting the underlying allocation backing the bitmap.
238      * Bitmap pixel data is not re-initialized for the new configuration.</p>
239      *
240      * <p>This method can be used to avoid allocating a new bitmap, instead
241      * reusing an existing bitmap's allocation for a new configuration of equal
242      * or lesser size. If the Bitmap's allocation isn't large enough to support
243      * the new configuration, an IllegalArgumentException will be thrown and the
244      * bitmap will not be modified.</p>
245      *
246      * <p>The result of {@link #getByteCount()} will reflect the new configuration,
247      * while {@link #getAllocationByteCount()} will reflect that of the initial
248      * configuration.</p>
249      *
250      * <p>Note: This may change this result of hasAlpha(). When converting to 565,
251      * the new bitmap will always be considered opaque. When converting from 565,
252      * the new bitmap will be considered non-opaque, and will respect the value
253      * set by setPremultiplied().</p>
254      *
255      * <p>WARNING: This method should NOT be called on a bitmap currently in use
256      * by the view system, Canvas, or the AndroidBitmap NDK API. It does not
257      * make guarantees about how the underlying pixel buffer is remapped to the
258      * new config, just that the allocation is reused. Additionally, the view
259      * system does not account for bitmap properties being modifying during use,
260      * e.g. while attached to drawables.</p>
261      *
262      * <p>In order to safely ensure that a Bitmap is no longer in use by the
263      * View system it is necessary to wait for a draw pass to occur after
264      * invalidate()'ing any view that had previously drawn the Bitmap in the last
265      * draw pass due to hardware acceleration's caching of draw commands. As
266      * an example, here is how this can be done for an ImageView:
267      * <pre class="prettyprint">
268      *      ImageView myImageView = ...;
269      *      final Bitmap myBitmap = ...;
270      *      myImageView.setImageDrawable(null);
271      *      myImageView.post(new Runnable() {
272      *          public void run() {
273      *              // myBitmap is now no longer in use by the ImageView
274      *              // and can be safely reconfigured.
275      *              myBitmap.reconfigure(...);
276      *          }
277      *      });
278      * </pre></p>
279      *
280      * @see #setWidth(int)
281      * @see #setHeight(int)
282      * @see #setConfig(Config)
283      */
reconfigure(int width, int height, @NonNull Config config)284     public void reconfigure(int width, int height, @NonNull Config config) {
285         checkRecycled("Can't call reconfigure() on a recycled bitmap");
286         if (width <= 0 || height <= 0) {
287             throw new IllegalArgumentException("width and height must be > 0");
288         }
289         if (!isMutable()) {
290             throw new IllegalStateException("only mutable bitmaps may be reconfigured");
291         }
292 
293         nativeReconfigure(mNativePtr, width, height, config.nativeInt, mRequestPremultiplied);
294         mWidth = width;
295         mHeight = height;
296         mColorSpace = null;
297     }
298 
299     /**
300      * <p>Convenience method for calling {@link #reconfigure(int, int, Config)}
301      * with the current height and config.</p>
302      *
303      * <p>WARNING: this method should not be used on bitmaps currently used by
304      * the view system, see {@link #reconfigure(int, int, Config)} for more
305      * details.</p>
306      *
307      * @see #reconfigure(int, int, Config)
308      * @see #setHeight(int)
309      * @see #setConfig(Config)
310      */
setWidth(int width)311     public void setWidth(int width) {
312         reconfigure(width, getHeight(), getConfig());
313     }
314 
315     /**
316      * <p>Convenience method for calling {@link #reconfigure(int, int, Config)}
317      * with the current width and config.</p>
318      *
319      * <p>WARNING: this method should not be used on bitmaps currently used by
320      * the view system, see {@link #reconfigure(int, int, Config)} for more
321      * details.</p>
322      *
323      * @see #reconfigure(int, int, Config)
324      * @see #setWidth(int)
325      * @see #setConfig(Config)
326      */
setHeight(int height)327     public void setHeight(int height) {
328         reconfigure(getWidth(), height, getConfig());
329     }
330 
331     /**
332      * <p>Convenience method for calling {@link #reconfigure(int, int, Config)}
333      * with the current height and width.</p>
334      *
335      * <p>WARNING: this method should not be used on bitmaps currently used by
336      * the view system, see {@link #reconfigure(int, int, Config)} for more
337      * details.</p>
338      *
339      * @see #reconfigure(int, int, Config)
340      * @see #setWidth(int)
341      * @see #setHeight(int)
342      */
setConfig(@onNull Config config)343     public void setConfig(@NonNull Config config) {
344         reconfigure(getWidth(), getHeight(), config);
345     }
346 
347     /**
348      * Sets the nine patch chunk.
349      *
350      * @param chunk The definition of the nine patch
351      */
352     @UnsupportedAppUsage
setNinePatchChunk(byte[] chunk)353     private void setNinePatchChunk(byte[] chunk) {
354         mNinePatchChunk = chunk;
355     }
356 
357     /**
358      * Free the native object associated with this bitmap, and clear the
359      * reference to the pixel data. This will not free the pixel data synchronously;
360      * it simply allows it to be garbage collected if there are no other references.
361      * The bitmap is marked as "dead", meaning it will throw an exception if
362      * getPixels() or setPixels() is called, and will draw nothing. This operation
363      * cannot be reversed, so it should only be called if you are sure there are no
364      * further uses for the bitmap. This is an advanced call, and normally need
365      * not be called, since the normal GC process will free up this memory when
366      * there are no more references to this bitmap.
367      */
recycle()368     public void recycle() {
369         if (!mRecycled) {
370             nativeRecycle(mNativePtr);
371             mNinePatchChunk = null;
372             mRecycled = true;
373             mHardwareBuffer = null;
374         }
375     }
376 
377     /**
378      * Returns true if this bitmap has been recycled. If so, then it is an error
379      * to try to access its pixels, and the bitmap will not draw.
380      *
381      * @return true if the bitmap has been recycled
382      */
isRecycled()383     public final boolean isRecycled() {
384         return mRecycled;
385     }
386 
387     /**
388      * Returns the generation ID of this bitmap. The generation ID changes
389      * whenever the bitmap is modified. This can be used as an efficient way to
390      * check if a bitmap has changed.
391      *
392      * @return The current generation ID for this bitmap.
393      */
getGenerationId()394     public int getGenerationId() {
395         if (mRecycled) {
396             Log.w(TAG, "Called getGenerationId() on a recycle()'d bitmap! This is undefined behavior!");
397         }
398         return nativeGenerationId(mNativePtr);
399     }
400 
401     /**
402      * This is called by methods that want to throw an exception if the bitmap
403      * has already been recycled.
404      * @hide
405      */
checkRecycled(String errorMessage)406     void checkRecycled(String errorMessage) {
407         if (mRecycled) {
408             throw new IllegalStateException(errorMessage);
409         }
410     }
411 
412     /**
413      * This is called by methods that want to throw an exception if the bitmap
414      * is {@link Config#HARDWARE}.
415      */
checkHardware(String errorMessage)416     private void checkHardware(String errorMessage) {
417         if (getConfig() == Config.HARDWARE) {
418             throw new IllegalStateException(errorMessage);
419         }
420     }
421 
422     /**
423      * Common code for checking that x and y are >= 0
424      *
425      * @param x x coordinate to ensure is >= 0
426      * @param y y coordinate to ensure is >= 0
427      */
checkXYSign(int x, int y)428     private static void checkXYSign(int x, int y) {
429         if (x < 0) {
430             throw new IllegalArgumentException("x must be >= 0");
431         }
432         if (y < 0) {
433             throw new IllegalArgumentException("y must be >= 0");
434         }
435     }
436 
437     /**
438      * Common code for checking that width and height are > 0
439      *
440      * @param width  width to ensure is > 0
441      * @param height height to ensure is > 0
442      */
checkWidthHeight(int width, int height)443     private static void checkWidthHeight(int width, int height) {
444         if (width <= 0) {
445             throw new IllegalArgumentException("width must be > 0");
446         }
447         if (height <= 0) {
448             throw new IllegalArgumentException("height must be > 0");
449         }
450     }
451 
452     /**
453      * Possible bitmap configurations. A bitmap configuration describes
454      * how pixels are stored. This affects the quality (color depth) as
455      * well as the ability to display transparent/translucent colors.
456      */
457     public enum Config {
458         // these native values must match up with the enum in SkBitmap.h
459 
460         /**
461          * Each pixel is stored as a single translucency (alpha) channel.
462          * This is very useful to efficiently store masks for instance.
463          * No color information is stored.
464          * With this configuration, each pixel requires 1 byte of memory.
465          */
466         ALPHA_8(1),
467 
468         /**
469          * Each pixel is stored on 2 bytes and only the RGB channels are
470          * encoded: red is stored with 5 bits of precision (32 possible
471          * values), green is stored with 6 bits of precision (64 possible
472          * values) and blue is stored with 5 bits of precision.
473          *
474          * This configuration can produce slight visual artifacts depending
475          * on the configuration of the source. For instance, without
476          * dithering, the result might show a greenish tint. To get better
477          * results dithering should be applied.
478          *
479          * This configuration may be useful when using opaque bitmaps
480          * that do not require high color fidelity.
481          *
482          * <p>Use this formula to pack into 16 bits:</p>
483          * <pre class="prettyprint">
484          * short color = (R & 0x1f) << 11 | (G & 0x3f) << 5 | (B & 0x1f);
485          * </pre>
486          */
487         RGB_565(3),
488 
489         /**
490          * Each pixel is stored on 2 bytes. The three RGB color channels
491          * and the alpha channel (translucency) are stored with a 4 bits
492          * precision (16 possible values.)
493          *
494          * This configuration is mostly useful if the application needs
495          * to store translucency information but also needs to save
496          * memory.
497          *
498          * It is recommended to use {@link #ARGB_8888} instead of this
499          * configuration.
500          *
501          * Note: as of {@link android.os.Build.VERSION_CODES#KITKAT},
502          * any bitmap created with this configuration will be created
503          * using {@link #ARGB_8888} instead.
504          *
505          * @deprecated Because of the poor quality of this configuration,
506          *             it is advised to use {@link #ARGB_8888} instead.
507          */
508         @Deprecated
509         ARGB_4444(4),
510 
511         /**
512          * Each pixel is stored on 4 bytes. Each channel (RGB and alpha
513          * for translucency) is stored with 8 bits of precision (256
514          * possible values.)
515          *
516          * This configuration is very flexible and offers the best
517          * quality. It should be used whenever possible.
518          *
519          * <p>Use this formula to pack into 32 bits:</p>
520          * <pre class="prettyprint">
521          * int color = (A & 0xff) << 24 | (B & 0xff) << 16 | (G & 0xff) << 8 | (R & 0xff);
522          * </pre>
523          */
524         ARGB_8888(5),
525 
526         /**
527          * Each pixel is stored on 8 bytes. Each channel (RGB and alpha
528          * for translucency) is stored as a
529          * {@link android.util.Half half-precision floating point value}.
530          *
531          * This configuration is particularly suited for wide-gamut and
532          * HDR content.
533          *
534          * <p>Use this formula to pack into 64 bits:</p>
535          * <pre class="prettyprint">
536          * long color = (A & 0xffff) << 48 | (B & 0xffff) << 32 | (G & 0xffff) << 16 | (R & 0xffff);
537          * </pre>
538          */
539         RGBA_F16(6),
540 
541         /**
542          * Special configuration, when bitmap is stored only in graphic memory.
543          * Bitmaps in this configuration are always immutable.
544          *
545          * It is optimal for cases, when the only operation with the bitmap is to draw it on a
546          * screen.
547          */
548         HARDWARE(7),
549 
550         /**
551          * Each pixel is stored on 4 bytes. Each RGB channel is stored with 10 bits of precision
552          * (1024 possible values). There is an additional alpha channel that is stored with 2 bits
553          * of precision (4 possible values).
554          *
555          * This configuration is suited for wide-gamut and HDR content which does not require alpha
556          * blending, such that the memory cost is the same as ARGB_8888 while enabling higher color
557          * precision.
558          *
559          * <p>Use this formula to pack into 32 bits:</p>
560          * <pre class="prettyprint">
561          * int color = (A & 0x3) << 30 | (B & 0x3ff) << 20 | (G & 0x3ff) << 10 | (R & 0x3ff);
562          * </pre>
563          */
564         RGBA_1010102(8);
565 
566         @UnsupportedAppUsage
567         final int nativeInt;
568 
569         private static Config sConfigs[] = {
570             null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888, RGBA_F16, HARDWARE, RGBA_1010102
571         };
572 
Config(int ni)573         Config(int ni) {
574             this.nativeInt = ni;
575         }
576 
577         @UnsupportedAppUsage
nativeToConfig(int ni)578         static Config nativeToConfig(int ni) {
579             return sConfigs[ni];
580         }
581     }
582 
583     /**
584      * <p>Copy the bitmap's pixels into the specified buffer (allocated by the
585      * caller). An exception is thrown if the buffer is not large enough to
586      * hold all of the pixels (taking into account the number of bytes per
587      * pixel) or if the Buffer subclass is not one of the support types
588      * (ByteBuffer, ShortBuffer, IntBuffer).</p>
589      * <p>The content of the bitmap is copied into the buffer as-is. This means
590      * that if this bitmap stores its pixels pre-multiplied
591      * (see {@link #isPremultiplied()}, the values in the buffer will also be
592      * pre-multiplied. The pixels remain in the color space of the bitmap.</p>
593      * <p>After this method returns, the current position of the buffer is
594      * updated: the position is incremented by the number of elements written
595      * in the buffer.</p>
596      * @throws IllegalStateException if the bitmap's config is {@link Config#HARDWARE}
597      */
copyPixelsToBuffer(@onNull Buffer dst)598     public void copyPixelsToBuffer(@NonNull Buffer dst) {
599         checkHardware("unable to copyPixelsToBuffer, "
600                 + "pixel access is not supported on Config#HARDWARE bitmaps");
601         int elements = dst.remaining();
602         int shift;
603         if (dst instanceof ByteBuffer) {
604             shift = 0;
605         } else if (dst instanceof ShortBuffer) {
606             shift = 1;
607         } else if (dst instanceof IntBuffer) {
608             shift = 2;
609         } else {
610             throw new RuntimeException("unsupported Buffer subclass");
611         }
612 
613         long bufferSize = (long)elements << shift;
614         long pixelSize = getByteCount();
615 
616         if (bufferSize < pixelSize) {
617             throw new RuntimeException("Buffer not large enough for pixels");
618         }
619 
620         nativeCopyPixelsToBuffer(mNativePtr, dst);
621 
622         // now update the buffer's position
623         int position = dst.position();
624         position += pixelSize >> shift;
625         dst.position(position);
626     }
627 
628     /**
629      * <p>Copy the pixels from the buffer, beginning at the current position,
630      * overwriting the bitmap's pixels. The data in the buffer is not changed
631      * in any way (unlike setPixels(), which converts from unpremultipled 32bit
632      * to whatever the bitmap's native format is. The pixels in the source
633      * buffer are assumed to be in the bitmap's color space.</p>
634      * <p>After this method returns, the current position of the buffer is
635      * updated: the position is incremented by the number of elements read from
636      * the buffer. If you need to read the bitmap from the buffer again you must
637      * first rewind the buffer.</p>
638      * @throws IllegalStateException if the bitmap's config is {@link Config#HARDWARE}
639      */
copyPixelsFromBuffer(@onNull Buffer src)640     public void copyPixelsFromBuffer(@NonNull Buffer src) {
641         checkRecycled("copyPixelsFromBuffer called on recycled bitmap");
642         checkHardware("unable to copyPixelsFromBuffer, Config#HARDWARE bitmaps are immutable");
643 
644         int elements = src.remaining();
645         int shift;
646         if (src instanceof ByteBuffer) {
647             shift = 0;
648         } else if (src instanceof ShortBuffer) {
649             shift = 1;
650         } else if (src instanceof IntBuffer) {
651             shift = 2;
652         } else {
653             throw new RuntimeException("unsupported Buffer subclass");
654         }
655 
656         long bufferBytes = (long) elements << shift;
657         long bitmapBytes = getByteCount();
658 
659         if (bufferBytes < bitmapBytes) {
660             throw new RuntimeException("Buffer not large enough for pixels");
661         }
662 
663         nativeCopyPixelsFromBuffer(mNativePtr, src);
664 
665         // now update the buffer's position
666         int position = src.position();
667         position += bitmapBytes >> shift;
668         src.position(position);
669     }
670 
noteHardwareBitmapSlowCall()671     private void noteHardwareBitmapSlowCall() {
672         if (getConfig() == Config.HARDWARE) {
673             StrictMode.noteSlowCall("Warning: attempt to read pixels from hardware "
674                     + "bitmap, which is very slow operation");
675         }
676     }
677 
678     /**
679      * Tries to make a new bitmap based on the dimensions of this bitmap,
680      * setting the new bitmap's config to the one specified, and then copying
681      * this bitmap's pixels into the new bitmap. If the conversion is not
682      * supported, or the allocator fails, then this returns NULL.  The returned
683      * bitmap has the same density and color space as the original, except in
684      * the following cases. When copying to {@link Config#ALPHA_8}, the color
685      * space is dropped. When copying to or from {@link Config#RGBA_F16},
686      * EXTENDED or non-EXTENDED variants may be adjusted as appropriate.
687      *
688      * @param config    The desired config for the resulting bitmap
689      * @param isMutable True if the resulting bitmap should be mutable (i.e.
690      *                  its pixels can be modified)
691      * @return the new bitmap, or null if the copy could not be made.
692      * @throws IllegalArgumentException if config is {@link Config#HARDWARE} and isMutable is true
693      */
copy(@onNull Config config, boolean isMutable)694     public Bitmap copy(@NonNull Config config, boolean isMutable) {
695         checkRecycled("Can't copy a recycled bitmap");
696         if (config == Config.HARDWARE && isMutable) {
697             throw new IllegalArgumentException("Hardware bitmaps are always immutable");
698         }
699         noteHardwareBitmapSlowCall();
700         Bitmap b = nativeCopy(mNativePtr, config.nativeInt, isMutable);
701         if (b != null) {
702             b.setPremultiplied(mRequestPremultiplied);
703             b.mDensity = mDensity;
704         }
705         return b;
706     }
707 
708     /**
709      * Creates a new immutable bitmap backed by ashmem which can efficiently
710      * be passed between processes.
711      *
712      * @hide
713      */
714     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R,
715             publicAlternatives = "Use {@link #asShared()} instead")
createAshmemBitmap()716     public Bitmap createAshmemBitmap() {
717         checkRecycled("Can't copy a recycled bitmap");
718         noteHardwareBitmapSlowCall();
719         Bitmap b = nativeCopyAshmem(mNativePtr);
720         if (b != null) {
721             b.setPremultiplied(mRequestPremultiplied);
722             b.mDensity = mDensity;
723         }
724         return b;
725     }
726 
727     /**
728      * Return an immutable bitmap backed by shared memory which can be
729      * efficiently passed between processes via Parcelable.
730      *
731      * <p>If this bitmap already meets these criteria it will return itself.
732      */
733     @NonNull
asShared()734     public Bitmap asShared() {
735         if (nativeIsBackedByAshmem(mNativePtr) && nativeIsImmutable(mNativePtr)) {
736             return this;
737         }
738         Bitmap shared = createAshmemBitmap();
739         if (shared == null) {
740             throw new RuntimeException("Failed to create shared Bitmap!");
741         }
742         return shared;
743     }
744 
745     /**
746      * Returns the shared memory handle to the pixel storage if the bitmap is already using
747      * shared memory and null if it is not.  The SharedMemory object is then useful to then pass
748      * through HIDL APIs (e.g. WearOS's DisplayOffload service).
749      *
750      * @hide
751      */
getSharedMemory()752     public SharedMemory getSharedMemory() {
753         checkRecycled("Cannot access shared memory of a recycled bitmap");
754         if (nativeIsBackedByAshmem(mNativePtr)) {
755             try {
756                 int fd = nativeGetAshmemFD(mNativePtr);
757                 return SharedMemory.fromFileDescriptor(ParcelFileDescriptor.fromFd(fd));
758             } catch (IOException e) {
759                 Log.e(TAG, "Unable to create dup'd file descriptor for shared bitmap memory");
760             }
761         }
762         return null;
763     }
764 
765     /**
766      * Create a hardware bitmap backed by a {@link HardwareBuffer}.
767      *
768      * <p>The passed HardwareBuffer's usage flags must contain
769      * {@link HardwareBuffer#USAGE_GPU_SAMPLED_IMAGE}.
770      *
771      * <p>The bitmap will keep a reference to the buffer so that callers can safely close the
772      * HardwareBuffer without affecting the Bitmap. However the HardwareBuffer must not be
773      * modified while a wrapped Bitmap is accessing it. Doing so will result in undefined behavior.
774      *
775      * @param hardwareBuffer The HardwareBuffer to wrap.
776      * @param colorSpace The color space of the bitmap. Must be a {@link ColorSpace.Rgb} colorspace.
777      *                   If null, SRGB is assumed.
778      * @return A bitmap wrapping the buffer, or null if there was a problem creating the bitmap.
779      * @throws IllegalArgumentException if the HardwareBuffer has an invalid usage, or an invalid
780      *                                  colorspace is given.
781      */
782     @Nullable
wrapHardwareBuffer(@onNull HardwareBuffer hardwareBuffer, @Nullable ColorSpace colorSpace)783     public static Bitmap wrapHardwareBuffer(@NonNull HardwareBuffer hardwareBuffer,
784             @Nullable ColorSpace colorSpace) {
785         if ((hardwareBuffer.getUsage() & HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE) == 0) {
786             throw new IllegalArgumentException("usage flags must contain USAGE_GPU_SAMPLED_IMAGE.");
787         }
788         int format = hardwareBuffer.getFormat();
789         if (colorSpace == null) {
790             colorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
791         }
792         Bitmap bitmap = nativeWrapHardwareBufferBitmap(hardwareBuffer,
793                 colorSpace.getNativeInstance());
794         if (bitmap != null) {
795             bitmap.mHardwareBuffer = new WeakReference<HardwareBuffer>(hardwareBuffer);
796         }
797         return bitmap;
798     }
799 
800     /**
801      * Creates a new bitmap, scaled from an existing bitmap, when possible. If the
802      * specified width and height are the same as the current width and height of
803      * the source bitmap, the source bitmap is returned and no new bitmap is
804      * created.
805      *
806      * @param src       The source bitmap.
807      * @param dstWidth  The new bitmap's desired width.
808      * @param dstHeight The new bitmap's desired height.
809      * @param filter    Whether or not bilinear filtering should be used when scaling the
810      *                  bitmap. If this is true then bilinear filtering will be used when
811      *                  scaling which has better image quality at the cost of worse performance.
812      *                  If this is false then nearest-neighbor scaling is used instead which
813      *                  will have worse image quality but is faster. Recommended default
814      *                  is to set filter to 'true' as the cost of bilinear filtering is
815      *                  typically minimal and the improved image quality is significant.
816      * @return The new scaled bitmap or the source bitmap if no scaling is required.
817      * @throws IllegalArgumentException if width is <= 0, or height is <= 0
818      */
819     @NonNull
createScaledBitmap(@onNull Bitmap src, int dstWidth, int dstHeight, boolean filter)820     public static Bitmap createScaledBitmap(@NonNull Bitmap src, int dstWidth, int dstHeight,
821             boolean filter) {
822         Matrix m = new Matrix();
823 
824         final int width = src.getWidth();
825         final int height = src.getHeight();
826         if (width != dstWidth || height != dstHeight) {
827             final float sx = dstWidth / (float) width;
828             final float sy = dstHeight / (float) height;
829             m.setScale(sx, sy);
830         }
831         return Bitmap.createBitmap(src, 0, 0, width, height, m, filter);
832     }
833 
834     /**
835      * Returns a bitmap from the source bitmap. The new bitmap may
836      * be the same object as source, or a copy may have been made.  It is
837      * initialized with the same density and color space as the original bitmap.
838      */
839     @NonNull
createBitmap(@onNull Bitmap src)840     public static Bitmap createBitmap(@NonNull Bitmap src) {
841         return createBitmap(src, 0, 0, src.getWidth(), src.getHeight());
842     }
843 
844     /**
845      * Returns a bitmap from the specified subset of the source
846      * bitmap. The new bitmap may be the same object as source, or a copy may
847      * have been made. It is initialized with the same density and color space
848      * as the original bitmap.
849      *
850      * @param source   The bitmap we are subsetting
851      * @param x        The x coordinate of the first pixel in source
852      * @param y        The y coordinate of the first pixel in source
853      * @param width    The number of pixels in each row
854      * @param height   The number of rows
855      * @return A copy of a subset of the source bitmap or the source bitmap itself.
856      * @throws IllegalArgumentException if the x, y, width, height values are
857      *         outside of the dimensions of the source bitmap, or width is <= 0,
858      *         or height is <= 0
859      */
860     @NonNull
createBitmap(@onNull Bitmap source, int x, int y, int width, int height)861     public static Bitmap createBitmap(@NonNull Bitmap source, int x, int y, int width, int height) {
862         return createBitmap(source, x, y, width, height, null, false);
863     }
864 
865     /**
866      * Returns a bitmap from subset of the source bitmap,
867      * transformed by the optional matrix. The new bitmap may be the
868      * same object as source, or a copy may have been made. It is
869      * initialized with the same density and color space as the original
870      * bitmap.
871      *
872      * If the source bitmap is immutable and the requested subset is the
873      * same as the source bitmap itself, then the source bitmap is
874      * returned and no new bitmap is created.
875      *
876      * The returned bitmap will always be mutable except in the following scenarios:
877      * (1) In situations where the source bitmap is returned and the source bitmap is immutable
878      *
879      * (2) The source bitmap is a hardware bitmap. That is {@link #getConfig()} is equivalent to
880      * {@link Config#HARDWARE}
881      *
882      * @param source   The bitmap we are subsetting
883      * @param x        The x coordinate of the first pixel in source
884      * @param y        The y coordinate of the first pixel in source
885      * @param width    The number of pixels in each row
886      * @param height   The number of rows
887      * @param m        Optional matrix to be applied to the pixels
888      * @param filter   true if the source should be filtered.
889      *                   Only applies if the matrix contains more than just
890      *                   translation.
891      * @return A bitmap that represents the specified subset of source
892      * @throws IllegalArgumentException if the x, y, width, height values are
893      *         outside of the dimensions of the source bitmap, or width is <= 0,
894      *         or height is <= 0, or if the source bitmap has already been recycled
895      */
896     @NonNull
createBitmap(@onNull Bitmap source, int x, int y, int width, int height, @Nullable Matrix m, boolean filter)897     public static Bitmap createBitmap(@NonNull Bitmap source, int x, int y, int width, int height,
898             @Nullable Matrix m, boolean filter) {
899 
900         checkXYSign(x, y);
901         checkWidthHeight(width, height);
902         if (x + width > source.getWidth()) {
903             throw new IllegalArgumentException("x + width must be <= bitmap.width()");
904         }
905         if (y + height > source.getHeight()) {
906             throw new IllegalArgumentException("y + height must be <= bitmap.height()");
907         }
908         if (source.isRecycled()) {
909             throw new IllegalArgumentException("cannot use a recycled source in createBitmap");
910         }
911 
912         // check if we can just return our argument unchanged
913         if (!source.isMutable() && x == 0 && y == 0 && width == source.getWidth() &&
914                 height == source.getHeight() && (m == null || m.isIdentity())) {
915             return source;
916         }
917 
918         boolean isHardware = source.getConfig() == Config.HARDWARE;
919         if (isHardware) {
920             source.noteHardwareBitmapSlowCall();
921             source = nativeCopyPreserveInternalConfig(source.mNativePtr);
922         }
923 
924         int neww = width;
925         int newh = height;
926         Bitmap bitmap;
927         Paint paint;
928 
929         Rect srcR = new Rect(x, y, x + width, y + height);
930         RectF dstR = new RectF(0, 0, width, height);
931         RectF deviceR = new RectF();
932 
933         Config newConfig = Config.ARGB_8888;
934         final Config config = source.getConfig();
935         // GIF files generate null configs, assume ARGB_8888
936         if (config != null) {
937             switch (config) {
938                 case RGB_565:
939                     newConfig = Config.RGB_565;
940                     break;
941                 case ALPHA_8:
942                     newConfig = Config.ALPHA_8;
943                     break;
944                 case RGBA_F16:
945                     newConfig = Config.RGBA_F16;
946                     break;
947                 //noinspection deprecation
948                 case ARGB_4444:
949                 case ARGB_8888:
950                 default:
951                     newConfig = Config.ARGB_8888;
952                     break;
953             }
954         }
955 
956         ColorSpace cs = source.getColorSpace();
957 
958         if (m == null || m.isIdentity()) {
959             bitmap = createBitmap(null, neww, newh, newConfig, source.hasAlpha(), cs);
960             paint = null;   // not needed
961         } else {
962             final boolean transformed = !m.rectStaysRect();
963 
964             m.mapRect(deviceR, dstR);
965 
966             neww = Math.round(deviceR.width());
967             newh = Math.round(deviceR.height());
968 
969             Config transformedConfig = newConfig;
970             if (transformed) {
971                 if (transformedConfig != Config.ARGB_8888 && transformedConfig != Config.RGBA_F16) {
972                     transformedConfig = Config.ARGB_8888;
973                     if (cs == null) {
974                         cs = ColorSpace.get(ColorSpace.Named.SRGB);
975                     }
976                 }
977             }
978 
979             bitmap = createBitmap(null, neww, newh, transformedConfig,
980                     transformed || source.hasAlpha(), cs);
981 
982             paint = new Paint();
983             paint.setFilterBitmap(filter);
984             if (transformed) {
985                 paint.setAntiAlias(true);
986             }
987         }
988 
989         // The new bitmap was created from a known bitmap source so assume that
990         // they use the same density
991         bitmap.mDensity = source.mDensity;
992         bitmap.setHasAlpha(source.hasAlpha());
993         bitmap.setPremultiplied(source.mRequestPremultiplied);
994 
995         Canvas canvas = new Canvas(bitmap);
996         canvas.translate(-deviceR.left, -deviceR.top);
997         canvas.concat(m);
998         canvas.drawBitmap(source, srcR, dstR, paint);
999         canvas.setBitmap(null);
1000 
1001         // If the source has a gainmap, apply the same set of transformations to the gainmap
1002         // and set it on the output
1003         if (source.hasGainmap()) {
1004             Bitmap newMapContents = transformGainmap(source, m, neww, newh, paint, srcR, dstR,
1005                     deviceR);
1006             if (newMapContents != null) {
1007                 bitmap.setGainmap(new Gainmap(source.getGainmap(), newMapContents));
1008             }
1009         }
1010 
1011         if (isHardware) {
1012             return bitmap.copy(Config.HARDWARE, false);
1013         }
1014         return bitmap;
1015     }
1016 
transformGainmap(Bitmap source, Matrix m, int neww, int newh, Paint paint, Rect srcR, RectF dstR, RectF deviceR)1017     private static Bitmap transformGainmap(Bitmap source, Matrix m, int neww, int newh, Paint paint,
1018             Rect srcR, RectF dstR, RectF deviceR) {
1019         Canvas canvas;
1020         Bitmap sourceGainmap = source.getGainmap().getGainmapContents();
1021         // Gainmaps can be scaled relative to the base image (eg, 1/4th res)
1022         // Preserve that relative scaling between the base & gainmap in the output
1023         float scaleX = (sourceGainmap.getWidth() / (float) source.getWidth());
1024         float scaleY = (sourceGainmap.getHeight() / (float) source.getHeight());
1025         int mapw = Math.round(neww * scaleX);
1026         int maph = Math.round(newh * scaleY);
1027 
1028         if (mapw == 0 || maph == 0) {
1029             // The gainmap has been scaled away entirely, drop it
1030             return null;
1031         }
1032 
1033         // Scale the computed `srcR` used for rendering the source bitmap to the destination
1034         // to be in gainmap dimensions
1035         Rect gSrcR = new Rect((int) (srcR.left * scaleX),
1036                 (int) (srcR.top * scaleY), (int) (srcR.right * scaleX),
1037                 (int) (srcR.bottom * scaleY));
1038 
1039         // Note: createBitmap isn't used as that requires a non-null colorspace, however
1040         // gainmaps don't have a colorspace. So use `nativeCreate` directly to bypass
1041         // that colorspace enforcement requirement (#getColorSpace() allows a null return)
1042         Bitmap newMapContents = nativeCreate(null, 0, mapw, mapw, maph,
1043                 sourceGainmap.getConfig().nativeInt, true, 0);
1044         newMapContents.eraseColor(0);
1045         canvas = new Canvas(newMapContents);
1046         // Scale the translate & matrix to be in gainmap-relative dimensions
1047         canvas.scale(scaleX, scaleY);
1048         canvas.translate(-deviceR.left, -deviceR.top);
1049         canvas.concat(m);
1050         canvas.drawBitmap(sourceGainmap, gSrcR, dstR, paint);
1051         canvas.setBitmap(null);
1052         // Create a new gainmap using a copy of the metadata information from the source but
1053         // with the transformed bitmap created above
1054         return newMapContents;
1055     }
1056 
1057     /**
1058      * Returns a mutable bitmap with the specified width and height.  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 width    The width of the bitmap
1063      * @param height   The height of the bitmap
1064      * @param config   The bitmap config to create.
1065      * @throws IllegalArgumentException if the width or height are <= 0, or if
1066      *         Config is Config.HARDWARE, because hardware bitmaps are always immutable
1067      */
1068     @NonNull
createBitmap(int width, int height, @NonNull Config config)1069     public static Bitmap createBitmap(int width, int height, @NonNull Config config) {
1070         return createBitmap(width, height, config, true);
1071     }
1072 
1073     /**
1074      * Returns a mutable bitmap with the specified width and height.  Its
1075      * initial density is determined from the given {@link DisplayMetrics}.
1076      * The newly created bitmap is in the {@link ColorSpace.Named#SRGB sRGB}
1077      * color space.
1078      *
1079      * @param display  Display metrics for the display this bitmap will be
1080      *                 drawn on.
1081      * @param width    The width of the bitmap
1082      * @param height   The height of the bitmap
1083      * @param config   The bitmap config to create.
1084      * @throws IllegalArgumentException if the width or height are <= 0, or if
1085      *         Config is Config.HARDWARE, because hardware bitmaps are always immutable
1086      */
1087     @NonNull
createBitmap(@ullable DisplayMetrics display, int width, int height, @NonNull Config config)1088     public static Bitmap createBitmap(@Nullable DisplayMetrics display, int width,
1089             int height, @NonNull Config config) {
1090         return createBitmap(display, width, height, config, true);
1091     }
1092 
1093     /**
1094      * Returns a mutable bitmap with the specified width and height.  Its
1095      * initial density is as per {@link #getDensity}. The newly created
1096      * bitmap is in the {@link ColorSpace.Named#SRGB sRGB} color space.
1097      *
1098      * @param width    The width of the bitmap
1099      * @param height   The height of the bitmap
1100      * @param config   The bitmap config to create.
1101      * @param hasAlpha If the bitmap is ARGB_8888, RGBA_16F, or RGBA_1010102 this flag can be
1102      *                 used to mark the bitmap as opaque. Doing so will clear the bitmap in black
1103      *                 instead of transparent.
1104      *
1105      * @throws IllegalArgumentException if the width or height are <= 0, or if
1106      *         Config is Config.HARDWARE, because hardware bitmaps are always immutable
1107      */
1108     @NonNull
createBitmap(int width, int height, @NonNull Config config, boolean hasAlpha)1109     public static Bitmap createBitmap(int width, int height,
1110             @NonNull Config config, boolean hasAlpha) {
1111         return createBitmap(null, width, height, config, hasAlpha);
1112     }
1113 
1114     /**
1115      * Returns a mutable bitmap with the specified width and height.  Its
1116      * initial density is as per {@link #getDensity}.
1117      *
1118      * @param width    The width of the bitmap
1119      * @param height   The height of the bitmap
1120      * @param config   The bitmap config to create.
1121      * @param hasAlpha If the bitmap is ARGB_8888, RGBA_16F, or RGBA_1010102 this flag can be
1122      *                 used to mark the bitmap as opaque. Doing so will clear the bitmap in black
1123      *                 instead of transparent.
1124      * @param colorSpace The color space of the bitmap. If the config is {@link Config#RGBA_F16}
1125      *                   and {@link ColorSpace.Named#SRGB sRGB} or
1126      *                   {@link ColorSpace.Named#LINEAR_SRGB Linear sRGB} is provided then the
1127      *                   corresponding extended range variant is assumed.
1128      *
1129      * @throws IllegalArgumentException if the width or height are <= 0, if
1130      *         Config is Config.HARDWARE (because hardware bitmaps are always
1131      *         immutable), if the specified color space is not {@link ColorSpace.Model#RGB RGB},
1132      *         if the specified color space's transfer function is not an
1133      *         {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}, or if
1134      *         the color space is null
1135      */
1136     @NonNull
createBitmap(int width, int height, @NonNull Config config, boolean hasAlpha, @NonNull ColorSpace colorSpace)1137     public static Bitmap createBitmap(int width, int height, @NonNull Config config,
1138             boolean hasAlpha, @NonNull ColorSpace colorSpace) {
1139         return createBitmap(null, width, height, config, hasAlpha, colorSpace);
1140     }
1141 
1142     /**
1143      * Returns a mutable bitmap with the specified width and height.  Its
1144      * initial density is determined from the given {@link DisplayMetrics}.
1145      * The newly created bitmap is in the {@link ColorSpace.Named#SRGB sRGB}
1146      * color space.
1147      *
1148      * @param display  Display metrics for the display this bitmap will be
1149      *                 drawn on.
1150      * @param width    The width of the bitmap
1151      * @param height   The height of the bitmap
1152      * @param config   The bitmap config to create.
1153      * @param hasAlpha If the bitmap is ARGB_8888, RGBA_16F, or RGBA_1010102 this flag can be
1154      *                 used to mark the bitmap as opaque. Doing so will clear the bitmap in black
1155      *                 instead of transparent.
1156      *
1157      * @throws IllegalArgumentException if the width or height are <= 0, or if
1158      *         Config is Config.HARDWARE, because hardware bitmaps are always immutable
1159      */
1160     @NonNull
createBitmap(@ullable DisplayMetrics display, int width, int height, @NonNull Config config, boolean hasAlpha)1161     public static Bitmap createBitmap(@Nullable DisplayMetrics display, int width, int height,
1162             @NonNull Config config, boolean hasAlpha) {
1163         return createBitmap(display, width, height, config, hasAlpha,
1164                 ColorSpace.get(ColorSpace.Named.SRGB));
1165     }
1166 
1167     /**
1168      * Returns a mutable bitmap with the specified width and height.  Its
1169      * initial density is determined from the given {@link DisplayMetrics}.
1170      * The newly created bitmap is in the {@link ColorSpace.Named#SRGB sRGB}
1171      * color space.
1172      *
1173      * @param display  Display metrics for the display this bitmap will be
1174      *                 drawn on.
1175      * @param width    The width of the bitmap
1176      * @param height   The height of the bitmap
1177      * @param config   The bitmap config to create.
1178      * @param hasAlpha If the bitmap is ARGB_8888, RGBA_16F, or RGBA_1010102 this flag can be
1179      *                 used to mark the bitmap as opaque. Doing so will clear the bitmap in black
1180      *                 instead of transparent.
1181      * @param colorSpace The color space of the bitmap. If the config is {@link Config#RGBA_F16}
1182      *                   and {@link ColorSpace.Named#SRGB sRGB} or
1183      *                   {@link ColorSpace.Named#LINEAR_SRGB Linear sRGB} is provided then the
1184      *                   corresponding extended range variant is assumed.
1185      *
1186      * @throws IllegalArgumentException if the width or height are <= 0, if
1187      *         Config is Config.HARDWARE (because hardware bitmaps are always
1188      *         immutable), if the specified color space is not {@link ColorSpace.Model#RGB RGB},
1189      *         if the specified color space's transfer function is not an
1190      *         {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}, or if
1191      *         the color space is null
1192      */
1193     @NonNull
createBitmap(@ullable DisplayMetrics display, int width, int height, @NonNull Config config, boolean hasAlpha, @NonNull ColorSpace colorSpace)1194     public static Bitmap createBitmap(@Nullable DisplayMetrics display, int width, int height,
1195             @NonNull Config config, boolean hasAlpha, @NonNull ColorSpace colorSpace) {
1196         if (width <= 0 || height <= 0) {
1197             throw new IllegalArgumentException("width and height must be > 0");
1198         }
1199         if (config == Config.HARDWARE) {
1200             throw new IllegalArgumentException("can't create mutable bitmap with Config.HARDWARE");
1201         }
1202         if (colorSpace == null && config != Config.ALPHA_8) {
1203             throw new IllegalArgumentException("can't create bitmap without a color space");
1204         }
1205 
1206         Bitmap bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true,
1207                 colorSpace == null ? 0 : colorSpace.getNativeInstance());
1208 
1209         if (display != null) {
1210             bm.mDensity = display.densityDpi;
1211         }
1212         bm.setHasAlpha(hasAlpha);
1213         if ((config == Config.ARGB_8888 || config == Config.RGBA_F16) && !hasAlpha) {
1214             nativeErase(bm.mNativePtr, 0xff000000);
1215         }
1216         // No need to initialize the bitmap to zeroes with other configs;
1217         // it is backed by a VM byte array which is by definition preinitialized
1218         // to all zeroes.
1219         return bm;
1220     }
1221 
1222     /**
1223      * Returns a immutable bitmap with the specified width and height, with each
1224      * pixel value set to the corresponding value in the colors array.  Its
1225      * initial density is as per {@link #getDensity}. The newly created
1226      * bitmap is in the {@link ColorSpace.Named#SRGB sRGB} color space.
1227      *
1228      * @param colors   Array of sRGB {@link Color colors} used to initialize the pixels.
1229      * @param offset   Number of values to skip before the first color in the
1230      *                 array of colors.
1231      * @param stride   Number of colors in the array between rows (must be >=
1232      *                 width or <= -width).
1233      * @param width    The width of the bitmap
1234      * @param height   The height of the bitmap
1235      * @param config   The bitmap config to create. If the config does not
1236      *                 support per-pixel alpha (e.g. RGB_565), then the alpha
1237      *                 bytes in the colors[] will be ignored (assumed to be FF)
1238      * @throws IllegalArgumentException if the width or height are <= 0, or if
1239      *         the color array's length is less than the number of pixels.
1240      */
1241     @NonNull
createBitmap(@onNull @olorInt int[] colors, int offset, int stride, int width, int height, @NonNull Config config)1242     public static Bitmap createBitmap(@NonNull @ColorInt int[] colors, int offset, int stride,
1243             int width, int height, @NonNull Config config) {
1244         return createBitmap(null, colors, offset, stride, width, height, config);
1245     }
1246 
1247     /**
1248      * Returns a immutable bitmap with the specified width and height, with each
1249      * pixel value set to the corresponding value in the colors array.  Its
1250      * initial density is determined from the given {@link DisplayMetrics}.
1251      * The newly created bitmap is in the {@link ColorSpace.Named#SRGB sRGB}
1252      * color space.
1253      *
1254      * @param display  Display metrics for the display this bitmap will be
1255      *                 drawn on.
1256      * @param colors   Array of sRGB {@link Color colors} used to initialize the pixels.
1257      * @param offset   Number of values to skip before the first color in the
1258      *                 array of colors.
1259      * @param stride   Number of colors in the array between rows (must be >=
1260      *                 width or <= -width).
1261      * @param width    The width of the bitmap
1262      * @param height   The height of the bitmap
1263      * @param config   The bitmap config to create. If the config does not
1264      *                 support per-pixel alpha (e.g. RGB_565), then the alpha
1265      *                 bytes in the colors[] will be ignored (assumed to be FF)
1266      * @throws IllegalArgumentException if the width or height are <= 0, or if
1267      *         the color array's length is less than the number of pixels.
1268      */
1269     @NonNull
createBitmap(@onNull DisplayMetrics display, @NonNull @ColorInt int[] colors, int offset, int stride, int width, int height, @NonNull Config config)1270     public static Bitmap createBitmap(@NonNull DisplayMetrics display,
1271             @NonNull @ColorInt int[] colors, int offset, int stride,
1272             int width, int height, @NonNull Config config) {
1273 
1274         checkWidthHeight(width, height);
1275         if (Math.abs(stride) < width) {
1276             throw new IllegalArgumentException("abs(stride) must be >= width");
1277         }
1278         int lastScanline = offset + (height - 1) * stride;
1279         int length = colors.length;
1280         if (offset < 0 || (offset + width > length) || lastScanline < 0 ||
1281                 (lastScanline + width > length)) {
1282             throw new ArrayIndexOutOfBoundsException();
1283         }
1284         if (width <= 0 || height <= 0) {
1285             throw new IllegalArgumentException("width and height must be > 0");
1286         }
1287         ColorSpace sRGB = ColorSpace.get(ColorSpace.Named.SRGB);
1288         Bitmap bm = nativeCreate(colors, offset, stride, width, height,
1289                             config.nativeInt, false, sRGB.getNativeInstance());
1290         if (display != null) {
1291             bm.mDensity = display.densityDpi;
1292         }
1293         return bm;
1294     }
1295 
1296     /**
1297      * Returns a immutable bitmap with the specified width and height, with each
1298      * pixel value set to the corresponding value in the colors array.  Its
1299      * initial density is as per {@link #getDensity}. The newly created
1300      * bitmap is in the {@link ColorSpace.Named#SRGB sRGB} color space.
1301      *
1302      * @param colors   Array of sRGB {@link Color colors} used to initialize the pixels.
1303      *                 This array must be at least as large as width * height.
1304      * @param width    The width of the bitmap
1305      * @param height   The height of the bitmap
1306      * @param config   The bitmap config to create. If the config does not
1307      *                 support per-pixel alpha (e.g. RGB_565), then the alpha
1308      *                 bytes in the colors[] will be ignored (assumed to be FF)
1309      * @throws IllegalArgumentException if the width or height are <= 0, or if
1310      *         the color array's length is less than the number of pixels.
1311      */
1312     @NonNull
createBitmap(@onNull @olorInt int[] colors, int width, int height, Config config)1313     public static Bitmap createBitmap(@NonNull @ColorInt int[] colors,
1314             int width, int height, Config config) {
1315         return createBitmap(null, colors, 0, width, width, height, config);
1316     }
1317 
1318     /**
1319      * Returns a immutable bitmap with the specified width and height, with each
1320      * pixel value set to the corresponding value in the colors array.  Its
1321      * initial density is determined from the given {@link DisplayMetrics}.
1322      * The newly created bitmap is in the {@link ColorSpace.Named#SRGB sRGB}
1323      * color space.
1324      *
1325      * @param display  Display metrics for the display this bitmap will be
1326      *                 drawn on.
1327      * @param colors   Array of sRGB {@link Color colors} used to initialize the pixels.
1328      *                 This array must be at least as large as width * height.
1329      * @param width    The width of the bitmap
1330      * @param height   The height of the bitmap
1331      * @param config   The bitmap config to create. If the config does not
1332      *                 support per-pixel alpha (e.g. RGB_565), then the alpha
1333      *                 bytes in the colors[] will be ignored (assumed to be FF)
1334      * @throws IllegalArgumentException if the width or height are <= 0, or if
1335      *         the color array's length is less than the number of pixels.
1336      */
1337     @NonNull
createBitmap(@ullable DisplayMetrics display, @NonNull @ColorInt int colors[], int width, int height, @NonNull Config config)1338     public static Bitmap createBitmap(@Nullable DisplayMetrics display,
1339             @NonNull @ColorInt int colors[], int width, int height, @NonNull Config config) {
1340         return createBitmap(display, colors, 0, width, width, height, config);
1341     }
1342 
1343     /**
1344      * Creates a Bitmap from the given {@link Picture} source of recorded drawing commands.
1345      *
1346      * Equivalent to calling {@link #createBitmap(Picture, int, int, Config)} with
1347      * width and height the same as the Picture's width and height and a Config.HARDWARE
1348      * config.
1349      *
1350      * @param source The recorded {@link Picture} of drawing commands that will be
1351      *               drawn into the returned Bitmap.
1352      * @return An immutable bitmap with a HARDWARE config whose contents are created
1353      * from the recorded drawing commands in the Picture source.
1354      */
1355     @NonNull
createBitmap(@onNull Picture source)1356     public static Bitmap createBitmap(@NonNull Picture source) {
1357         return createBitmap(source, source.getWidth(), source.getHeight(), Config.HARDWARE);
1358     }
1359 
1360     /**
1361      * Creates a Bitmap from the given {@link Picture} source of recorded drawing commands.
1362      *
1363      * The bitmap will be immutable with the given width and height. If the width and height
1364      * are not the same as the Picture's width & height, the Picture will be scaled to
1365      * fit the given width and height.
1366      *
1367      * @param source The recorded {@link Picture} of drawing commands that will be
1368      *               drawn into the returned Bitmap.
1369      * @param width The width of the bitmap to create. The picture's width will be
1370      *              scaled to match if necessary.
1371      * @param height The height of the bitmap to create. The picture's height will be
1372      *              scaled to match if necessary.
1373      * @param config The {@link Config} of the created bitmap.
1374      *
1375      * @return An immutable bitmap with a configuration specified by the config parameter
1376      */
1377     @NonNull
createBitmap(@onNull Picture source, int width, int height, @NonNull Config config)1378     public static Bitmap createBitmap(@NonNull Picture source, int width, int height,
1379             @NonNull Config config) {
1380         if (width <= 0 || height <= 0) {
1381             throw new IllegalArgumentException("width & height must be > 0");
1382         }
1383         if (config == null) {
1384             throw new IllegalArgumentException("Config must not be null");
1385         }
1386         source.endRecording();
1387         if (source.requiresHardwareAcceleration() && config != Config.HARDWARE) {
1388             StrictMode.noteSlowCall("GPU readback");
1389         }
1390         if (config == Config.HARDWARE || source.requiresHardwareAcceleration()) {
1391             final RenderNode node = RenderNode.create("BitmapTemporary", null);
1392             node.setLeftTopRightBottom(0, 0, width, height);
1393             node.setClipToBounds(false);
1394             node.setForceDarkAllowed(false);
1395             final RecordingCanvas canvas = node.beginRecording(width, height);
1396             if (source.getWidth() != width || source.getHeight() != height) {
1397                 canvas.scale(width / (float) source.getWidth(),
1398                         height / (float) source.getHeight());
1399             }
1400             canvas.drawPicture(source);
1401             node.endRecording();
1402             Bitmap bitmap = ThreadedRenderer.createHardwareBitmap(node, width, height);
1403             if (config != Config.HARDWARE) {
1404                 bitmap = bitmap.copy(config, false);
1405             }
1406             return bitmap;
1407         } else {
1408             Bitmap bitmap = Bitmap.createBitmap(width, height, config);
1409             Canvas canvas = new Canvas(bitmap);
1410             if (source.getWidth() != width || source.getHeight() != height) {
1411                 canvas.scale(width / (float) source.getWidth(),
1412                         height / (float) source.getHeight());
1413             }
1414             canvas.drawPicture(source);
1415             canvas.setBitmap(null);
1416             bitmap.setImmutable();
1417             return bitmap;
1418         }
1419     }
1420 
1421     /**
1422      * Returns an optional array of private data, used by the UI system for
1423      * some bitmaps. Not intended to be called by applications.
1424      */
1425     @Nullable
getNinePatchChunk()1426     public byte[] getNinePatchChunk() {
1427         return mNinePatchChunk;
1428     }
1429 
1430     /**
1431      * Populates a rectangle with the bitmap's optical insets.
1432      *
1433      * @param outInsets Rect to populate with optical insets
1434      *
1435      * @hide
1436      * Must be public for access from android.graphics.drawable,
1437      * but must not be called from outside the UI module.
1438      */
getOpticalInsets(@onNull Rect outInsets)1439     public void getOpticalInsets(@NonNull Rect outInsets) {
1440         if (mNinePatchInsets == null) {
1441             outInsets.setEmpty();
1442         } else {
1443             outInsets.set(mNinePatchInsets.opticalRect);
1444         }
1445     }
1446 
1447     /**
1448      * @hide
1449      * Must be public for access from android.graphics.drawable,
1450      * but must not be called from outside the UI module.
1451      */
getNinePatchInsets()1452     public NinePatch.InsetStruct getNinePatchInsets() {
1453         return mNinePatchInsets;
1454     }
1455 
1456     /**
1457      * Specifies the known formats a bitmap can be compressed into
1458      */
1459     public enum CompressFormat {
1460         /**
1461          * Compress to the JPEG format. {@code quality} of {@code 0} means
1462          * compress for the smallest size. {@code 100} means compress for max
1463          * visual quality.
1464          */
1465         JPEG          (0),
1466         /**
1467          * Compress to the PNG format. PNG is lossless, so {@code quality} is
1468          * ignored.
1469          */
1470         PNG           (1),
1471         /**
1472          * Compress to the WEBP format. {@code quality} of {@code 0} means
1473          * compress for the smallest size. {@code 100} means compress for max
1474          * visual quality. As of {@link android.os.Build.VERSION_CODES#Q}, a
1475          * value of {@code 100} results in a file in the lossless WEBP format.
1476          * Otherwise the file will be in the lossy WEBP format.
1477          *
1478          * @deprecated in favor of the more explicit
1479          *             {@link CompressFormat#WEBP_LOSSY} and
1480          *             {@link CompressFormat#WEBP_LOSSLESS}.
1481          */
1482         @Deprecated
1483         WEBP          (2),
1484         /**
1485          * Compress to the WEBP lossy format. {@code quality} of {@code 0} means
1486          * compress for the smallest size. {@code 100} means compress for max
1487          * visual quality.
1488          */
1489         WEBP_LOSSY    (3),
1490         /**
1491          * Compress to the WEBP lossless format. {@code quality} refers to how
1492          * much effort to put into compression. A value of {@code 0} means to
1493          * compress quickly, resulting in a relatively large file size.
1494          * {@code 100} means to spend more time compressing, resulting in a
1495          * smaller file.
1496          */
1497         WEBP_LOSSLESS (4);
1498 
CompressFormat(int nativeInt)1499         CompressFormat(int nativeInt) {
1500             this.nativeInt = nativeInt;
1501         }
1502         final int nativeInt;
1503     }
1504 
1505     /**
1506      * Number of bytes of temp storage we use for communicating between the
1507      * native compressor and the java OutputStream.
1508      */
1509     private final static int WORKING_COMPRESS_STORAGE = 4096;
1510 
1511     /**
1512      * Write a compressed version of the bitmap to the specified outputstream.
1513      * If this returns true, the bitmap can be reconstructed by passing a
1514      * corresponding inputstream to BitmapFactory.decodeStream(). Note: not
1515      * all Formats support all bitmap configs directly, so it is possible that
1516      * the returned bitmap from BitmapFactory could be in a different bitdepth,
1517      * and/or may have lost per-pixel alpha (e.g. JPEG only supports opaque
1518      * pixels).
1519      *
1520      * @param format   The format of the compressed image
1521      * @param quality  Hint to the compressor, 0-100. The value is interpreted
1522      *                 differently depending on the {@link CompressFormat}.
1523      * @param stream   The outputstream to write the compressed data.
1524      * @return true if successfully compressed to the specified stream.
1525      */
1526     @WorkerThread
compress(@onNull CompressFormat format, int quality, @NonNull OutputStream stream)1527     public boolean compress(@NonNull CompressFormat format, int quality,
1528                             @NonNull OutputStream stream) {
1529         checkRecycled("Can't compress a recycled bitmap");
1530         // do explicit check before calling the native method
1531         if (stream == null) {
1532             throw new NullPointerException();
1533         }
1534         if (quality < 0 || quality > 100) {
1535             throw new IllegalArgumentException("quality must be 0..100");
1536         }
1537         StrictMode.noteSlowCall("Compression of a bitmap is slow");
1538         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "Bitmap.compress");
1539         boolean result = nativeCompress(mNativePtr, format.nativeInt,
1540                 quality, stream, new byte[WORKING_COMPRESS_STORAGE]);
1541         Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
1542         return result;
1543     }
1544 
1545     /**
1546      * Returns true if the bitmap is marked as mutable (i.e.&nbsp;can be drawn into)
1547      */
isMutable()1548     public final boolean isMutable() {
1549         return !nativeIsImmutable(mNativePtr);
1550     }
1551 
1552     /**
1553      * Marks the Bitmap as immutable. Further modifications to this Bitmap are disallowed.
1554      * After this method is called, this Bitmap cannot be made mutable again and subsequent calls
1555      * to {@link #reconfigure(int, int, Config)}, {@link #setPixel(int, int, int)},
1556      * {@link #setPixels(int[], int, int, int, int, int, int)} and {@link #eraseColor(int)} will
1557      * fail and throw an IllegalStateException.
1558      */
setImmutable()1559     private void setImmutable() {
1560         if (isMutable()) {
1561             nativeSetImmutable(mNativePtr);
1562         }
1563     }
1564 
1565     /**
1566      * <p>Indicates whether pixels stored in this bitmaps are stored pre-multiplied.
1567      * When a pixel is pre-multiplied, the RGB components have been multiplied by
1568      * the alpha component. For instance, if the original color is a 50%
1569      * translucent red <code>(128, 255, 0, 0)</code>, the pre-multiplied form is
1570      * <code>(128, 128, 0, 0)</code>.</p>
1571      *
1572      * <p>This method always returns false if {@link #getConfig()} is
1573      * {@link Bitmap.Config#RGB_565}.</p>
1574      *
1575      * <p>The return value is undefined if {@link #getConfig()} is
1576      * {@link Bitmap.Config#ALPHA_8}.</p>
1577      *
1578      * <p>This method only returns true if {@link #hasAlpha()} returns true.
1579      * A bitmap with no alpha channel can be used both as a pre-multiplied and
1580      * as a non pre-multiplied bitmap.</p>
1581      *
1582      * <p>Only pre-multiplied bitmaps may be drawn by the view system or
1583      * {@link Canvas}. If a non-pre-multiplied bitmap with an alpha channel is
1584      * drawn to a Canvas, a RuntimeException will be thrown.</p>
1585      *
1586      * @return true if the underlying pixels have been pre-multiplied, false
1587      *         otherwise
1588      *
1589      * @see Bitmap#setPremultiplied(boolean)
1590      * @see BitmapFactory.Options#inPremultiplied
1591      */
isPremultiplied()1592     public final boolean isPremultiplied() {
1593         if (mRecycled) {
1594             Log.w(TAG, "Called isPremultiplied() on a recycle()'d bitmap! This is undefined behavior!");
1595         }
1596         return nativeIsPremultiplied(mNativePtr);
1597     }
1598 
1599     /**
1600      * Sets whether the bitmap should treat its data as pre-multiplied.
1601      *
1602      * <p>Bitmaps are always treated as pre-multiplied by the view system and
1603      * {@link Canvas} for performance reasons. Storing un-pre-multiplied data in
1604      * a Bitmap (through {@link #setPixel}, {@link #setPixels}, or {@link
1605      * BitmapFactory.Options#inPremultiplied BitmapFactory.Options.inPremultiplied})
1606      * can lead to incorrect blending if drawn by the framework.</p>
1607      *
1608      * <p>This method will not affect the behavior of a bitmap without an alpha
1609      * channel, or if {@link #hasAlpha()} returns false.</p>
1610      *
1611      * <p>Calling {@link #createBitmap} or {@link #createScaledBitmap} with a source
1612      * Bitmap whose colors are not pre-multiplied may result in a RuntimeException,
1613      * since those functions require drawing the source, which is not supported for
1614      * un-pre-multiplied Bitmaps.</p>
1615      *
1616      * @see Bitmap#isPremultiplied()
1617      * @see BitmapFactory.Options#inPremultiplied
1618      */
setPremultiplied(boolean premultiplied)1619     public final void setPremultiplied(boolean premultiplied) {
1620         checkRecycled("setPremultiplied called on a recycled bitmap");
1621         mRequestPremultiplied = premultiplied;
1622         nativeSetPremultiplied(mNativePtr, premultiplied);
1623     }
1624 
1625     /** Returns the bitmap's width */
getWidth()1626     public final int getWidth() {
1627         if (mRecycled) {
1628             Log.w(TAG, "Called getWidth() on a recycle()'d bitmap! This is undefined behavior!");
1629         }
1630         return mWidth;
1631     }
1632 
1633     /** Returns the bitmap's height */
getHeight()1634     public final int getHeight() {
1635         if (mRecycled) {
1636             Log.w(TAG, "Called getHeight() on a recycle()'d bitmap! This is undefined behavior!");
1637         }
1638         return mHeight;
1639     }
1640 
1641     /**
1642      * Convenience for calling {@link #getScaledWidth(int)} with the target
1643      * density of the given {@link Canvas}.
1644      */
getScaledWidth(@onNull Canvas canvas)1645     public int getScaledWidth(@NonNull Canvas canvas) {
1646         return scaleFromDensity(getWidth(), mDensity, canvas.mDensity);
1647     }
1648 
1649     /**
1650      * Convenience for calling {@link #getScaledHeight(int)} with the target
1651      * density of the given {@link Canvas}.
1652      */
getScaledHeight(@onNull Canvas canvas)1653     public int getScaledHeight(@NonNull Canvas canvas) {
1654         return scaleFromDensity(getHeight(), mDensity, canvas.mDensity);
1655     }
1656 
1657     /**
1658      * Convenience for calling {@link #getScaledWidth(int)} with the target
1659      * density of the given {@link DisplayMetrics}.
1660      */
getScaledWidth(@onNull DisplayMetrics metrics)1661     public int getScaledWidth(@NonNull DisplayMetrics metrics) {
1662         return scaleFromDensity(getWidth(), mDensity, metrics.densityDpi);
1663     }
1664 
1665     /**
1666      * Convenience for calling {@link #getScaledHeight(int)} with the target
1667      * density of the given {@link DisplayMetrics}.
1668      */
getScaledHeight(@onNull DisplayMetrics metrics)1669     public int getScaledHeight(@NonNull DisplayMetrics metrics) {
1670         return scaleFromDensity(getHeight(), mDensity, metrics.densityDpi);
1671     }
1672 
1673     /**
1674      * Convenience method that returns the width of this bitmap divided
1675      * by the density scale factor.
1676      *
1677      * Returns the bitmap's width multiplied by the ratio of the target density to the bitmap's
1678      * source density
1679      *
1680      * @param targetDensity The density of the target canvas of the bitmap.
1681      * @return The scaled width of this bitmap, according to the density scale factor.
1682      */
getScaledWidth(int targetDensity)1683     public int getScaledWidth(int targetDensity) {
1684         return scaleFromDensity(getWidth(), mDensity, targetDensity);
1685     }
1686 
1687     /**
1688      * Convenience method that returns the height of this bitmap divided
1689      * by the density scale factor.
1690      *
1691      * Returns the bitmap's height multiplied by the ratio of the target density to the bitmap's
1692      * source density
1693      *
1694      * @param targetDensity The density of the target canvas of the bitmap.
1695      * @return The scaled height of this bitmap, according to the density scale factor.
1696      */
getScaledHeight(int targetDensity)1697     public int getScaledHeight(int targetDensity) {
1698         return scaleFromDensity(getHeight(), mDensity, targetDensity);
1699     }
1700 
1701     /**
1702      * @hide
1703      * Must be public for access from android.graphics.drawable,
1704      * but must not be called from outside the UI module.
1705      */
1706     @UnsupportedAppUsage
scaleFromDensity(int size, int sdensity, int tdensity)1707     static public int scaleFromDensity(int size, int sdensity, int tdensity) {
1708         if (sdensity == DENSITY_NONE || tdensity == DENSITY_NONE || sdensity == tdensity) {
1709             return size;
1710         }
1711 
1712         // Scale by tdensity / sdensity, rounding up.
1713         return ((size * tdensity) + (sdensity >> 1)) / sdensity;
1714     }
1715 
1716     /**
1717      * Return the number of bytes between rows in the bitmap's pixels. Note that
1718      * this refers to the pixels as stored natively by the bitmap. If you call
1719      * getPixels() or setPixels(), then the pixels are uniformly treated as
1720      * 32bit values, packed according to the Color class.
1721      *
1722      * <p>As of {@link android.os.Build.VERSION_CODES#KITKAT}, this method
1723      * should not be used to calculate the memory usage of the bitmap. Instead,
1724      * see {@link #getAllocationByteCount()}.
1725      *
1726      * @return number of bytes between rows of the native bitmap pixels.
1727      */
getRowBytes()1728     public final int getRowBytes() {
1729         if (mRecycled) {
1730             Log.w(TAG, "Called getRowBytes() on a recycle()'d bitmap! This is undefined behavior!");
1731         }
1732         return nativeRowBytes(mNativePtr);
1733     }
1734 
1735     /**
1736      * Returns the minimum number of bytes that can be used to store this bitmap's pixels.
1737      *
1738      * <p>As of {@link android.os.Build.VERSION_CODES#KITKAT}, the result of this method can
1739      * no longer be used to determine memory usage of a bitmap. See {@link
1740      * #getAllocationByteCount()}.</p>
1741      */
getByteCount()1742     public final int getByteCount() {
1743         if (mRecycled) {
1744             Log.w(TAG, "Called getByteCount() on a recycle()'d bitmap! "
1745                     + "This is undefined behavior!");
1746             return 0;
1747         }
1748         // int result permits bitmaps up to 46,340 x 46,340
1749         return getRowBytes() * getHeight();
1750     }
1751 
1752     /**
1753      * Returns the size of the allocated memory used to store this bitmap's pixels.
1754      *
1755      * <p>This can be larger than the result of {@link #getByteCount()} if a bitmap is reused to
1756      * decode other bitmaps of smaller size, or by manual reconfiguration. See {@link
1757      * #reconfigure(int, int, Config)}, {@link #setWidth(int)}, {@link #setHeight(int)}, {@link
1758      * #setConfig(Bitmap.Config)}, and {@link BitmapFactory.Options#inBitmap
1759      * BitmapFactory.Options.inBitmap}. If a bitmap is not modified in this way, this value will be
1760      * the same as that returned by {@link #getByteCount()}.</p>
1761      *
1762      * <p>This value will not change over the lifetime of a Bitmap.</p>
1763      *
1764      * @see #reconfigure(int, int, Config)
1765      */
getAllocationByteCount()1766     public final int getAllocationByteCount() {
1767         if (mRecycled) {
1768             Log.w(TAG, "Called getAllocationByteCount() on a recycle()'d bitmap! "
1769                     + "This is undefined behavior!");
1770             return 0;
1771         }
1772         return nativeGetAllocationByteCount(mNativePtr);
1773     }
1774 
1775     /**
1776      * If the bitmap's internal config is in one of the public formats, return
1777      * that config, otherwise return null.
1778      */
1779     @NonNull
getConfig()1780     public final Config getConfig() {
1781         if (mRecycled) {
1782             Log.w(TAG, "Called getConfig() on a recycle()'d bitmap! This is undefined behavior!");
1783         }
1784         return Config.nativeToConfig(nativeConfig(mNativePtr));
1785     }
1786 
1787     /** Returns true if the bitmap's config supports per-pixel alpha, and
1788      * if the pixels may contain non-opaque alpha values. For some configs,
1789      * this is always false (e.g. RGB_565), since they do not support per-pixel
1790      * alpha. However, for configs that do, the bitmap may be flagged to be
1791      * known that all of its pixels are opaque. In this case hasAlpha() will
1792      * also return false. If a config such as ARGB_8888 is not so flagged,
1793      * it will return true by default.
1794      */
hasAlpha()1795     public final boolean hasAlpha() {
1796         if (mRecycled) {
1797             Log.w(TAG, "Called hasAlpha() on a recycle()'d bitmap! This is undefined behavior!");
1798         }
1799         return nativeHasAlpha(mNativePtr);
1800     }
1801 
1802     /**
1803      * Tell the bitmap if all of the pixels are known to be opaque (false)
1804      * or if some of the pixels may contain non-opaque alpha values (true).
1805      * Note, for some configs (e.g. RGB_565) this call is ignored, since it
1806      * does not support per-pixel alpha values.
1807      *
1808      * This is meant as a drawing hint, as in some cases a bitmap that is known
1809      * to be opaque can take a faster drawing case than one that may have
1810      * non-opaque per-pixel alpha values.
1811      */
setHasAlpha(boolean hasAlpha)1812     public void setHasAlpha(boolean hasAlpha) {
1813         checkRecycled("setHasAlpha called on a recycled bitmap");
1814         nativeSetHasAlpha(mNativePtr, hasAlpha, mRequestPremultiplied);
1815     }
1816 
1817     /**
1818      * Indicates whether the renderer responsible for drawing this
1819      * bitmap should attempt to use mipmaps when this bitmap is drawn
1820      * scaled down.
1821      *
1822      * If you know that you are going to draw this bitmap at less than
1823      * 50% of its original size, you may be able to obtain a higher
1824      * quality
1825      *
1826      * This property is only a suggestion that can be ignored by the
1827      * renderer. It is not guaranteed to have any effect.
1828      *
1829      * @return true if the renderer should attempt to use mipmaps,
1830      *         false otherwise
1831      *
1832      * @see #setHasMipMap(boolean)
1833      */
hasMipMap()1834     public final boolean hasMipMap() {
1835         if (mRecycled) {
1836             Log.w(TAG, "Called hasMipMap() on a recycle()'d bitmap! This is undefined behavior!");
1837         }
1838         return nativeHasMipMap(mNativePtr);
1839     }
1840 
1841     /**
1842      * Set a hint for the renderer responsible for drawing this bitmap
1843      * indicating that it should attempt to use mipmaps when this bitmap
1844      * is drawn scaled down.
1845      *
1846      * If you know that you are going to draw this bitmap at less than
1847      * 50% of its original size, you may be able to obtain a higher
1848      * quality by turning this property on.
1849      *
1850      * Note that if the renderer respects this hint it might have to
1851      * allocate extra memory to hold the mipmap levels for this bitmap.
1852      *
1853      * This property is only a suggestion that can be ignored by the
1854      * renderer. It is not guaranteed to have any effect.
1855      *
1856      * @param hasMipMap indicates whether the renderer should attempt
1857      *                  to use mipmaps
1858      *
1859      * @see #hasMipMap()
1860      */
setHasMipMap(boolean hasMipMap)1861     public final void setHasMipMap(boolean hasMipMap) {
1862         checkRecycled("setHasMipMap called on a recycled bitmap");
1863         nativeSetHasMipMap(mNativePtr, hasMipMap);
1864     }
1865 
1866     /**
1867      * Returns the color space associated with this bitmap. If the color
1868      * space is unknown, this method returns null.
1869      */
1870     @Nullable
getColorSpace()1871     public final ColorSpace getColorSpace() {
1872         checkRecycled("getColorSpace called on a recycled bitmap");
1873         if (mColorSpace == null) {
1874             mColorSpace = nativeComputeColorSpace(mNativePtr);
1875         }
1876         return mColorSpace;
1877     }
1878 
1879     /**
1880      * <p>Modifies the bitmap to have the specified {@link ColorSpace}, without
1881      * affecting the underlying allocation backing the bitmap.</p>
1882      *
1883      * <p>This affects how the framework will interpret the color at each pixel. A bitmap
1884      * with {@link Config#ALPHA_8} never has a color space, since a color space does not
1885      * affect the alpha channel. Other {@code Config}s must always have a non-null
1886      * {@code ColorSpace}.</p>
1887      *
1888      * @throws IllegalArgumentException If the specified color space is {@code null}, not
1889      *         {@link ColorSpace.Model#RGB RGB}, or whose components min/max values reduce
1890      *         the numerical range compared to the previously assigned color space.
1891      *         Prior to {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE},
1892      *         <code>IllegalArgumentException</code> will also be thrown
1893      *         if the specified color space has a transfer function that is not an
1894      *         {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}. Starting from
1895      *         {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, the color spaces with non
1896      *         ICC parametric curve transfer function are allowed.
1897      *         E.g., {@link ColorSpace.Named#BT2020_HLG BT2020_HLG}.
1898      *
1899      * @throws IllegalArgumentException If the {@code Config} (returned by {@link #getConfig()})
1900      *         is {@link Config#ALPHA_8}.
1901      *
1902      * @param colorSpace to assign to the bitmap
1903      */
setColorSpace(@onNull ColorSpace colorSpace)1904     public void setColorSpace(@NonNull ColorSpace colorSpace) {
1905         checkRecycled("setColorSpace called on a recycled bitmap");
1906         if (colorSpace == null) {
1907             throw new IllegalArgumentException("The colorSpace cannot be set to null");
1908         }
1909 
1910         if (getConfig() == Config.ALPHA_8) {
1911             throw new IllegalArgumentException("Cannot set a ColorSpace on ALPHA_8");
1912         }
1913 
1914         // Keep track of the old ColorSpace for comparison, and so we can reset it in case of an
1915         // Exception.
1916         final ColorSpace oldColorSpace = getColorSpace();
1917         nativeSetColorSpace(mNativePtr, colorSpace.getNativeInstance());
1918 
1919         // This will update mColorSpace. It may not be the same as |colorSpace|, e.g. if we
1920         // corrected it because the Bitmap is F16.
1921         mColorSpace = null;
1922         final ColorSpace newColorSpace = getColorSpace();
1923 
1924         try {
1925             if (oldColorSpace.getComponentCount() != newColorSpace.getComponentCount()) {
1926                 throw new IllegalArgumentException("The new ColorSpace must have the same "
1927                         + "component count as the current ColorSpace");
1928             } else {
1929                 for (int i = 0; i < oldColorSpace.getComponentCount(); i++) {
1930                     if (oldColorSpace.getMinValue(i) < newColorSpace.getMinValue(i)) {
1931                         throw new IllegalArgumentException("The new ColorSpace cannot increase the "
1932                                 + "minimum value for any of the components compared to the current "
1933                                 + "ColorSpace. To perform this type of conversion create a new "
1934                                 + "Bitmap in the desired ColorSpace and draw this Bitmap into it.");
1935                     }
1936                     if (oldColorSpace.getMaxValue(i) > newColorSpace.getMaxValue(i)) {
1937                         throw new IllegalArgumentException("The new ColorSpace cannot decrease the "
1938                                 + "maximum value for any of the components compared to the current "
1939                                 + "ColorSpace/ To perform this type of conversion create a new "
1940                                 + "Bitmap in the desired ColorSpace and draw this Bitmap into it.");
1941                     }
1942                 }
1943             }
1944         } catch (IllegalArgumentException e) {
1945             // Undo the change to the ColorSpace.
1946             mColorSpace = oldColorSpace;
1947             nativeSetColorSpace(mNativePtr, mColorSpace.getNativeInstance());
1948             throw e;
1949         }
1950     }
1951 
1952     /**
1953      * Returns whether or not this Bitmap contains a Gainmap.
1954      */
hasGainmap()1955     public boolean hasGainmap() {
1956         checkRecycled("Bitmap is recycled");
1957         return nativeHasGainmap(mNativePtr);
1958     }
1959 
1960     /**
1961      * Returns the gainmap or null if the bitmap doesn't contain a gainmap
1962      */
getGainmap()1963     public @Nullable Gainmap getGainmap() {
1964         checkRecycled("Bitmap is recycled");
1965         if (mGainmap == null) {
1966             mGainmap = nativeExtractGainmap(mNativePtr);
1967         }
1968         return mGainmap;
1969     }
1970 
1971     /**
1972      * Sets a gainmap on this bitmap, or removes the gainmap if null
1973      */
setGainmap(@ullable Gainmap gainmap)1974     public void setGainmap(@Nullable Gainmap gainmap) {
1975         checkRecycled("Bitmap is recycled");
1976         mGainmap = null;
1977         nativeSetGainmap(mNativePtr, gainmap == null ? 0 : gainmap.mNativePtr);
1978     }
1979 
1980     /**
1981      * Fills the bitmap's pixels with the specified {@link Color}.
1982      *
1983      * @throws IllegalStateException if the bitmap is not mutable.
1984      */
eraseColor(@olorInt int c)1985     public void eraseColor(@ColorInt int c) {
1986         checkRecycled("Can't erase a recycled bitmap");
1987         if (!isMutable()) {
1988             throw new IllegalStateException("cannot erase immutable bitmaps");
1989         }
1990         nativeErase(mNativePtr, c);
1991     }
1992 
1993     /**
1994      * Fills the bitmap's pixels with the specified {@code ColorLong}.
1995      *
1996      * @param color The color to fill as packed by the {@link Color} class.
1997      * @throws IllegalStateException if the bitmap is not mutable.
1998      * @throws IllegalArgumentException if the color space encoded in the
1999      *                                  {@code ColorLong} is invalid or unknown.
2000      *
2001      */
eraseColor(@olorLong long color)2002     public void eraseColor(@ColorLong long color) {
2003         checkRecycled("Can't erase a recycled bitmap");
2004         if (!isMutable()) {
2005             throw new IllegalStateException("cannot erase immutable bitmaps");
2006         }
2007 
2008         ColorSpace cs = Color.colorSpace(color);
2009         nativeErase(mNativePtr, cs.getNativeInstance(), color);
2010     }
2011 
2012     /**
2013      * Returns the {@link Color} at the specified location. Throws an exception
2014      * if x or y are out of bounds (negative or >= to the width or height
2015      * respectively). The returned color is a non-premultiplied ARGB value in
2016      * the {@link ColorSpace.Named#SRGB sRGB} color space.
2017      *
2018      * @param x    The x coordinate (0...width-1) of the pixel to return
2019      * @param y    The y coordinate (0...height-1) of the pixel to return
2020      * @return     The argb {@link Color} at the specified coordinate
2021      * @throws IllegalArgumentException if x, y exceed the bitmap's bounds
2022      * @throws IllegalStateException if the bitmap's config is {@link Config#HARDWARE}
2023      */
2024     @ColorInt
getPixel(int x, int y)2025     public int getPixel(int x, int y) {
2026         checkRecycled("Can't call getPixel() on a recycled bitmap");
2027         checkHardware("unable to getPixel(), "
2028                 + "pixel access is not supported on Config#HARDWARE bitmaps");
2029         checkPixelAccess(x, y);
2030         return nativeGetPixel(mNativePtr, x, y);
2031     }
2032 
clamp(float value, @NonNull ColorSpace cs, int index)2033     private static float clamp(float value, @NonNull ColorSpace cs, int index) {
2034         return Math.max(Math.min(value, cs.getMaxValue(index)), cs.getMinValue(index));
2035     }
2036 
2037     /**
2038      * Returns the {@link Color} at the specified location. Throws an exception
2039      * if x or y are out of bounds (negative or >= to the width or height
2040      * respectively).
2041      *
2042      * @param x    The x coordinate (0...width-1) of the pixel to return
2043      * @param y    The y coordinate (0...height-1) of the pixel to return
2044      * @return     The {@link Color} at the specified coordinate
2045      * @throws IllegalArgumentException if x, y exceed the bitmap's bounds
2046      * @throws IllegalStateException if the bitmap's config is {@link Config#HARDWARE}
2047      *
2048      */
2049     @NonNull
getColor(int x, int y)2050     public Color getColor(int x, int y) {
2051         checkRecycled("Can't call getColor() on a recycled bitmap");
2052         checkHardware("unable to getColor(), "
2053                 + "pixel access is not supported on Config#HARDWARE bitmaps");
2054         checkPixelAccess(x, y);
2055 
2056         final ColorSpace cs = getColorSpace();
2057         if (cs == null || cs.equals(ColorSpace.get(ColorSpace.Named.SRGB))) {
2058             return Color.valueOf(nativeGetPixel(mNativePtr, x, y));
2059         }
2060         // The returned value is in kRGBA_F16_SkColorType, which is packed as
2061         // four half-floats, r,g,b,a.
2062         long rgba = nativeGetColor(mNativePtr, x, y);
2063         float r = Half.toFloat((short) ((rgba >>  0) & 0xffff));
2064         float g = Half.toFloat((short) ((rgba >> 16) & 0xffff));
2065         float b = Half.toFloat((short) ((rgba >> 32) & 0xffff));
2066         float a = Half.toFloat((short) ((rgba >> 48) & 0xffff));
2067 
2068         // Skia may draw outside of the numerical range of the colorSpace.
2069         // Clamp to get an expected value.
2070         return Color.valueOf(clamp(r, cs, 0), clamp(g, cs, 1), clamp(b, cs, 2), a, cs);
2071     }
2072 
2073     /**
2074      * Returns in pixels[] a copy of the data in the bitmap. Each value is
2075      * a packed int representing a {@link Color}. The stride parameter allows
2076      * the caller to allow for gaps in the returned pixels array between
2077      * rows. For normal packed results, just pass width for the stride value.
2078      * The returned colors are non-premultiplied ARGB values in the
2079      * {@link ColorSpace.Named#SRGB sRGB} color space.
2080      *
2081      * @param pixels   The array to receive the bitmap's colors
2082      * @param offset   The first index to write into pixels[]
2083      * @param stride   The number of entries in pixels[] to skip between
2084      *                 rows (must be >= bitmap's width). Can be negative.
2085      * @param x        The x coordinate of the first pixel to read from
2086      *                 the bitmap
2087      * @param y        The y coordinate of the first pixel to read from
2088      *                 the bitmap
2089      * @param width    The number of pixels to read from each row
2090      * @param height   The number of rows to read
2091      *
2092      * @throws IllegalArgumentException if x, y, width, height exceed the
2093      *         bounds of the bitmap, or if abs(stride) < width.
2094      * @throws ArrayIndexOutOfBoundsException if the pixels array is too small
2095      *         to receive the specified number of pixels.
2096      * @throws IllegalStateException if the bitmap's config is {@link Config#HARDWARE}
2097      */
getPixels(@onNull @olorInt int[] pixels, int offset, int stride, int x, int y, int width, int height)2098     public void getPixels(@NonNull @ColorInt int[] pixels, int offset, int stride,
2099                           int x, int y, int width, int height) {
2100         checkRecycled("Can't call getPixels() on a recycled bitmap");
2101         checkHardware("unable to getPixels(), "
2102                 + "pixel access is not supported on Config#HARDWARE bitmaps");
2103         if (width == 0 || height == 0) {
2104             return; // nothing to do
2105         }
2106         checkPixelsAccess(x, y, width, height, offset, stride, pixels);
2107         nativeGetPixels(mNativePtr, pixels, offset, stride,
2108                         x, y, width, height);
2109     }
2110 
2111     /**
2112      * Shared code to check for illegal arguments passed to getPixel()
2113      * or setPixel()
2114      *
2115      * @param x x coordinate of the pixel
2116      * @param y y coordinate of the pixel
2117      */
checkPixelAccess(int x, int y)2118     private void checkPixelAccess(int x, int y) {
2119         checkXYSign(x, y);
2120         if (x >= getWidth()) {
2121             throw new IllegalArgumentException("x must be < bitmap.width()");
2122         }
2123         if (y >= getHeight()) {
2124             throw new IllegalArgumentException("y must be < bitmap.height()");
2125         }
2126     }
2127 
2128     /**
2129      * Shared code to check for illegal arguments passed to getPixels()
2130      * or setPixels()
2131      *
2132      * @param x left edge of the area of pixels to access
2133      * @param y top edge of the area of pixels to access
2134      * @param width width of the area of pixels to access
2135      * @param height height of the area of pixels to access
2136      * @param offset offset into pixels[] array
2137      * @param stride number of elements in pixels[] between each logical row
2138      * @param pixels array to hold the area of pixels being accessed
2139     */
checkPixelsAccess(int x, int y, int width, int height, int offset, int stride, int pixels[])2140     private void checkPixelsAccess(int x, int y, int width, int height,
2141                                    int offset, int stride, int pixels[]) {
2142         checkXYSign(x, y);
2143         if (width < 0) {
2144             throw new IllegalArgumentException("width must be >= 0");
2145         }
2146         if (height < 0) {
2147             throw new IllegalArgumentException("height must be >= 0");
2148         }
2149         if (x + width > getWidth()) {
2150             throw new IllegalArgumentException(
2151                     "x + width must be <= bitmap.width()");
2152         }
2153         if (y + height > getHeight()) {
2154             throw new IllegalArgumentException(
2155                     "y + height must be <= bitmap.height()");
2156         }
2157         if (Math.abs(stride) < width) {
2158             throw new IllegalArgumentException("abs(stride) must be >= width");
2159         }
2160         int lastScanline = offset + (height - 1) * stride;
2161         int length = pixels.length;
2162         if (offset < 0 || (offset + width > length)
2163                 || lastScanline < 0
2164                 || (lastScanline + width > length)) {
2165             throw new ArrayIndexOutOfBoundsException();
2166         }
2167     }
2168 
2169     /**
2170      * <p>Write the specified {@link Color} into the bitmap (assuming it is
2171      * mutable) at the x,y coordinate. The color must be a
2172      * non-premultiplied ARGB value in the {@link ColorSpace.Named#SRGB sRGB}
2173      * color space.</p>
2174      *
2175      * @param x     The x coordinate of the pixel to replace (0...width-1)
2176      * @param y     The y coordinate of the pixel to replace (0...height-1)
2177      * @param color The ARGB color to write into the bitmap
2178      *
2179      * @throws IllegalStateException if the bitmap is not mutable
2180      * @throws IllegalArgumentException if x, y are outside of the bitmap's
2181      *         bounds.
2182      */
setPixel(int x, int y, @ColorInt int color)2183     public void setPixel(int x, int y, @ColorInt int color) {
2184         checkRecycled("Can't call setPixel() on a recycled bitmap");
2185         if (!isMutable()) {
2186             throw new IllegalStateException();
2187         }
2188         checkPixelAccess(x, y);
2189         nativeSetPixel(mNativePtr, x, y, color);
2190     }
2191 
2192     /**
2193      * <p>Replace pixels in the bitmap with the colors in the array. Each element
2194      * in the array is a packed int representing a non-premultiplied ARGB
2195      * {@link Color} in the {@link ColorSpace.Named#SRGB sRGB} color space.</p>
2196      *
2197      * @param pixels   The colors to write to the bitmap
2198      * @param offset   The index of the first color to read from pixels[]
2199      * @param stride   The number of colors in pixels[] to skip between rows.
2200      *                 Normally this value will be the same as the width of
2201      *                 the bitmap, but it can be larger (or negative).
2202      * @param x        The x coordinate of the first pixel to write to in
2203      *                 the bitmap.
2204      * @param y        The y coordinate of the first pixel to write to in
2205      *                 the bitmap.
2206      * @param width    The number of colors to copy from pixels[] per row
2207      * @param height   The number of rows to write to the bitmap
2208      *
2209      * @throws IllegalStateException if the bitmap is not mutable
2210      * @throws IllegalArgumentException if x, y, width, height are outside of
2211      *         the bitmap's bounds.
2212      * @throws ArrayIndexOutOfBoundsException if the pixels array is too small
2213      *         to receive the specified number of pixels.
2214      */
setPixels(@onNull @olorInt int[] pixels, int offset, int stride, int x, int y, int width, int height)2215     public void setPixels(@NonNull @ColorInt int[] pixels, int offset, int stride,
2216             int x, int y, int width, int height) {
2217         checkRecycled("Can't call setPixels() on a recycled bitmap");
2218         if (!isMutable()) {
2219             throw new IllegalStateException();
2220         }
2221         if (width == 0 || height == 0) {
2222             return; // nothing to do
2223         }
2224         checkPixelsAccess(x, y, width, height, offset, stride, pixels);
2225         nativeSetPixels(mNativePtr, pixels, offset, stride,
2226                         x, y, width, height);
2227     }
2228 
2229     public static final @NonNull Parcelable.Creator<Bitmap> CREATOR
2230             = new Parcelable.Creator<Bitmap>() {
2231                 /**
2232                  * Rebuilds a bitmap previously stored with writeToParcel().
2233                  *
2234                  * @param p    Parcel object to read the bitmap from
2235                  * @return a new bitmap created from the data in the parcel
2236                  */
2237                 public Bitmap createFromParcel(Parcel p) {
2238                     Bitmap bm = nativeCreateFromParcel(p);
2239                     if (bm == null) {
2240                         throw new RuntimeException("Failed to unparcel Bitmap");
2241                     }
2242                     if (p.readBoolean()) {
2243                         bm.setGainmap(p.readTypedObject(Gainmap.CREATOR));
2244                     }
2245                     return bm;
2246                 }
2247                 public Bitmap[] newArray(int size) {
2248                     return new Bitmap[size];
2249                 }
2250             };
2251 
2252     /**
2253      * No special parcel contents.
2254      */
describeContents()2255     public int describeContents() {
2256         return 0;
2257     }
2258 
2259     /**
2260      * Write the bitmap and its pixels to the parcel. The bitmap can be
2261      * rebuilt from the parcel by calling CREATOR.createFromParcel().
2262      *
2263      * If this bitmap is {@link Config#HARDWARE}, it may be unparceled with a different pixel
2264      * format (e.g. 565, 8888), but the content will be preserved to the best quality permitted
2265      * by the final pixel format
2266      * @param p    Parcel object to write the bitmap data into
2267      */
writeToParcel(@onNull Parcel p, int flags)2268     public void writeToParcel(@NonNull Parcel p, int flags) {
2269         checkRecycled("Can't parcel a recycled bitmap");
2270         noteHardwareBitmapSlowCall();
2271         if (!nativeWriteToParcel(mNativePtr, mDensity, p)) {
2272             throw new RuntimeException("native writeToParcel failed");
2273         }
2274         if (hasGainmap()) {
2275             p.writeBoolean(true);
2276             p.writeTypedObject(mGainmap, flags);
2277         } else {
2278             p.writeBoolean(false);
2279         }
2280     }
2281 
2282     /**
2283      * Returns a new bitmap that captures the alpha values of the original.
2284      * This may be drawn with Canvas.drawBitmap(), where the color(s) will be
2285      * taken from the paint that is passed to the draw call.
2286      *
2287      * @return new bitmap containing the alpha channel of the original bitmap.
2288      */
2289     @CheckResult
2290     @NonNull
extractAlpha()2291     public Bitmap extractAlpha() {
2292         return extractAlpha(null, null);
2293     }
2294 
2295     /**
2296      * Returns a new bitmap that captures the alpha values of the original.
2297      * These values may be affected by the optional Paint parameter, which
2298      * can contain its own alpha, and may also contain a MaskFilter which
2299      * could change the actual dimensions of the resulting bitmap (e.g.
2300      * a blur maskfilter might enlarge the resulting bitmap). If offsetXY
2301      * is not null, it returns the amount to offset the returned bitmap so
2302      * that it will logically align with the original. For example, if the
2303      * paint contains a blur of radius 2, then offsetXY[] would contains
2304      * -2, -2, so that drawing the alpha bitmap offset by (-2, -2) and then
2305      * drawing the original would result in the blur visually aligning with
2306      * the original.
2307      *
2308      * <p>The initial density of the returned bitmap is the same as the original's.
2309      *
2310      * @param paint Optional paint used to modify the alpha values in the
2311      *              resulting bitmap. Pass null for default behavior.
2312      * @param offsetXY Optional array that returns the X (index 0) and Y
2313      *                 (index 1) offset needed to position the returned bitmap
2314      *                 so that it visually lines up with the original.
2315      * @return new bitmap containing the (optionally modified by paint) alpha
2316      *         channel of the original bitmap. This may be drawn with
2317      *         Canvas.drawBitmap(), where the color(s) will be taken from the
2318      *         paint that is passed to the draw call.
2319      */
2320     @CheckResult
2321     @NonNull
extractAlpha(@ullable Paint paint, int[] offsetXY)2322     public Bitmap extractAlpha(@Nullable Paint paint, int[] offsetXY) {
2323         checkRecycled("Can't extractAlpha on a recycled bitmap");
2324         long nativePaint = paint != null ? paint.getNativeInstance() : 0;
2325         noteHardwareBitmapSlowCall();
2326         Bitmap bm = nativeExtractAlpha(mNativePtr, nativePaint, offsetXY);
2327         if (bm == null) {
2328             throw new RuntimeException("Failed to extractAlpha on Bitmap");
2329         }
2330         bm.mDensity = mDensity;
2331         return bm;
2332     }
2333 
2334     /**
2335      *  Given another bitmap, return true if it has the same dimensions, config,
2336      *  and pixel data as this bitmap. If any of those differ, return false.
2337      *  If other is null, return false.
2338      */
2339     @WorkerThread
sameAs(@ullable Bitmap other)2340     public boolean sameAs(@Nullable Bitmap other) {
2341         StrictMode.noteSlowCall("sameAs compares pixel data, not expected to be fast");
2342         checkRecycled("Can't call sameAs on a recycled bitmap!");
2343         if (this == other) return true;
2344         if (other == null) return false;
2345         if (other.isRecycled()) {
2346             throw new IllegalArgumentException("Can't compare to a recycled bitmap!");
2347         }
2348         return nativeSameAs(mNativePtr, other.mNativePtr);
2349     }
2350 
2351     /**
2352      * Builds caches associated with the bitmap that are used for drawing it.
2353      *
2354      * <p>Starting in {@link android.os.Build.VERSION_CODES#N}, this call initiates an asynchronous
2355      * upload to the GPU on RenderThread, if the Bitmap is not already uploaded. With Hardware
2356      * Acceleration, Bitmaps must be uploaded to the GPU in order to be rendered. This is done by
2357      * default the first time a Bitmap is drawn, but the process can take several milliseconds,
2358      * depending on the size of the Bitmap. Each time a Bitmap is modified and drawn again, it must
2359      * be re-uploaded.</p>
2360      *
2361      * <p>Calling this method in advance can save time in the first frame it's used. For example, it
2362      * is recommended to call this on an image decoding worker thread when a decoded Bitmap is about
2363      * to be displayed. It is recommended to make any pre-draw modifications to the Bitmap before
2364      * calling this method, so the cached, uploaded copy may be reused without re-uploading.</p>
2365      *
2366      * In {@link android.os.Build.VERSION_CODES#KITKAT} and below, for purgeable bitmaps, this call
2367      * would attempt to ensure that the pixels have been decoded.
2368      */
prepareToDraw()2369     public void prepareToDraw() {
2370         checkRecycled("Can't prepareToDraw on a recycled bitmap!");
2371         // Kick off an update/upload of the bitmap outside of the normal
2372         // draw path.
2373         nativePrepareToDraw(mNativePtr);
2374     }
2375 
2376     /**
2377      * @return {@link HardwareBuffer} which is internally used by hardware bitmap
2378      *
2379      * Note: the HardwareBuffer does *not* have an associated {@link ColorSpace}.
2380      * To render this object the same as its rendered with this Bitmap, you
2381      * should also call {@link #getColorSpace()}.</p>
2382      *
2383      * Must not be modified while a wrapped Bitmap is accessing it. Doing so will
2384      * result in undefined behavior.</p>
2385      *
2386      * @throws IllegalStateException if the bitmap's config is not {@link Config#HARDWARE}
2387      * or if the bitmap has been recycled.
2388      */
2389     @NonNull
getHardwareBuffer()2390     public HardwareBuffer getHardwareBuffer() {
2391         checkRecycled("Can't getHardwareBuffer from a recycled bitmap");
2392         HardwareBuffer hardwareBuffer = mHardwareBuffer == null ? null : mHardwareBuffer.get();
2393         if (hardwareBuffer == null || hardwareBuffer.isClosed()) {
2394             hardwareBuffer = nativeGetHardwareBuffer(mNativePtr);
2395             mHardwareBuffer = new WeakReference<HardwareBuffer>(hardwareBuffer);
2396         }
2397         return hardwareBuffer;
2398     }
2399 
2400     //////////// native methods
2401 
nativeCreate(int[] colors, int offset, int stride, int width, int height, int nativeConfig, boolean mutable, long nativeColorSpace)2402     private static native Bitmap nativeCreate(int[] colors, int offset,
2403                                               int stride, int width, int height,
2404                                               int nativeConfig, boolean mutable,
2405                                               long nativeColorSpace);
nativeCopy(long nativeSrcBitmap, int nativeConfig, boolean isMutable)2406     private static native Bitmap nativeCopy(long nativeSrcBitmap, int nativeConfig,
2407                                             boolean isMutable);
nativeCopyAshmem(long nativeSrcBitmap)2408     private static native Bitmap nativeCopyAshmem(long nativeSrcBitmap);
nativeCopyAshmemConfig(long nativeSrcBitmap, int nativeConfig)2409     private static native Bitmap nativeCopyAshmemConfig(long nativeSrcBitmap, int nativeConfig);
nativeGetAshmemFD(long nativeBitmap)2410     private static native int nativeGetAshmemFD(long nativeBitmap);
nativeGetNativeFinalizer()2411     private static native long nativeGetNativeFinalizer();
nativeRecycle(long nativeBitmap)2412     private static native void nativeRecycle(long nativeBitmap);
2413     @UnsupportedAppUsage
nativeReconfigure(long nativeBitmap, int width, int height, int config, boolean isPremultiplied)2414     private static native void nativeReconfigure(long nativeBitmap, int width, int height,
2415                                                  int config, boolean isPremultiplied);
2416 
nativeCompress(long nativeBitmap, int format, int quality, OutputStream stream, byte[] tempStorage)2417     private static native boolean nativeCompress(long nativeBitmap, int format,
2418                                             int quality, OutputStream stream,
2419                                             byte[] tempStorage);
nativeErase(long nativeBitmap, int color)2420     private static native void nativeErase(long nativeBitmap, int color);
nativeErase(long nativeBitmap, long colorSpacePtr, long color)2421     private static native void nativeErase(long nativeBitmap, long colorSpacePtr, long color);
nativeRowBytes(long nativeBitmap)2422     private static native int nativeRowBytes(long nativeBitmap);
nativeConfig(long nativeBitmap)2423     private static native int nativeConfig(long nativeBitmap);
2424 
nativeGetPixel(long nativeBitmap, int x, int y)2425     private static native int nativeGetPixel(long nativeBitmap, int x, int y);
nativeGetColor(long nativeBitmap, int x, int y)2426     private static native long nativeGetColor(long nativeBitmap, int x, int y);
nativeGetPixels(long nativeBitmap, int[] pixels, int offset, int stride, int x, int y, int width, int height)2427     private static native void nativeGetPixels(long nativeBitmap, int[] pixels,
2428                                                int offset, int stride, int x, int y,
2429                                                int width, int height);
2430 
nativeSetPixel(long nativeBitmap, int x, int y, int color)2431     private static native void nativeSetPixel(long nativeBitmap, int x, int y, int color);
nativeSetPixels(long nativeBitmap, int[] colors, int offset, int stride, int x, int y, int width, int height)2432     private static native void nativeSetPixels(long nativeBitmap, int[] colors,
2433                                                int offset, int stride, int x, int y,
2434                                                int width, int height);
nativeCopyPixelsToBuffer(long nativeBitmap, Buffer dst)2435     private static native void nativeCopyPixelsToBuffer(long nativeBitmap,
2436                                                         Buffer dst);
nativeCopyPixelsFromBuffer(long nativeBitmap, Buffer src)2437     private static native void nativeCopyPixelsFromBuffer(long nativeBitmap, Buffer src);
nativeGenerationId(long nativeBitmap)2438     private static native int nativeGenerationId(long nativeBitmap);
2439 
nativeCreateFromParcel(Parcel p)2440     private static native Bitmap nativeCreateFromParcel(Parcel p);
2441     // returns true on success
nativeWriteToParcel(long nativeBitmap, int density, Parcel p)2442     private static native boolean nativeWriteToParcel(long nativeBitmap,
2443                                                       int density,
2444                                                       Parcel p);
2445     // returns a new bitmap built from the native bitmap's alpha, and the paint
nativeExtractAlpha(long nativeBitmap, long nativePaint, int[] offsetXY)2446     private static native Bitmap nativeExtractAlpha(long nativeBitmap,
2447                                                     long nativePaint,
2448                                                     int[] offsetXY);
2449 
nativeHasAlpha(long nativeBitmap)2450     private static native boolean nativeHasAlpha(long nativeBitmap);
nativeIsPremultiplied(long nativeBitmap)2451     private static native boolean nativeIsPremultiplied(long nativeBitmap);
nativeSetPremultiplied(long nativeBitmap, boolean isPremul)2452     private static native void nativeSetPremultiplied(long nativeBitmap,
2453                                                       boolean isPremul);
nativeSetHasAlpha(long nativeBitmap, boolean hasAlpha, boolean requestPremul)2454     private static native void nativeSetHasAlpha(long nativeBitmap,
2455                                                  boolean hasAlpha,
2456                                                  boolean requestPremul);
nativeHasMipMap(long nativeBitmap)2457     private static native boolean nativeHasMipMap(long nativeBitmap);
nativeSetHasMipMap(long nativeBitmap, boolean hasMipMap)2458     private static native void nativeSetHasMipMap(long nativeBitmap, boolean hasMipMap);
nativeSameAs(long nativeBitmap0, long nativeBitmap1)2459     private static native boolean nativeSameAs(long nativeBitmap0, long nativeBitmap1);
nativePrepareToDraw(long nativeBitmap)2460     private static native void nativePrepareToDraw(long nativeBitmap);
nativeGetAllocationByteCount(long nativeBitmap)2461     private static native int nativeGetAllocationByteCount(long nativeBitmap);
nativeCopyPreserveInternalConfig(long nativeBitmap)2462     private static native Bitmap nativeCopyPreserveInternalConfig(long nativeBitmap);
nativeWrapHardwareBufferBitmap(HardwareBuffer buffer, long nativeColorSpace)2463     private static native Bitmap nativeWrapHardwareBufferBitmap(HardwareBuffer buffer,
2464                                                                 long nativeColorSpace);
nativeGetHardwareBuffer(long nativeBitmap)2465     private static native HardwareBuffer nativeGetHardwareBuffer(long nativeBitmap);
nativeComputeColorSpace(long nativePtr)2466     private static native ColorSpace nativeComputeColorSpace(long nativePtr);
nativeSetColorSpace(long nativePtr, long nativeColorSpace)2467     private static native void nativeSetColorSpace(long nativePtr, long nativeColorSpace);
nativeIsSRGB(long nativePtr)2468     private static native boolean nativeIsSRGB(long nativePtr);
nativeIsSRGBLinear(long nativePtr)2469     private static native boolean nativeIsSRGBLinear(long nativePtr);
2470 
nativeSetImmutable(long nativePtr)2471     private static native void nativeSetImmutable(long nativePtr);
2472 
nativeExtractGainmap(long nativePtr)2473     private static native Gainmap nativeExtractGainmap(long nativePtr);
nativeSetGainmap(long bitmapPtr, long gainmapPtr)2474     private static native void nativeSetGainmap(long bitmapPtr, long gainmapPtr);
2475 
2476     // ---------------- @CriticalNative -------------------
2477 
2478     @CriticalNative
nativeIsImmutable(long nativePtr)2479     private static native boolean nativeIsImmutable(long nativePtr);
2480 
2481     @CriticalNative
nativeIsBackedByAshmem(long nativePtr)2482     private static native boolean nativeIsBackedByAshmem(long nativePtr);
2483 
2484     @CriticalNative
nativeHasGainmap(long nativePtr)2485     private static native boolean nativeHasGainmap(long nativePtr);
2486 }
2487