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