1 /*
2  * Copyright (C) 2007 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 static android.graphics.BitmapFactory.Options.validate;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.compat.annotation.UnsupportedAppUsage;
24 import android.content.res.AssetManager;
25 import android.content.res.Resources;
26 import android.os.Build;
27 import android.os.Trace;
28 import android.system.OsConstants;
29 import android.util.DisplayMetrics;
30 import android.util.Log;
31 import android.util.TypedValue;
32 
33 import libcore.io.IoBridge;
34 
35 import java.io.FileDescriptor;
36 import java.io.FileInputStream;
37 import java.io.IOException;
38 import java.io.InputStream;
39 
40 /**
41  * Creates Bitmap objects from various sources, including files, streams,
42  * and byte-arrays.
43  */
44 public class BitmapFactory {
45     private static final int DECODE_BUFFER_SIZE = 16 * 1024;
46 
47     public static class Options {
48         /**
49          * Create a default Options object, which if left unchanged will give
50          * the same result from the decoder as if null were passed.
51          */
Options()52         public Options() {
53             inScaled = true;
54             inPremultiplied = true;
55         }
56 
57         /**
58          * If set, decode methods that take the Options object will attempt to
59          * reuse this bitmap when loading content. If the decode operation
60          * cannot use this bitmap, the decode method will throw an
61          * {@link java.lang.IllegalArgumentException}. The
62          * current implementation necessitates that the reused bitmap be
63          * mutable, and the resulting reused bitmap will continue to remain
64          * mutable even when decoding a resource which would normally result in
65          * an immutable bitmap.</p>
66          *
67          * <p>You should still always use the returned Bitmap of the decode
68          * method and not assume that reusing the bitmap worked, due to the
69          * constraints outlined above and failure situations that can occur.
70          * Checking whether the return value matches the value of the inBitmap
71          * set in the Options structure will indicate if the bitmap was reused,
72          * but in all cases you should use the Bitmap returned by the decoding
73          * function to ensure that you are using the bitmap that was used as the
74          * decode destination.</p>
75          *
76          * <h3>Usage with BitmapFactory</h3>
77          *
78          * <p>As of {@link android.os.Build.VERSION_CODES#KITKAT}, any
79          * mutable bitmap can be reused by {@link BitmapFactory} to decode any
80          * other bitmaps as long as the resulting {@link Bitmap#getByteCount()
81          * byte count} of the decoded bitmap is less than or equal to the {@link
82          * Bitmap#getAllocationByteCount() allocated byte count} of the reused
83          * bitmap. This can be because the intrinsic size is smaller, or its
84          * size post scaling (for density / sample size) is smaller.</p>
85          *
86          * <p class="note">Prior to {@link android.os.Build.VERSION_CODES#KITKAT}
87          * additional constraints apply: The image being decoded (whether as a
88          * resource or as a stream) must be in jpeg or png format. Only equal
89          * sized bitmaps are supported, with {@link #inSampleSize} set to 1.
90          * Additionally, the {@link android.graphics.Bitmap.Config
91          * configuration} of the reused bitmap will override the setting of
92          * {@link #inPreferredConfig}, if set.</p>
93          *
94          * <h3>Usage with BitmapRegionDecoder</h3>
95          *
96          * <p>BitmapRegionDecoder will draw its requested content into the Bitmap
97          * provided, clipping if the output content size (post scaling) is larger
98          * than the provided Bitmap. The provided Bitmap's width, height, and
99          * {@link Bitmap.Config} will not be changed.
100          *
101          * <p class="note">BitmapRegionDecoder support for {@link #inBitmap} was
102          * introduced in {@link android.os.Build.VERSION_CODES#JELLY_BEAN}. All
103          * formats supported by BitmapRegionDecoder support Bitmap reuse via
104          * {@link #inBitmap}.</p>
105          *
106          * @see Bitmap#reconfigure(int,int, android.graphics.Bitmap.Config)
107          */
108         public Bitmap inBitmap;
109 
110         /**
111          * If set, decode methods will always return a mutable Bitmap instead of
112          * an immutable one. This can be used for instance to programmatically apply
113          * effects to a Bitmap loaded through BitmapFactory.
114          * <p>Can not be set simultaneously with inPreferredConfig =
115          * {@link android.graphics.Bitmap.Config#HARDWARE},
116          * because hardware bitmaps are always immutable.
117          */
118         @SuppressWarnings({"UnusedDeclaration"}) // used in native code
119         public boolean inMutable;
120 
121         /**
122          * If set to true, the decoder will return null (no bitmap), but
123          * the <code>out...</code> fields will still be set, allowing the caller to
124          * query the bitmap without having to allocate the memory for its pixels.
125          */
126         public boolean inJustDecodeBounds;
127 
128         /**
129          * If set to a value > 1, requests the decoder to subsample the original
130          * image, returning a smaller image to save memory. The sample size is
131          * the number of pixels in either dimension that correspond to a single
132          * pixel in the decoded bitmap. For example, inSampleSize == 4 returns
133          * an image that is 1/4 the width/height of the original, and 1/16 the
134          * number of pixels. Any value <= 1 is treated the same as 1. Note: the
135          * decoder uses a final value based on powers of 2, any other value will
136          * be rounded down to the nearest power of 2.
137          */
138         public int inSampleSize;
139 
140         /**
141          * If this is non-null, the decoder will try to decode into this
142          * internal configuration. If it is null, or the request cannot be met,
143          * the decoder will try to pick the best matching config based on the
144          * system's screen depth, and characteristics of the original image such
145          * as if it has per-pixel alpha (requiring a config that also does).
146          *
147          * Image are loaded with the {@link Bitmap.Config#ARGB_8888} config by
148          * default.
149          */
150         public Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888;
151 
152         /**
153          * <p>If this is non-null, the decoder will try to decode into this
154          * color space. If it is null, or the request cannot be met,
155          * the decoder will pick either the color space embedded in the image
156          * or the color space best suited for the requested image configuration
157          * (for instance {@link ColorSpace.Named#SRGB sRGB} for
158          * {@link Bitmap.Config#ARGB_8888} configuration and
159          * {@link ColorSpace.Named#EXTENDED_SRGB EXTENDED_SRGB} for
160          * {@link Bitmap.Config#RGBA_F16}).</p>
161          *
162          * <p class="note">Only {@link ColorSpace.Model#RGB} color spaces are
163          * currently supported. An <code>IllegalArgumentException</code> will
164          * be thrown by the decode methods when setting a non-RGB color space
165          * such as {@link ColorSpace.Named#CIE_LAB Lab}.</p>
166          *
167          * <p class="note">
168          * Prior to {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE},
169          * the specified color space's transfer function must be
170          * an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}. An
171          * <code>IllegalArgumentException</code> will be thrown by the decode methods
172          * if calling {@link ColorSpace.Rgb#getTransferParameters()} on the
173          * specified color space returns null.
174          *
175          * Starting from {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE},
176          * non ICC parametric curve transfer function is allowed.
177          * E.g., {@link ColorSpace.Named#BT2020_HLG BT2020_HLG}.</p>
178          *
179          * <p>After decode, the bitmap's color space is stored in
180          * {@link #outColorSpace}.</p>
181          */
182         public ColorSpace inPreferredColorSpace = null;
183 
184         /**
185          * If true (which is the default), the resulting bitmap will have its
186          * color channels pre-multiplied by the alpha channel.
187          *
188          * <p>This should NOT be set to false for images to be directly drawn by
189          * the view system or through a {@link Canvas}. The view system and
190          * {@link Canvas} assume all drawn images are pre-multiplied to simplify
191          * draw-time blending, and will throw a RuntimeException when
192          * un-premultiplied are drawn.</p>
193          *
194          * <p>This is likely only useful if you want to manipulate raw encoded
195          * image data, e.g. with RenderScript or custom OpenGL.</p>
196          *
197          * <p>This does not affect bitmaps without an alpha channel.</p>
198          *
199          * <p>Setting this flag to false while setting {@link #inScaled} to true
200          * may result in incorrect colors.</p>
201          *
202          * @see Bitmap#hasAlpha()
203          * @see Bitmap#isPremultiplied()
204          * @see #inScaled
205          */
206         public boolean inPremultiplied;
207 
208         /**
209          * @deprecated As of {@link android.os.Build.VERSION_CODES#N}, this is
210          * ignored.
211          *
212          * In {@link android.os.Build.VERSION_CODES#M} and below, if dither is
213          * true, the decoder will attempt to dither the decoded image.
214          */
215         public boolean inDither;
216 
217         /**
218          * The pixel density to use for the bitmap.  This will always result
219          * in the returned bitmap having a density set for it (see
220          * {@link Bitmap#setDensity(int) Bitmap.setDensity(int)}).  In addition,
221          * if {@link #inScaled} is set (which it is by default} and this
222          * density does not match {@link #inTargetDensity}, then the bitmap
223          * will be scaled to the target density before being returned.
224          *
225          * <p>If this is 0,
226          * {@link BitmapFactory#decodeResource(Resources, int)},
227          * {@link BitmapFactory#decodeResource(Resources, int, android.graphics.BitmapFactory.Options)},
228          * and {@link BitmapFactory#decodeResourceStream}
229          * will fill in the density associated with the resource.  The other
230          * functions will leave it as-is and no density will be applied.
231          *
232          * @see #inTargetDensity
233          * @see #inScreenDensity
234          * @see #inScaled
235          * @see Bitmap#setDensity(int)
236          * @see android.util.DisplayMetrics#densityDpi
237          */
238         public int inDensity;
239 
240         /**
241          * The pixel density of the destination this bitmap will be drawn to.
242          * This is used in conjunction with {@link #inDensity} and
243          * {@link #inScaled} to determine if and how to scale the bitmap before
244          * returning it.
245          *
246          * <p>If this is 0,
247          * {@link BitmapFactory#decodeResource(Resources, int)},
248          * {@link BitmapFactory#decodeResource(Resources, int, android.graphics.BitmapFactory.Options)},
249          * and {@link BitmapFactory#decodeResourceStream}
250          * will fill in the density associated the Resources object's
251          * DisplayMetrics.  The other
252          * functions will leave it as-is and no scaling for density will be
253          * performed.
254          *
255          * @see #inDensity
256          * @see #inScreenDensity
257          * @see #inScaled
258          * @see android.util.DisplayMetrics#densityDpi
259          */
260         public int inTargetDensity;
261 
262         /**
263          * The pixel density of the actual screen that is being used.  This is
264          * purely for applications running in density compatibility code, where
265          * {@link #inTargetDensity} is actually the density the application
266          * sees rather than the real screen density.
267          *
268          * <p>By setting this, you
269          * allow the loading code to avoid scaling a bitmap that is currently
270          * in the screen density up/down to the compatibility density.  Instead,
271          * if {@link #inDensity} is the same as {@link #inScreenDensity}, the
272          * bitmap will be left as-is.  Anything using the resulting bitmap
273          * must also used {@link Bitmap#getScaledWidth(int)
274          * Bitmap.getScaledWidth} and {@link Bitmap#getScaledHeight
275          * Bitmap.getScaledHeight} to account for any different between the
276          * bitmap's density and the target's density.
277          *
278          * <p>This is never set automatically for the caller by
279          * {@link BitmapFactory} itself.  It must be explicitly set, since the
280          * caller must deal with the resulting bitmap in a density-aware way.
281          *
282          * @see #inDensity
283          * @see #inTargetDensity
284          * @see #inScaled
285          * @see android.util.DisplayMetrics#densityDpi
286          */
287         public int inScreenDensity;
288 
289         /**
290          * When this flag is set, if {@link #inDensity} and
291          * {@link #inTargetDensity} are not 0, the
292          * bitmap will be scaled to match {@link #inTargetDensity} when loaded,
293          * rather than relying on the graphics system scaling it each time it
294          * is drawn to a Canvas.
295          *
296          * <p>BitmapRegionDecoder ignores this flag, and will not scale output
297          * based on density. (though {@link #inSampleSize} is supported)</p>
298          *
299          * <p>This flag is turned on by default and should be turned off if you need
300          * a non-scaled version of the bitmap.  Nine-patch bitmaps ignore this
301          * flag and are always scaled.
302          *
303          * <p>If {@link #inPremultiplied} is set to false, and the image has alpha,
304          * setting this flag to true may result in incorrect colors.
305          */
306         public boolean inScaled;
307 
308         /**
309          * @deprecated As of {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this is
310          * ignored.
311          *
312          * In {@link android.os.Build.VERSION_CODES#KITKAT} and below, if this
313          * is set to true, then the resulting bitmap will allocate its
314          * pixels such that they can be purged if the system needs to reclaim
315          * memory. In that instance, when the pixels need to be accessed again
316          * (e.g. the bitmap is drawn, getPixels() is called), they will be
317          * automatically re-decoded.
318          *
319          * <p>For the re-decode to happen, the bitmap must have access to the
320          * encoded data, either by sharing a reference to the input
321          * or by making a copy of it. This distinction is controlled by
322          * inInputShareable. If this is true, then the bitmap may keep a shallow
323          * reference to the input. If this is false, then the bitmap will
324          * explicitly make a copy of the input data, and keep that. Even if
325          * sharing is allowed, the implementation may still decide to make a
326          * deep copy of the input data.</p>
327          *
328          * <p>While inPurgeable can help avoid big Dalvik heap allocations (from
329          * API level 11 onward), it sacrifices performance predictability since any
330          * image that the view system tries to draw may incur a decode delay which
331          * can lead to dropped frames. Therefore, most apps should avoid using
332          * inPurgeable to allow for a fast and fluid UI. To minimize Dalvik heap
333          * allocations use the {@link #inBitmap} flag instead.</p>
334          *
335          * <p class="note"><strong>Note:</strong> This flag is ignored when used
336          * with {@link #decodeResource(Resources, int,
337          * android.graphics.BitmapFactory.Options)} or {@link #decodeFile(String,
338          * android.graphics.BitmapFactory.Options)}.</p>
339          */
340         @Deprecated
341         public boolean inPurgeable;
342 
343         /**
344          * @deprecated As of {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this is
345          * ignored.
346          *
347          * In {@link android.os.Build.VERSION_CODES#KITKAT} and below, this
348          * field works in conjunction with inPurgeable. If inPurgeable is false,
349          * then this field is ignored. If inPurgeable is true, then this field
350          * determines whether the bitmap can share a reference to the input
351          * data (inputstream, array, etc.) or if it must make a deep copy.
352          */
353         @Deprecated
354         public boolean inInputShareable;
355 
356         /**
357          * @deprecated As of {@link android.os.Build.VERSION_CODES#N}, this is
358          * ignored.  The output will always be high quality.
359          *
360          * In {@link android.os.Build.VERSION_CODES#M} and below, if
361          * inPreferQualityOverSpeed is set to true, the decoder will try to
362          * decode the reconstructed image to a higher quality even at the
363          * expense of the decoding speed. Currently the field only affects JPEG
364          * decode, in the case of which a more accurate, but slightly slower,
365          * IDCT method will be used instead.
366          */
367         @Deprecated
368         public boolean inPreferQualityOverSpeed;
369 
370         /**
371          * The resulting width of the bitmap. If {@link #inJustDecodeBounds} is
372          * set to false, this will be width of the output bitmap after any
373          * scaling is applied. If true, it will be the width of the input image
374          * without any accounting for scaling.
375          *
376          * <p>outWidth will be set to -1 if there is an error trying to decode.</p>
377          */
378         public int outWidth;
379 
380         /**
381          * The resulting height of the bitmap. If {@link #inJustDecodeBounds} is
382          * set to false, this will be height of the output bitmap after any
383          * scaling is applied. If true, it will be the height of the input image
384          * without any accounting for scaling.
385          *
386          * <p>outHeight will be set to -1 if there is an error trying to decode.</p>
387          */
388         public int outHeight;
389 
390         /**
391          * If known, this string is set to the mimetype of the decoded image.
392          * If not known, or there is an error, it is set to null.
393          */
394         public String outMimeType;
395 
396         /**
397          * If known, the config the decoded bitmap will have.
398          * If not known, or there is an error, it is set to null.
399          */
400         public Bitmap.Config outConfig;
401 
402         /**
403          * If known, the color space the decoded bitmap will have. Note that the
404          * output color space is not guaranteed to be the color space the bitmap
405          * is encoded with. If not known (when the config is
406          * {@link Bitmap.Config#ALPHA_8} for instance), or there is an error,
407          * it is set to null.
408          */
409         public ColorSpace outColorSpace;
410 
411         /**
412          * Temp storage to use for decoding.  Suggest 16K or so.
413          */
414         public byte[] inTempStorage;
415 
416         /**
417          * @deprecated As of {@link android.os.Build.VERSION_CODES#N}, see
418          * comments on {@link #requestCancelDecode()}.
419          *
420          * Flag to indicate that cancel has been called on this object.  This
421          * is useful if there's an intermediary that wants to first decode the
422          * bounds and then decode the image.  In that case the intermediary
423          * can check, inbetween the bounds decode and the image decode, to see
424          * if the operation is canceled.
425          */
426         @Deprecated
427         public boolean mCancel;
428 
429         /**
430          *  @deprecated As of {@link android.os.Build.VERSION_CODES#N}, this
431          *  will not affect the decode, though it will still set mCancel.
432          *
433          *  In {@link android.os.Build.VERSION_CODES#M} and below, if this can
434          *  be called from another thread while this options object is inside
435          *  a decode... call. Calling this will notify the decoder that it
436          *  should cancel its operation. This is not guaranteed to cancel the
437          *  decode, but if it does, the decoder... operation will return null,
438          *  or if inJustDecodeBounds is true, will set outWidth/outHeight
439          *  to -1
440          */
441         @Deprecated
requestCancelDecode()442         public void requestCancelDecode() {
443             mCancel = true;
444         }
445 
validate(Options opts)446         static void validate(Options opts) {
447             if (opts == null) return;
448 
449             if (opts.inBitmap != null) {
450                 if (opts.inBitmap.getConfig() == Bitmap.Config.HARDWARE) {
451                     throw new IllegalArgumentException(
452                             "Bitmaps with Config.HARDWARE are always immutable");
453                 }
454                 if (opts.inBitmap.isRecycled()) {
455                     throw new IllegalArgumentException(
456                             "Cannot reuse a recycled Bitmap");
457                 }
458             }
459 
460             if (opts.inMutable && opts.inPreferredConfig == Bitmap.Config.HARDWARE) {
461                 throw new IllegalArgumentException("Bitmaps with Config.HARDWARE cannot be " +
462                         "decoded into - they are immutable");
463             }
464 
465             if (opts.inPreferredColorSpace != null) {
466                 if (!(opts.inPreferredColorSpace instanceof ColorSpace.Rgb)) {
467                     throw new IllegalArgumentException("The destination color space must use the " +
468                             "RGB color model");
469                 }
470                 if (!opts.inPreferredColorSpace.equals(ColorSpace.get(ColorSpace.Named.BT2020_HLG))
471                         && !opts.inPreferredColorSpace.equals(
472                             ColorSpace.get(ColorSpace.Named.BT2020_PQ))
473                         && ((ColorSpace.Rgb) opts.inPreferredColorSpace)
474                             .getTransferParameters() == null) {
475                     throw new IllegalArgumentException("The destination color space must use an " +
476                             "ICC parametric transfer function");
477                 }
478             }
479         }
480 
481         /**
482          *  Helper for passing inBitmap's native pointer to native.
483          */
nativeInBitmap(Options opts)484         static long nativeInBitmap(Options opts) {
485             if (opts == null || opts.inBitmap == null) {
486                 return 0;
487             }
488             // Clear out the gainmap since we don't attempt to reuse it and don't want to
489             // accidentally keep it on the re-used bitmap
490             opts.inBitmap.setGainmap(null);
491             return opts.inBitmap.getNativeInstance();
492         }
493 
494         /**
495          *  Helper for passing SkColorSpace pointer to native.
496          *
497          *  @throws IllegalArgumentException if the ColorSpace is not Rgb or does
498          *          not have TransferParameters.
499          */
nativeColorSpace(Options opts)500         static long nativeColorSpace(Options opts) {
501             if (opts == null || opts.inPreferredColorSpace == null) {
502                 return 0;
503             }
504 
505             return opts.inPreferredColorSpace.getNativeInstance();
506         }
507 
508     }
509 
510     /**
511      * Decode a file path into a bitmap. If the specified file name is null,
512      * or cannot be decoded into a bitmap, the function returns null.
513      *
514      * @param pathName complete path name for the file to be decoded.
515      * @param opts null-ok; Options that control downsampling and whether the
516      *             image should be completely decoded, or just is size returned.
517      * @return The decoded bitmap, or null if the image data could not be
518      *         decoded, or, if opts is non-null, if opts requested only the
519      *         size be returned (in opts.outWidth and opts.outHeight)
520      * @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
521      *         is {@link android.graphics.Bitmap.Config#HARDWARE}
522      *         and {@link BitmapFactory.Options#inMutable} is set, if the specified color space
523      *         is not {@link ColorSpace.Model#RGB RGB}, or if the specified color space's transfer
524      *         function is not an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}
525      */
decodeFile(String pathName, Options opts)526     public static Bitmap decodeFile(String pathName, Options opts) {
527         validate(opts);
528         Bitmap bm = null;
529         FileDescriptor fd = null;
530         try {
531             fd = IoBridge.open(pathName, OsConstants.O_RDONLY);
532             bm = decodeFileDescriptor(fd, null, opts);
533         } catch (Exception e) {
534             /*  do nothing.
535                 If the exception happened on open, bm will be null.
536             */
537             Log.e("BitmapFactory", "Unable to decode file: " + e);
538         } finally {
539             if (fd != null) {
540                 try {
541                     IoBridge.closeAndSignalBlockedThreads(fd);
542                 } catch (IOException e) {
543                     // do nothing here
544                 }
545             }
546         }
547         return bm;
548     }
549 
550     /**
551      * Decode a file path into a bitmap. If the specified file name is null,
552      * or cannot be decoded into a bitmap, the function returns null.
553      *
554      * @param pathName complete path name for the file to be decoded.
555      * @return the resulting decoded bitmap, or null if it could not be decoded.
556      */
decodeFile(String pathName)557     public static Bitmap decodeFile(String pathName) {
558         return decodeFile(pathName, null);
559     }
560 
561     /**
562      * Decode a new Bitmap from an InputStream. This InputStream was obtained from
563      * resources, which we pass to be able to scale the bitmap accordingly.
564      * @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
565      *         is {@link android.graphics.Bitmap.Config#HARDWARE}
566      *         and {@link BitmapFactory.Options#inMutable} is set, if the specified color space
567      *         is not {@link ColorSpace.Model#RGB RGB}, or if the specified color space's transfer
568      *         function is not an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}
569      */
570     @Nullable
decodeResourceStream(@ullable Resources res, @Nullable TypedValue value, @Nullable InputStream is, @Nullable Rect pad, @Nullable Options opts)571     public static Bitmap decodeResourceStream(@Nullable Resources res, @Nullable TypedValue value,
572             @Nullable InputStream is, @Nullable Rect pad, @Nullable Options opts) {
573         validate(opts);
574         if (opts == null) {
575             opts = new Options();
576         }
577 
578         if (opts.inDensity == 0 && value != null) {
579             final int density = value.density;
580             if (density == TypedValue.DENSITY_DEFAULT) {
581                 opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;
582             } else if (density != TypedValue.DENSITY_NONE) {
583                 opts.inDensity = density;
584             }
585         }
586 
587         if (opts.inTargetDensity == 0 && res != null) {
588             opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
589         }
590 
591         return decodeStream(is, pad, opts);
592     }
593 
594     /**
595      * Synonym for opening the given resource and calling
596      * {@link #decodeResourceStream}.
597      *
598      * @param res   The resources object containing the image data
599      * @param id The resource id of the image data
600      * @param opts null-ok; Options that control downsampling and whether the
601      *             image should be completely decoded, or just is size returned.
602      * @return The decoded bitmap, or null if the image data could not be
603      *         decoded, or, if opts is non-null, if opts requested only the
604      *         size be returned (in opts.outWidth and opts.outHeight)
605      * @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
606      *         is {@link android.graphics.Bitmap.Config#HARDWARE}
607      *         and {@link BitmapFactory.Options#inMutable} is set, if the specified color space
608      *         is not {@link ColorSpace.Model#RGB RGB}, or if the specified color space's transfer
609      *         function is not an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}
610      */
decodeResource(Resources res, int id, Options opts)611     public static Bitmap decodeResource(Resources res, int id, Options opts) {
612         validate(opts);
613         Bitmap bm = null;
614         InputStream is = null;
615 
616         try {
617             final TypedValue value = new TypedValue();
618             is = res.openRawResource(id, value);
619 
620             bm = decodeResourceStream(res, value, is, null, opts);
621         } catch (Exception e) {
622             /*  do nothing.
623                 If the exception happened on open, bm will be null.
624                 If it happened on close, bm is still valid.
625             */
626         } finally {
627             try {
628                 if (is != null) is.close();
629             } catch (IOException e) {
630                 // Ignore
631             }
632         }
633 
634         if (bm == null && opts != null && opts.inBitmap != null) {
635             throw new IllegalArgumentException("Problem decoding into existing bitmap");
636         }
637 
638         return bm;
639     }
640 
641     /**
642      * Synonym for {@link #decodeResource(Resources, int, android.graphics.BitmapFactory.Options)}
643      * with null Options.
644      *
645      * @param res The resources object containing the image data
646      * @param id The resource id of the image data
647      * @return The decoded bitmap, or null if the image could not be decoded.
648      */
decodeResource(Resources res, int id)649     public static Bitmap decodeResource(Resources res, int id) {
650         return decodeResource(res, id, null);
651     }
652 
653     /**
654      * Decode an immutable bitmap from the specified byte array.
655      *
656      * @param data byte array of compressed image data
657      * @param offset offset into imageData for where the decoder should begin
658      *               parsing.
659      * @param length the number of bytes, beginning at offset, to parse
660      * @param opts null-ok; Options that control downsampling and whether the
661      *             image should be completely decoded, or just is size returned.
662      * @return The decoded bitmap, or null if the image data could not be
663      *         decoded, or, if opts is non-null, if opts requested only the
664      *         size be returned (in opts.outWidth and opts.outHeight)
665      * @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
666      *         is {@link android.graphics.Bitmap.Config#HARDWARE}
667      *         and {@link BitmapFactory.Options#inMutable} is set, if the specified color space
668      *         is not {@link ColorSpace.Model#RGB RGB}, or if the specified color space's transfer
669      *         function is not an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}
670      */
decodeByteArray(byte[] data, int offset, int length, Options opts)671     public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts) {
672         if ((offset | length) < 0 || data.length < offset + length) {
673             throw new ArrayIndexOutOfBoundsException();
674         }
675         validate(opts);
676 
677         Bitmap bm;
678 
679         Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "decodeBitmap");
680         try {
681             bm = nativeDecodeByteArray(data, offset, length, opts,
682                     Options.nativeInBitmap(opts),
683                     Options.nativeColorSpace(opts));
684 
685             if (bm == null && opts != null && opts.inBitmap != null) {
686                 throw new IllegalArgumentException("Problem decoding into existing bitmap");
687             }
688             setDensityFromOptions(bm, opts);
689         } finally {
690             Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
691         }
692 
693         return bm;
694     }
695 
696     /**
697      * Decode an immutable bitmap from the specified byte array.
698      *
699      * @param data byte array of compressed image data
700      * @param offset offset into imageData for where the decoder should begin
701      *               parsing.
702      * @param length the number of bytes, beginning at offset, to parse
703      * @return The decoded bitmap, or null if the image could not be decoded.
704      */
decodeByteArray(byte[] data, int offset, int length)705     public static Bitmap decodeByteArray(byte[] data, int offset, int length) {
706         return decodeByteArray(data, offset, length, null);
707     }
708 
709     /**
710      * Set the newly decoded bitmap's density based on the Options.
711      */
setDensityFromOptions(Bitmap outputBitmap, Options opts)712     private static void setDensityFromOptions(Bitmap outputBitmap, Options opts) {
713         if (outputBitmap == null || opts == null) return;
714 
715         final int density = opts.inDensity;
716         if (density != 0) {
717             outputBitmap.setDensity(density);
718             final int targetDensity = opts.inTargetDensity;
719             if (targetDensity == 0 || density == targetDensity || density == opts.inScreenDensity) {
720                 return;
721             }
722 
723             byte[] np = outputBitmap.getNinePatchChunk();
724             final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np);
725             if (opts.inScaled || isNinePatch) {
726                 outputBitmap.setDensity(targetDensity);
727             }
728         } else if (opts.inBitmap != null) {
729             // bitmap was reused, ensure density is reset
730             outputBitmap.setDensity(Bitmap.getDefaultDensity());
731         }
732     }
733 
734     /**
735      * Decode an input stream into a bitmap. If the input stream is null, or
736      * cannot be used to decode a bitmap, the function returns null.
737      * The stream's position will be where ever it was after the encoded data
738      * was read.
739      *
740      * @param is The input stream that holds the raw data to be decoded into a
741      *           bitmap.
742      * @param outPadding If not null, return the padding rect for the bitmap if
743      *                   it exists, otherwise set padding to [-1,-1,-1,-1]. If
744      *                   no bitmap is returned (null) then padding is
745      *                   unchanged.
746      * @param opts null-ok; Options that control downsampling and whether the
747      *             image should be completely decoded, or just is size returned.
748      * @return The decoded bitmap, or null if the image data could not be
749      *         decoded, or, if opts is non-null, if opts requested only the
750      *         size be returned (in opts.outWidth and opts.outHeight)
751      * @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
752      *         is {@link android.graphics.Bitmap.Config#HARDWARE}
753      *         and {@link BitmapFactory.Options#inMutable} is set, if the specified color space
754      *         is not {@link ColorSpace.Model#RGB RGB}, or if the specified color space's transfer
755      *         function is not an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}
756      *
757      * <p class="note">Prior to {@link android.os.Build.VERSION_CODES#KITKAT},
758      * if {@link InputStream#markSupported is.markSupported()} returns true,
759      * <code>is.mark(1024)</code> would be called. As of
760      * {@link android.os.Build.VERSION_CODES#KITKAT}, this is no longer the case.</p>
761      */
762     @Nullable
decodeStream(@ullable InputStream is, @Nullable Rect outPadding, @Nullable Options opts)763     public static Bitmap decodeStream(@Nullable InputStream is, @Nullable Rect outPadding,
764             @Nullable Options opts) {
765         // we don't throw in this case, thus allowing the caller to only check
766         // the cache, and not force the image to be decoded.
767         if (is == null) {
768             return null;
769         }
770         validate(opts);
771 
772         Bitmap bm = null;
773 
774         Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "decodeBitmap");
775         try {
776             if (is instanceof AssetManager.AssetInputStream) {
777                 final long asset = ((AssetManager.AssetInputStream) is).getNativeAsset();
778                 bm = nativeDecodeAsset(asset, outPadding, opts, Options.nativeInBitmap(opts),
779                     Options.nativeColorSpace(opts));
780             } else {
781                 bm = decodeStreamInternal(is, outPadding, opts);
782             }
783 
784             if (bm == null && opts != null && opts.inBitmap != null) {
785                 throw new IllegalArgumentException("Problem decoding into existing bitmap");
786             }
787 
788             setDensityFromOptions(bm, opts);
789         } finally {
790             Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
791         }
792 
793         return bm;
794     }
795 
796     /**
797      * Private helper function for decoding an InputStream natively. Buffers the input enough to
798      * do a rewind as needed, and supplies temporary storage if necessary. is MUST NOT be null.
799      */
decodeStreamInternal(@onNull InputStream is, @Nullable Rect outPadding, @Nullable Options opts)800     private static Bitmap decodeStreamInternal(@NonNull InputStream is,
801             @Nullable Rect outPadding, @Nullable Options opts) {
802         // ASSERT(is != null);
803         byte [] tempStorage = null;
804         if (opts != null) tempStorage = opts.inTempStorage;
805         if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE];
806         return nativeDecodeStream(is, tempStorage, outPadding, opts,
807                 Options.nativeInBitmap(opts),
808                 Options.nativeColorSpace(opts));
809     }
810 
811     /**
812      * Decode an input stream into a bitmap. If the input stream is null, or
813      * cannot be used to decode a bitmap, the function returns null.
814      * The stream's position will be where ever it was after the encoded data
815      * was read.
816      *
817      * @param is The input stream that holds the raw data to be decoded into a
818      *           bitmap.
819      * @return The decoded bitmap, or null if the image data could not be decoded.
820      */
decodeStream(InputStream is)821     public static Bitmap decodeStream(InputStream is) {
822         return decodeStream(is, null, null);
823     }
824 
825     /**
826      * Decode a bitmap from the file descriptor. If the bitmap cannot be decoded
827      * return null. The position within the descriptor will not be changed when
828      * this returns, so the descriptor can be used again as-is.
829      *
830      * @param fd The file descriptor containing the bitmap data to decode
831      * @param outPadding If not null, return the padding rect for the bitmap if
832      *                   it exists, otherwise set padding to [-1,-1,-1,-1]. If
833      *                   no bitmap is returned (null) then padding is
834      *                   unchanged.
835      * @param opts null-ok; Options that control downsampling and whether the
836      *             image should be completely decoded, or just its size returned.
837      * @return the decoded bitmap, or null
838      * @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
839      *         is {@link android.graphics.Bitmap.Config#HARDWARE}
840      *         and {@link BitmapFactory.Options#inMutable} is set, if the specified color space
841      *         is not {@link ColorSpace.Model#RGB RGB}, or if the specified color space's transfer
842      *         function is not an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}
843      */
decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts)844     public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
845         validate(opts);
846         Bitmap bm;
847 
848         Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "decodeFileDescriptor");
849         try {
850             if (nativeIsSeekable(fd)) {
851                 bm = nativeDecodeFileDescriptor(fd, outPadding, opts,
852                         Options.nativeInBitmap(opts),
853                         Options.nativeColorSpace(opts));
854             } else {
855                 FileInputStream fis = new FileInputStream(fd);
856                 try {
857                     bm = decodeStreamInternal(fis, outPadding, opts);
858                 } finally {
859                     try {
860                         fis.close();
861                     } catch (Throwable t) {/* ignore */}
862                 }
863             }
864 
865             if (bm == null && opts != null && opts.inBitmap != null) {
866                 throw new IllegalArgumentException("Problem decoding into existing bitmap");
867             }
868 
869             setDensityFromOptions(bm, opts);
870         } finally {
871             Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
872         }
873         return bm;
874     }
875 
876     /**
877      * Decode a bitmap from the file descriptor. If the bitmap cannot be decoded
878      * return null. The position within the descriptor will not be changed when
879      * this returns, so the descriptor can be used again as is.
880      *
881      * @param fd The file descriptor containing the bitmap data to decode
882      * @return the decoded bitmap, or null
883      */
decodeFileDescriptor(FileDescriptor fd)884     public static Bitmap decodeFileDescriptor(FileDescriptor fd) {
885         return decodeFileDescriptor(fd, null, null);
886     }
887 
888     @UnsupportedAppUsage
nativeDecodeStream(InputStream is, byte[] storage, Rect padding, Options opts, long inBitmapHandle, long colorSpaceHandle)889     private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,
890             Rect padding, Options opts, long inBitmapHandle, long colorSpaceHandle);
891     @UnsupportedAppUsage
nativeDecodeFileDescriptor(FileDescriptor fd, Rect padding, Options opts, long inBitmapHandle, long colorSpaceHandle)892     private static native Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,
893             Rect padding, Options opts, long inBitmapHandle, long colorSpaceHandle);
894     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
nativeDecodeAsset(long nativeAsset, Rect padding, Options opts, long inBitmapHandle, long colorSpaceHandle)895     private static native Bitmap nativeDecodeAsset(long nativeAsset, Rect padding, Options opts,
896             long inBitmapHandle, long colorSpaceHandle);
897     @UnsupportedAppUsage
nativeDecodeByteArray(byte[] data, int offset, int length, Options opts, long inBitmapHandle, long colorSpaceHandle)898     private static native Bitmap nativeDecodeByteArray(byte[] data, int offset,
899             int length, Options opts, long inBitmapHandle, long colorSpaceHandle);
nativeIsSeekable(FileDescriptor fd)900     private static native boolean nativeIsSeekable(FileDescriptor fd);
901 }
902