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