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.Log;
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    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         */
43        public Options() {
44            inDither = false;
45            inScaled = true;
46        }
47
48        /**
49         * If set, decode methods that take the Options object will attempt to
50         * reuse this bitmap when loading content. If the decode operation cannot
51         * use this bitmap, the decode method will return <code>null</code> and
52         * will throw an IllegalArgumentException. The
53         * current implementation necessitates that the reused bitmap be of the
54         * same size as the source content and in jpeg or png format (whether as a
55         * resource or as a stream). The {@link android.graphics.Bitmap.Config
56         * configuration} of the reused bitmap will override the setting of
57         * {@link #inPreferredConfig}, if set.
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 is a way to see if the bitmap was reused,
64         * but in all cases you should use the returned Bitmap to make sure
65         * that you are using the bitmap that was used as the decode destination.</p>
66         */
67        public Bitmap inBitmap;
68
69        /**
70         * If set, decode methods will always return a mutable Bitmap instead of
71         * an immutable one. This can be used for instance to programmatically apply
72         * effects to a Bitmap loaded through BitmapFactory.
73         */
74        @SuppressWarnings({"UnusedDeclaration"}) // used in native code
75        public boolean inMutable;
76
77        /**
78         * If set to true, the decoder will return null (no bitmap), but
79         * the out... fields will still be set, allowing the caller to query
80         * the bitmap without having to allocate the memory for its pixels.
81         */
82        public boolean inJustDecodeBounds;
83
84        /**
85         * If set to a value > 1, requests the decoder to subsample the original
86         * image, returning a smaller image to save memory. The sample size is
87         * the number of pixels in either dimension that correspond to a single
88         * pixel in the decoded bitmap. For example, inSampleSize == 4 returns
89         * an image that is 1/4 the width/height of the original, and 1/16 the
90         * number of pixels. Any value <= 1 is treated the same as 1. Note: the
91         * decoder will try to fulfill this request, but the resulting bitmap
92         * may have different dimensions that precisely what has been requested.
93         * Also, powers of 2 are often faster/easier for the decoder to honor.
94         */
95        public int inSampleSize;
96
97        /**
98         * If this is non-null, the decoder will try to decode into this
99         * internal configuration. If it is null, or the request cannot be met,
100         * the decoder will try to pick the best matching config based on the
101         * system's screen depth, and characteristics of the original image such
102         * as if it has per-pixel alpha (requiring a config that also does).
103         *
104         * Image are loaded with the {@link Bitmap.Config#ARGB_8888} config by
105         * default.
106         */
107        public Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888;
108
109        /**
110         * If dither is true, the decoder will attempt to dither the decoded
111         * image.
112         */
113        public boolean inDither;
114
115        /**
116         * The pixel density to use for the bitmap.  This will always result
117         * in the returned bitmap having a density set for it (see
118         * {@link Bitmap#setDensity(int) Bitmap.setDensity(int)}).  In addition,
119         * if {@link #inScaled} is set (which it is by default} and this
120         * density does not match {@link #inTargetDensity}, then the bitmap
121         * will be scaled to the target density before being returned.
122         *
123         * <p>If this is 0,
124         * {@link BitmapFactory#decodeResource(Resources, int)},
125         * {@link BitmapFactory#decodeResource(Resources, int, android.graphics.BitmapFactory.Options)},
126         * and {@link BitmapFactory#decodeResourceStream}
127         * will fill in the density associated with the resource.  The other
128         * functions will leave it as-is and no density will be applied.
129         *
130         * @see #inTargetDensity
131         * @see #inScreenDensity
132         * @see #inScaled
133         * @see Bitmap#setDensity(int)
134         * @see android.util.DisplayMetrics#densityDpi
135         */
136        public int inDensity;
137
138        /**
139         * The pixel density of the destination this bitmap will be drawn to.
140         * This is used in conjunction with {@link #inDensity} and
141         * {@link #inScaled} to determine if and how to scale the bitmap before
142         * returning it.
143         *
144         * <p>If this is 0,
145         * {@link BitmapFactory#decodeResource(Resources, int)},
146         * {@link BitmapFactory#decodeResource(Resources, int, android.graphics.BitmapFactory.Options)},
147         * and {@link BitmapFactory#decodeResourceStream}
148         * will fill in the density associated the Resources object's
149         * DisplayMetrics.  The other
150         * functions will leave it as-is and no scaling for density will be
151         * performed.
152         *
153         * @see #inDensity
154         * @see #inScreenDensity
155         * @see #inScaled
156         * @see android.util.DisplayMetrics#densityDpi
157         */
158        public int inTargetDensity;
159
160        /**
161         * The pixel density of the actual screen that is being used.  This is
162         * purely for applications running in density compatibility code, where
163         * {@link #inTargetDensity} is actually the density the application
164         * sees rather than the real screen density.
165         *
166         * <p>By setting this, you
167         * allow the loading code to avoid scaling a bitmap that is currently
168         * in the screen density up/down to the compatibility density.  Instead,
169         * if {@link #inDensity} is the same as {@link #inScreenDensity}, the
170         * bitmap will be left as-is.  Anything using the resulting bitmap
171         * must also used {@link Bitmap#getScaledWidth(int)
172         * Bitmap.getScaledWidth} and {@link Bitmap#getScaledHeight
173         * Bitmap.getScaledHeight} to account for any different between the
174         * bitmap's density and the target's density.
175         *
176         * <p>This is never set automatically for the caller by
177         * {@link BitmapFactory} itself.  It must be explicitly set, since the
178         * caller must deal with the resulting bitmap in a density-aware way.
179         *
180         * @see #inDensity
181         * @see #inTargetDensity
182         * @see #inScaled
183         * @see android.util.DisplayMetrics#densityDpi
184         */
185        public int inScreenDensity;
186
187        /**
188         * When this flag is set, if {@link #inDensity} and
189         * {@link #inTargetDensity} are not 0, the
190         * bitmap will be scaled to match {@link #inTargetDensity} when loaded,
191         * rather than relying on the graphics system scaling it each time it
192         * is drawn to a Canvas.
193         *
194         * <p>This flag is turned on by default and should be turned off if you need
195         * a non-scaled version of the bitmap.  Nine-patch bitmaps ignore this
196         * flag and are always scaled.
197         */
198        public boolean inScaled;
199
200        /**
201         * If this is set to true, then the resulting bitmap will allocate its
202         * pixels such that they can be purged if the system needs to reclaim
203         * memory. In that instance, when the pixels need to be accessed again
204         * (e.g. the bitmap is drawn, getPixels() is called), they will be
205         * automatically re-decoded.
206         *
207         * For the re-decode to happen, the bitmap must have access to the
208         * encoded data, either by sharing a reference to the input
209         * or by making a copy of it. This distinction is controlled by
210         * inInputShareable. If this is true, then the bitmap may keep a shallow
211         * reference to the input. If this is false, then the bitmap will
212         * explicitly make a copy of the input data, and keep that. Even if
213         * sharing is allowed, the implementation may still decide to make a
214         * deep copy of the input data.
215         */
216        public boolean inPurgeable;
217
218        /**
219         * This field works in conjuction with inPurgeable. If inPurgeable is
220         * false, then this field is ignored. If inPurgeable is true, then this
221         * field determines whether the bitmap can share a reference to the
222         * input data (inputstream, array, etc.) or if it must make a deep copy.
223         */
224        public boolean inInputShareable;
225
226        /**
227         * If inPreferQualityOverSpeed is set to true, the decoder will try to
228         * decode the reconstructed image to a higher quality even at the
229         * expense of the decoding speed. Currently the field only affects JPEG
230         * decode, in the case of which a more accurate, but slightly slower,
231         * IDCT method will be used instead.
232         */
233        public boolean inPreferQualityOverSpeed;
234
235        /**
236         * The resulting width of the bitmap, set independent of the state of
237         * inJustDecodeBounds. However, if there is an error trying to decode,
238         * outWidth will be set to -1.
239         */
240
241        public int outWidth;
242
243        /**
244         * The resulting height of the bitmap, set independent of the state of
245         * inJustDecodeBounds. However, if there is an error trying to decode,
246         * outHeight will be set to -1.
247         */
248        public int outHeight;
249
250        /**
251         * If known, this string is set to the mimetype of the decoded image.
252         * If not know, or there is an error, it is set to null.
253         */
254        public String outMimeType;
255
256        /**
257         * Temp storage to use for decoding.  Suggest 16K or so.
258         */
259        public byte[] inTempStorage;
260
261        private native void requestCancel();
262
263        /**
264         * Flag to indicate that cancel has been called on this object.  This
265         * is useful if there's an intermediary that wants to first decode the
266         * bounds and then decode the image.  In that case the intermediary
267         * can check, inbetween the bounds decode and the image decode, to see
268         * if the operation is canceled.
269         */
270        public boolean mCancel;
271
272        /**
273         *  This can be called from another thread while this options object is
274         *  inside a decode... call. Calling this will notify the decoder that
275         *  it should cancel its operation. This is not guaranteed to cancel
276         *  the decode, but if it does, the decoder... operation will return
277         *  null, or if inJustDecodeBounds is true, will set outWidth/outHeight
278         *  to -1
279         */
280        public void requestCancelDecode() {
281            mCancel = true;
282            requestCancel();
283        }
284    }
285
286    /**
287     * Decode a file path into a bitmap. If the specified file name is null,
288     * or cannot be decoded into a bitmap, the function returns null.
289     *
290     * @param pathName complete path name for the file to be decoded.
291     * @param opts null-ok; Options that control downsampling and whether the
292     *             image should be completely decoded, or just is size returned.
293     * @return The decoded bitmap, or null if the image data could not be
294     *         decoded, or, if opts is non-null, if opts requested only the
295     *         size be returned (in opts.outWidth and opts.outHeight)
296     */
297    public static Bitmap decodeFile(String pathName, Options opts) {
298        Bitmap bm = null;
299        InputStream stream = null;
300        try {
301            stream = new FileInputStream(pathName);
302            bm = decodeStream(stream, null, opts);
303        } catch (Exception e) {
304            /*  do nothing.
305                If the exception happened on open, bm will be null.
306            */
307            Log.e("BitmapFactory", "Unable to decode stream: " + e);
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        if (bm == null && opts != null && opts.inBitmap != null) {
393            throw new IllegalArgumentException("Problem decoding into existing bitmap");
394        }
395
396        return bm;
397    }
398
399    /**
400     * Synonym for {@link #decodeResource(Resources, int, android.graphics.BitmapFactory.Options)}
401     * will null Options.
402     *
403     * @param res The resources object containing the image data
404     * @param id The resource id of the image data
405     * @return The decoded bitmap, or null if the image could not be decode.
406     */
407    public static Bitmap decodeResource(Resources res, int id) {
408        return decodeResource(res, id, null);
409    }
410
411    /**
412     * Decode an immutable bitmap from the specified byte array.
413     *
414     * @param data byte array of compressed image data
415     * @param offset offset into imageData for where the decoder should begin
416     *               parsing.
417     * @param length the number of bytes, beginning at offset, to parse
418     * @param opts null-ok; Options that control downsampling and whether the
419     *             image should be completely decoded, or just is size returned.
420     * @return The decoded bitmap, or null if the image data could not be
421     *         decoded, or, if opts is non-null, if opts requested only the
422     *         size be returned (in opts.outWidth and opts.outHeight)
423     */
424    public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts) {
425        if ((offset | length) < 0 || data.length < offset + length) {
426            throw new ArrayIndexOutOfBoundsException();
427        }
428        Bitmap bm = nativeDecodeByteArray(data, offset, length, opts);
429
430        if (bm == null && opts != null && opts.inBitmap != null) {
431            throw new IllegalArgumentException("Problem decoding into existing bitmap");
432        }
433        return bm;
434    }
435
436    /**
437     * Decode an immutable bitmap from the specified byte array.
438     *
439     * @param data byte array of compressed image data
440     * @param offset offset into imageData for where the decoder should begin
441     *               parsing.
442     * @param length the number of bytes, beginning at offset, to parse
443     * @return The decoded bitmap, or null if the image could not be decode.
444     */
445    public static Bitmap decodeByteArray(byte[] data, int offset, int length) {
446        return decodeByteArray(data, offset, length, null);
447    }
448
449    /**
450     * Decode an input stream into a bitmap. If the input stream is null, or
451     * cannot be used to decode a bitmap, the function returns null.
452     * The stream's position will be where ever it was after the encoded data
453     * was read.
454     *
455     * @param is The input stream that holds the raw data to be decoded into a
456     *           bitmap.
457     * @param outPadding If not null, return the padding rect for the bitmap if
458     *                   it exists, otherwise set padding to [-1,-1,-1,-1]. If
459     *                   no bitmap is returned (null) then padding is
460     *                   unchanged.
461     * @param opts null-ok; Options that control downsampling and whether the
462     *             image should be completely decoded, or just is size returned.
463     * @return The decoded bitmap, or null if the image data could not be
464     *         decoded, or, if opts is non-null, if opts requested only the
465     *         size be returned (in opts.outWidth and opts.outHeight)
466     */
467    public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
468        // we don't throw in this case, thus allowing the caller to only check
469        // the cache, and not force the image to be decoded.
470        if (is == null) {
471            return null;
472        }
473
474        // we need mark/reset to work properly
475
476        if (!is.markSupported()) {
477            is = new BufferedInputStream(is, DECODE_BUFFER_SIZE);
478        }
479
480        // so we can call reset() if a given codec gives up after reading up to
481        // this many bytes. FIXME: need to find out from the codecs what this
482        // value should be.
483        is.mark(1024);
484
485        Bitmap bm;
486        boolean finish = true;
487
488        if (is instanceof AssetManager.AssetInputStream) {
489            final int asset = ((AssetManager.AssetInputStream) is).getAssetInt();
490
491            if (opts == null || (opts.inScaled && opts.inBitmap == null)) {
492                float scale = 1.0f;
493                int targetDensity = 0;
494                if (opts != null) {
495                    final int density = opts.inDensity;
496                    targetDensity = opts.inTargetDensity;
497                    if (density != 0 && targetDensity != 0) {
498                        scale = targetDensity / (float) density;
499                    }
500                }
501
502                bm = nativeDecodeAsset(asset, outPadding, opts, true, scale);
503                if (bm != null && targetDensity != 0) bm.setDensity(targetDensity);
504
505                finish = false;
506            } else {
507                bm = nativeDecodeAsset(asset, outPadding, opts);
508            }
509        } else {
510            // pass some temp storage down to the native code. 1024 is made up,
511            // but should be large enough to avoid too many small calls back
512            // into is.read(...) This number is not related to the value passed
513            // to mark(...) above.
514            byte [] tempStorage = null;
515            if (opts != null) tempStorage = opts.inTempStorage;
516            if (tempStorage == null) tempStorage = new byte[16 * 1024];
517
518            if (opts == null || (opts.inScaled && opts.inBitmap == null)) {
519                float scale = 1.0f;
520                int targetDensity = 0;
521                if (opts != null) {
522                    final int density = opts.inDensity;
523                    targetDensity = opts.inTargetDensity;
524                    if (density != 0 && targetDensity != 0) {
525                        scale = targetDensity / (float) density;
526                    }
527                }
528
529                bm = nativeDecodeStream(is, tempStorage, outPadding, opts, true, scale);
530                if (bm != null && targetDensity != 0) bm.setDensity(targetDensity);
531
532                finish = false;
533            } else {
534                bm = nativeDecodeStream(is, tempStorage, outPadding, opts);
535            }
536        }
537
538        if (bm == null && opts != null && opts.inBitmap != null) {
539            throw new IllegalArgumentException("Problem decoding into existing bitmap");
540        }
541
542        return finish ? finishDecode(bm, outPadding, opts) : bm;
543    }
544
545    private static Bitmap finishDecode(Bitmap bm, Rect outPadding, Options opts) {
546        if (bm == null || opts == null) {
547            return bm;
548        }
549
550        final int density = opts.inDensity;
551        if (density == 0) {
552            return bm;
553        }
554
555        bm.setDensity(density);
556        final int targetDensity = opts.inTargetDensity;
557        if (targetDensity == 0 || density == targetDensity || density == opts.inScreenDensity) {
558            return bm;
559        }
560        byte[] np = bm.getNinePatchChunk();
561        int[] lb = bm.getLayoutBounds();
562        final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np);
563        if (opts.inScaled || isNinePatch) {
564            float scale = targetDensity / (float) density;
565            if (scale != 1.0f) {
566                final Bitmap oldBitmap = bm;
567                bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f),
568                        (int) (bm.getHeight() * scale + 0.5f), true);
569                if (bm != oldBitmap) oldBitmap.recycle();
570
571                if (isNinePatch) {
572                    np = nativeScaleNinePatch(np, scale, outPadding);
573                    bm.setNinePatchChunk(np);
574                }
575                if (lb != null) {
576                    int[] newLb = new int[lb.length];
577                    for (int i=0; i<lb.length; i++) {
578                        newLb[i] = (int)((lb[i]*scale)+.5f);
579                    }
580                    bm.setLayoutBounds(newLb);
581                }
582            }
583
584            bm.setDensity(targetDensity);
585        }
586
587        return bm;
588    }
589
590    /**
591     * Decode an input stream into a bitmap. If the input stream is null, or
592     * cannot be used to decode a bitmap, the function returns null.
593     * The stream's position will be where ever it was after the encoded data
594     * was read.
595     *
596     * @param is The input stream that holds the raw data to be decoded into a
597     *           bitmap.
598     * @return The decoded bitmap, or null if the image data could not be decoded.
599     */
600    public static Bitmap decodeStream(InputStream is) {
601        return decodeStream(is, null, null);
602    }
603
604    /**
605     * Decode a bitmap from the file descriptor. If the bitmap cannot be decoded
606     * return null. The position within the descriptor will not be changed when
607     * this returns, so the descriptor can be used again as-is.
608     *
609     * @param fd The file descriptor containing the bitmap data to decode
610     * @param outPadding If not null, return the padding rect for the bitmap if
611     *                   it exists, otherwise set padding to [-1,-1,-1,-1]. If
612     *                   no bitmap is returned (null) then padding is
613     *                   unchanged.
614     * @param opts null-ok; Options that control downsampling and whether the
615     *             image should be completely decoded, or just is size returned.
616     * @return the decoded bitmap, or null
617     */
618    public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
619        if (nativeIsSeekable(fd)) {
620            Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
621            if (bm == null && opts != null && opts.inBitmap != null) {
622                throw new IllegalArgumentException("Problem decoding into existing bitmap");
623            }
624            return finishDecode(bm, outPadding, opts);
625        } else {
626            FileInputStream fis = new FileInputStream(fd);
627            try {
628                return decodeStream(fis, outPadding, opts);
629            } finally {
630                try {
631                    fis.close();
632                } catch (Throwable t) {/* ignore */}
633            }
634        }
635    }
636
637    /**
638     * Decode a bitmap from the file descriptor. If the bitmap cannot be decoded
639     * return null. The position within the descriptor will not be changed when
640     * this returns, so the descriptor can be used again as is.
641     *
642     * @param fd The file descriptor containing the bitmap data to decode
643     * @return the decoded bitmap, or null
644     */
645    public static Bitmap decodeFileDescriptor(FileDescriptor fd) {
646        return decodeFileDescriptor(fd, null, null);
647    }
648
649    private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,
650            Rect padding, Options opts);
651    private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,
652            Rect padding, Options opts, boolean applyScale, float scale);
653    private static native Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,
654            Rect padding, Options opts);
655    private static native Bitmap nativeDecodeAsset(int asset, Rect padding, Options opts);
656    private static native Bitmap nativeDecodeAsset(int asset, Rect padding, Options opts,
657            boolean applyScale, float scale);
658    private static native Bitmap nativeDecodeByteArray(byte[] data, int offset,
659            int length, Options opts);
660    private static native byte[] nativeScaleNinePatch(byte[] chunk, float scale, Rect pad);
661    private static native boolean nativeIsSeekable(FileDescriptor fd);
662}
663