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