BitmapFactory.java revision 37f74cad46c6f1799aec3c52e8f47598237f43d4
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
17package android.graphics;
18
19import android.content.res.AssetManager;
20import android.content.res.Resources;
21import android.util.DisplayMetrics;
22import android.util.TypedValue;
23
24import java.io.BufferedInputStream;
25import java.io.FileDescriptor;
26import java.io.FileInputStream;
27import java.io.IOException;
28import java.io.InputStream;
29
30/**
31 * Creates Bitmap objects from various sources, including files, streams,
32 * and byte-arrays.
33 */
34public class BitmapFactory {
35    public static class Options {
36        /**
37         * Create a default Options object, which if left unchanged will give
38         * the same result from the decoder as if null were passed.
39         */
40        public Options() {
41            inDither = false;
42            inScaled = true;
43        }
44
45        /**
46         * If set, decode methods that take the Options object will attempt to
47         * reuse this bitmap when loading content. This is a hint to the decoder
48         * only, and the decoder may choose to create a new Bitmap instead. The
49         * current implementation necessitates that the reused bitmap be of the
50         * same size as the source content and in jpeg format (whether as a
51         * resource or as a stream). The {@link android.graphics.Bitmap.Config
52         * configuration} of the reused bitmap will override the setting of
53         * {@link #inPreferredConfig}, if set.
54         *
55         * <p>You should still always use the returned Bitmap of the decode
56         * method and not assume that reusing the bitmap worked, due to the
57         * constraints outlined above and failure situations that can occur.
58         * Checking whether the return value matches the value of the inBitmap
59         * set in the Options structure is a way to see if the bitmap was reused,
60         * but in all cases you should use the returned Bitmap to make sure
61         * that you are using the bitmap that was used as the decode destination.</p>
62         */
63        public Bitmap inBitmap;
64
65        /**
66         * If set to true, the decoder will return null (no bitmap), but
67         * the out... fields will still be set, allowing the caller to query
68         * the bitmap without having to allocate the memory for its pixels.
69         */
70        public boolean inJustDecodeBounds;
71
72        /**
73         * If set to a value > 1, requests the decoder to subsample the original
74         * image, returning a smaller image to save memory. The sample size is
75         * the number of pixels in either dimension that correspond to a single
76         * pixel in the decoded bitmap. For example, inSampleSize == 4 returns
77         * an image that is 1/4 the width/height of the original, and 1/16 the
78         * number of pixels. Any value <= 1 is treated the same as 1. Note: the
79         * decoder will try to fulfill this request, but the resulting bitmap
80         * may have different dimensions that precisely what has been requested.
81         * Also, powers of 2 are often faster/easier for the decoder to honor.
82         */
83        public int inSampleSize;
84
85        /**
86         * If this is non-null, the decoder will try to decode into this
87         * internal configuration. If it is null, or the request cannot be met,
88         * the decoder will try to pick the best matching config based on the
89         * system's screen depth, and characteristics of the original image such
90         * as if it has per-pixel alpha (requiring a config that also does).
91         *
92         * Image are loaded with the {@link Bitmap.Config#ARGB_8888} config by
93         * default.
94         */
95        public Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888;
96
97        /**
98         * If dither is true, the decoder will attempt to dither the decoded
99         * image.
100         */
101        public boolean inDither;
102
103        /**
104         * The pixel density to use for the bitmap.  This will always result
105         * in the returned bitmap having a density set for it (see
106         * {@link Bitmap#setDensity(int) Bitmap.setDensity(int)}).  In addition,
107         * if {@link #inScaled} is set (which it is by default} and this
108         * density does not match {@link #inTargetDensity}, then the bitmap
109         * will be scaled to the target density before being returned.
110         *
111         * <p>If this is 0,
112         * {@link BitmapFactory#decodeResource(Resources, int)},
113         * {@link BitmapFactory#decodeResource(Resources, int, android.graphics.BitmapFactory.Options)},
114         * and {@link BitmapFactory#decodeResourceStream}
115         * will fill in the density associated with the resource.  The other
116         * functions will leave it as-is and no density will be applied.
117         *
118         * @see #inTargetDensity
119         * @see #inScreenDensity
120         * @see #inScaled
121         * @see Bitmap#setDensity(int)
122         * @see android.util.DisplayMetrics#densityDpi
123         */
124        public int inDensity;
125
126        /**
127         * The pixel density of the destination this bitmap will be drawn to.
128         * This is used in conjunction with {@link #inDensity} and
129         * {@link #inScaled} to determine if and how to scale the bitmap before
130         * returning it.
131         *
132         * <p>If this is 0,
133         * {@link BitmapFactory#decodeResource(Resources, int)},
134         * {@link BitmapFactory#decodeResource(Resources, int, android.graphics.BitmapFactory.Options)},
135         * and {@link BitmapFactory#decodeResourceStream}
136         * will fill in the density associated the Resources object's
137         * DisplayMetrics.  The other
138         * functions will leave it as-is and no scaling for density will be
139         * performed.
140         *
141         * @see #inDensity
142         * @see #inScreenDensity
143         * @see #inScaled
144         * @see android.util.DisplayMetrics#densityDpi
145         */
146        public int inTargetDensity;
147
148        /**
149         * The pixel density of the actual screen that is being used.  This is
150         * purely for applications running in density compatibility code, where
151         * {@link #inTargetDensity} is actually the density the application
152         * sees rather than the real screen density.
153         *
154         * <p>By setting this, you
155         * allow the loading code to avoid scaling a bitmap that is currently
156         * in the screen density up/down to the compatibility density.  Instead,
157         * if {@link #inDensity} is the same as {@link #inScreenDensity}, the
158         * bitmap will be left as-is.  Anything using the resulting bitmap
159         * must also used {@link Bitmap#getScaledWidth(int)
160         * Bitmap.getScaledWidth} and {@link Bitmap#getScaledHeight
161         * Bitmap.getScaledHeight} to account for any different between the
162         * bitmap's density and the target's density.
163         *
164         * <p>This is never set automatically for the caller by
165         * {@link BitmapFactory} itself.  It must be explicitly set, since the
166         * caller must deal with the resulting bitmap in a density-aware way.
167         *
168         * @see #inDensity
169         * @see #inTargetDensity
170         * @see #inScaled
171         * @see android.util.DisplayMetrics#densityDpi
172         */
173        public int inScreenDensity;
174
175        /**
176         * When this flag is set, if {@link #inDensity} and
177         * {@link #inTargetDensity} are not 0, the
178         * bitmap will be scaled to match {@link #inTargetDensity} when loaded,
179         * rather than relying on the graphics system scaling it each time it
180         * is drawn to a Canvas.
181         *
182         * <p>This flag is turned on by default and should be turned off if you need
183         * a non-scaled version of the bitmap.  Nine-patch bitmaps ignore this
184         * flag and are always scaled.
185         */
186        public boolean inScaled;
187
188        /**
189         * If this is set to true, then the resulting bitmap will allocate its
190         * pixels such that they can be purged if the system needs to reclaim
191         * memory. In that instance, when the pixels need to be accessed again
192         * (e.g. the bitmap is drawn, getPixels() is called), they will be
193         * automatically re-decoded.
194         *
195         * For the re-decode to happen, the bitmap must have access to the
196         * encoded data, either by sharing a reference to the input
197         * or by making a copy of it. This distinction is controlled by
198         * inInputShareable. If this is true, then the bitmap may keep a shallow
199         * reference to the input. If this is false, then the bitmap will
200         * explicitly make a copy of the input data, and keep that. Even if
201         * sharing is allowed, the implementation may still decide to make a
202         * deep copy of the input data.
203         */
204        public boolean inPurgeable;
205
206        /**
207         * This field works in conjuction with inPurgeable. If inPurgeable is
208         * false, then this field is ignored. If inPurgeable is true, then this
209         * field determines whether the bitmap can share a reference to the
210         * input data (inputstream, array, etc.) or if it must make a deep copy.
211         */
212        public boolean inInputShareable;
213
214        /**
215         * Normally bitmap allocations count against the dalvik heap, which
216         * means they help trigger GCs when a lot have been allocated. However,
217         * in rare cases, the caller may want to allocate the bitmap outside of
218         * that heap. To request that, set inNativeAlloc to true. In these
219         * rare instances, it is solely up to the caller to ensure that OOM is
220         * managed explicitly by calling bitmap.recycle() as soon as such a
221         * bitmap is no longer needed.
222         *
223         * @hide pending API council approval
224         */
225        public boolean inNativeAlloc;
226
227        /**
228         * If inPreferQualityOverSpeed is set to true, the decoder will try to
229         * decode the reconstructed image to a higher quality even at the
230         * expense of the decoding speed. Currently the field only affects JPEG
231         * decode, in the case of which a more accurate, but slightly slower,
232         * IDCT method will be used instead.
233         */
234        public boolean inPreferQualityOverSpeed;
235
236        /**
237         * The resulting width of the bitmap, set independent of the state of
238         * inJustDecodeBounds. However, if there is an error trying to decode,
239         * outWidth will be set to -1.
240         */
241
242        public int outWidth;
243
244        /**
245         * The resulting height of the bitmap, set independent of the state of
246         * inJustDecodeBounds. However, if there is an error trying to decode,
247         * outHeight will be set to -1.
248         */
249        public int outHeight;
250
251        /**
252         * If known, this string is set to the mimetype of the decoded image.
253         * If not know, or there is an error, it is set to null.
254         */
255        public String outMimeType;
256
257        /**
258         * Temp storage to use for decoding.  Suggest 16K or so.
259         */
260        public byte[] inTempStorage;
261
262        private native void requestCancel();
263
264        /**
265         * Flag to indicate that cancel has been called on this object.  This
266         * is useful if there's an intermediary that wants to first decode the
267         * bounds and then decode the image.  In that case the intermediary
268         * can check, inbetween the bounds decode and the image decode, to see
269         * if the operation is canceled.
270         */
271        public boolean mCancel;
272
273        /**
274         *  This can be called from another thread while this options object is
275         *  inside a decode... call. Calling this will notify the decoder that
276         *  it should cancel its operation. This is not guaranteed to cancel
277         *  the decode, but if it does, the decoder... operation will return
278         *  null, or if inJustDecodeBounds is true, will set outWidth/outHeight
279         *  to -1
280         */
281        public void requestCancelDecode() {
282            mCancel = true;
283            requestCancel();
284        }
285    }
286
287    /**
288     * Decode a file path into a bitmap. If the specified file name is null,
289     * or cannot be decoded into a bitmap, the function returns null.
290     *
291     * @param pathName complete path name for the file to be decoded.
292     * @param opts null-ok; Options that control downsampling and whether the
293     *             image should be completely decoded, or just is size returned.
294     * @return The decoded bitmap, or null if the image data could not be
295     *         decoded, or, if opts is non-null, if opts requested only the
296     *         size be returned (in opts.outWidth and opts.outHeight)
297     */
298    public static Bitmap decodeFile(String pathName, Options opts) {
299        Bitmap bm = null;
300        InputStream stream = null;
301        try {
302            stream = new FileInputStream(pathName);
303            bm = decodeStream(stream, null, opts);
304        } catch (Exception e) {
305            /*  do nothing.
306                If the exception happened on open, bm will be null.
307            */
308        } finally {
309            if (stream != null) {
310                try {
311                    stream.close();
312                } catch (IOException e) {
313                    // do nothing here
314                }
315            }
316        }
317        return bm;
318    }
319
320    /**
321     * Decode a file path into a bitmap. If the specified file name is null,
322     * or cannot be decoded into a bitmap, the function returns null.
323     *
324     * @param pathName complete path name for the file to be decoded.
325     * @return the resulting decoded bitmap, or null if it could not be decoded.
326     */
327    public static Bitmap decodeFile(String pathName) {
328        return decodeFile(pathName, null);
329    }
330
331    /**
332     * Decode a new Bitmap from an InputStream. This InputStream was obtained from
333     * resources, which we pass to be able to scale the bitmap accordingly.
334     */
335    public static Bitmap decodeResourceStream(Resources res, TypedValue value,
336            InputStream is, Rect pad, Options opts) {
337
338        if (opts == null) {
339            opts = new Options();
340        }
341
342        if (opts.inDensity == 0 && value != null) {
343            final int density = value.density;
344            if (density == TypedValue.DENSITY_DEFAULT) {
345                opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;
346            } else if (density != TypedValue.DENSITY_NONE) {
347                opts.inDensity = density;
348            }
349        }
350
351        if (opts.inTargetDensity == 0 && res != null) {
352            opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
353        }
354
355        return decodeStream(is, pad, opts);
356    }
357
358    /**
359     * Synonym for opening the given resource and calling
360     * {@link #decodeResourceStream}.
361     *
362     * @param res   The resources object containing the image data
363     * @param id The resource id of the image data
364     * @param opts null-ok; Options that control downsampling and whether the
365     *             image should be completely decoded, or just is size returned.
366     * @return The decoded bitmap, or null if the image data could not be
367     *         decoded, or, if opts is non-null, if opts requested only the
368     *         size be returned (in opts.outWidth and opts.outHeight)
369     */
370    public static Bitmap decodeResource(Resources res, int id, Options opts) {
371        Bitmap bm = null;
372        InputStream is = null;
373
374        try {
375            final TypedValue value = new TypedValue();
376            is = res.openRawResource(id, value);
377
378            bm = decodeResourceStream(res, value, is, null, opts);
379        } catch (Exception e) {
380            /*  do nothing.
381                If the exception happened on open, bm will be null.
382                If it happened on close, bm is still valid.
383            */
384        } finally {
385            try {
386                if (is != null) is.close();
387            } catch (IOException e) {
388                // Ignore
389            }
390        }
391
392        return bm;
393    }
394
395    /**
396     * Synonym for {@link #decodeResource(Resources, int, android.graphics.BitmapFactory.Options)}
397     * will null Options.
398     *
399     * @param res The resources object containing the image data
400     * @param id The resource id of the image data
401     * @return The decoded bitmap, or null if the image could not be decode.
402     */
403    public static Bitmap decodeResource(Resources res, int id) {
404        return decodeResource(res, id, null);
405    }
406
407    /**
408     * Decode an immutable bitmap from the specified byte array.
409     *
410     * @param data byte array of compressed image data
411     * @param offset offset into imageData for where the decoder should begin
412     *               parsing.
413     * @param length the number of bytes, beginning at offset, to parse
414     * @param opts null-ok; Options that control downsampling and whether the
415     *             image should be completely decoded, or just is size returned.
416     * @return The decoded bitmap, or null if the image data could not be
417     *         decoded, or, if opts is non-null, if opts requested only the
418     *         size be returned (in opts.outWidth and opts.outHeight)
419     */
420    public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts) {
421        if ((offset | length) < 0 || data.length < offset + length) {
422            throw new ArrayIndexOutOfBoundsException();
423        }
424        return nativeDecodeByteArray(data, offset, length, opts);
425    }
426
427    /**
428     * Decode an immutable bitmap from the specified byte array.
429     *
430     * @param data byte array of compressed image data
431     * @param offset offset into imageData for where the decoder should begin
432     *               parsing.
433     * @param length the number of bytes, beginning at offset, to parse
434     * @return The decoded bitmap, or null if the image could not be decode.
435     */
436    public static Bitmap decodeByteArray(byte[] data, int offset, int length) {
437        return decodeByteArray(data, offset, length, null);
438    }
439
440    /**
441     * Decode an input stream into a bitmap. If the input stream is null, or
442     * cannot be used to decode a bitmap, the function returns null.
443     * The stream's position will be where ever it was after the encoded data
444     * was read.
445     *
446     * @param is The input stream that holds the raw data to be decoded into a
447     *           bitmap.
448     * @param outPadding If not null, return the padding rect for the bitmap if
449     *                   it exists, otherwise set padding to [-1,-1,-1,-1]. If
450     *                   no bitmap is returned (null) then padding is
451     *                   unchanged.
452     * @param opts null-ok; Options that control downsampling and whether the
453     *             image should be completely decoded, or just is size returned.
454     * @return The decoded bitmap, or null if the image data could not be
455     *         decoded, or, if opts is non-null, if opts requested only the
456     *         size be returned (in opts.outWidth and opts.outHeight)
457     */
458    public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
459        // we don't throw in this case, thus allowing the caller to only check
460        // the cache, and not force the image to be decoded.
461        if (is == null) {
462            return null;
463        }
464
465        // we need mark/reset to work properly
466
467        if (!is.markSupported()) {
468            is = new BufferedInputStream(is, 16 * 1024);
469        }
470
471        // so we can call reset() if a given codec gives up after reading up to
472        // this many bytes. FIXME: need to find out from the codecs what this
473        // value should be.
474        is.mark(1024);
475
476        Bitmap  bm;
477
478        if (is instanceof AssetManager.AssetInputStream) {
479            bm = nativeDecodeAsset(((AssetManager.AssetInputStream) is).getAssetInt(),
480                    outPadding, opts);
481        } else {
482            // pass some temp storage down to the native code. 1024 is made up,
483            // but should be large enough to avoid too many small calls back
484            // into is.read(...) This number is not related to the value passed
485            // to mark(...) above.
486            byte [] tempStorage = null;
487            if (opts != null) tempStorage = opts.inTempStorage;
488            if (tempStorage == null) tempStorage = new byte[16 * 1024];
489            bm = nativeDecodeStream(is, tempStorage, outPadding, opts);
490        }
491
492        return finishDecode(bm, outPadding, opts);
493    }
494
495    private static Bitmap finishDecode(Bitmap bm, Rect outPadding, Options opts) {
496        if (bm == null || opts == null) {
497            return bm;
498        }
499
500        final int density = opts.inDensity;
501        if (density == 0) {
502            return bm;
503        }
504
505        bm.setDensity(density);
506        final int targetDensity = opts.inTargetDensity;
507        if (targetDensity == 0 || density == targetDensity || density == opts.inScreenDensity) {
508            return bm;
509        }
510
511        byte[] np = bm.getNinePatchChunk();
512        final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np);
513        if (opts.inScaled || isNinePatch) {
514            float scale = targetDensity / (float)density;
515            // TODO: This is very inefficient and should be done in native by Skia
516            final Bitmap oldBitmap = bm;
517            bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f),
518                    (int) (bm.getHeight() * scale + 0.5f), true);
519            oldBitmap.recycle();
520
521            if (isNinePatch) {
522                np = nativeScaleNinePatch(np, scale, outPadding);
523                bm.setNinePatchChunk(np);
524            }
525            bm.setDensity(targetDensity);
526        }
527
528        return bm;
529    }
530
531    /**
532     * Decode an input stream into a bitmap. If the input stream is null, or
533     * cannot be used to decode a bitmap, the function returns null.
534     * The stream's position will be where ever it was after the encoded data
535     * was read.
536     *
537     * @param is The input stream that holds the raw data to be decoded into a
538     *           bitmap.
539     * @return The decoded bitmap, or null if the image data could not be decoded.
540     */
541    public static Bitmap decodeStream(InputStream is) {
542        return decodeStream(is, null, null);
543    }
544
545    /**
546     * Decode a bitmap from the file descriptor. If the bitmap cannot be decoded
547     * return null. The position within the descriptor will not be changed when
548     * this returns, so the descriptor can be used again as-is.
549     *
550     * @param fd The file descriptor containing the bitmap data to decode
551     * @param outPadding If not null, return the padding rect for the bitmap if
552     *                   it exists, otherwise set padding to [-1,-1,-1,-1]. If
553     *                   no bitmap is returned (null) then padding is
554     *                   unchanged.
555     * @param opts null-ok; Options that control downsampling and whether the
556     *             image should be completely decoded, or just is size returned.
557     * @return the decoded bitmap, or null
558     */
559    public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
560        Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
561        return finishDecode(bm, outPadding, opts);
562    }
563
564    /**
565     * Decode a bitmap from the file descriptor. If the bitmap cannot be decoded
566     * return null. The position within the descriptor will not be changed when
567     * this returns, so the descriptor can be used again as is.
568     *
569     * @param fd The file descriptor containing the bitmap data to decode
570     * @return the decoded bitmap, or null
571     */
572    public static Bitmap decodeFileDescriptor(FileDescriptor fd) {
573        return decodeFileDescriptor(fd, null, null);
574    }
575
576    /**
577     * Set the default config used for decoding bitmaps. This config is
578     * presented to the codec if the caller did not specify a preferred config
579     * in their call to decode...
580     *
581     * The default value is chosen by the system to best match the device's
582     * screen and memory constraints.
583     *
584     * @param config The preferred config for decoding bitmaps. If null, then
585     *               a suitable default is chosen by the system.
586     *
587     * @hide - only called by the browser at the moment, but should be stable
588     *   enough to expose if needed
589     */
590    public static void setDefaultConfig(Bitmap.Config config) {
591        if (config == null) {
592            // pick this for now, as historically it was our default.
593            // However, if we have a smarter algorithm, we can change this.
594            config = Bitmap.Config.RGB_565;
595        }
596        nativeSetDefaultConfig(config.nativeInt);
597    }
598
599    private static native void nativeSetDefaultConfig(int nativeConfig);
600    private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,
601            Rect padding, Options opts);
602    private static native Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,
603            Rect padding, Options opts);
604    private static native Bitmap nativeDecodeAsset(int asset, Rect padding, Options opts);
605    private static native Bitmap nativeDecodeByteArray(byte[] data, int offset,
606            int length, Options opts);
607    private static native byte[] nativeScaleNinePatch(byte[] chunk, float scale, Rect pad);
608}
609