BitmapFactory.java revision 843ef36f7b96cc19ea7d2996b7c8661b41ec3452
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.TypedValue;
22import android.util.DisplayMetrics;
23
24import java.io.BufferedInputStream;
25import java.io.FileInputStream;
26import java.io.InputStream;
27import java.io.IOException;
28import java.io.FileDescriptor;
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 = true;
42            inDensity = 0;
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        public Bitmap.Config inPreferredConfig;
74
75        /**
76         * If dither is true, the decoder will atttempt to dither the decoded
77         * image.
78         */
79        public boolean inDither;
80
81        /**
82         * The desired pixel density of the bitmap.
83         *
84         * @see android.util.DisplayMetrics#DEFAULT_DENSITY
85         * @see android.util.DisplayMetrics#density
86         *
87         * @hide pending API council approval
88         */
89        public int inDensity;
90
91        /**
92         * </p>If the bitmap is loaded from {@link android.content.res.Resources} and
93         * this flag is turned on, the bitmap will be scaled to match the default
94         * display's pixel density.</p>
95         *
96         * </p>This flag is turned on by default and should be turned off if you need
97         * a non-scaled version of the bitmap. In this case,
98         * {@link android.graphics.Bitmap#setAutoScalingEnabled(boolean)} can be used
99         * to properly scale the bitmap at drawing time.</p>
100         *
101         * @hide pending API council approval
102         */
103        public boolean inScaled;
104
105        /**
106         * If this is set to true, then the resulting bitmap will allocate its
107         * pixels such that they can be purged if the system needs to reclaim
108         * memory. In that instance, when the pixels need to be accessed again
109         * (e.g. the bitmap is drawn, getPixels() is called), they will be
110         * automatically re-decoded.
111         *
112         * For the re-decode to happen, the bitmap must have access to the
113         * encoded data, either by sharing a reference to the input
114         * or by making a copy of it. This distinction is controlled by
115         * inInputShareable. If this is true, then the bitmap may keep a shallow
116         * reference to the input. If this is false, then the bitmap will
117         * explicitly make a copy of the input data, and keep that. Even if
118         * sharing is allowed, the implementation may still decide to make a
119         * deep copy of the input data.
120         *
121         * @hide pending API council approval
122         */
123        public boolean inPurgeable;
124
125        /**
126         * This field works in conjuction with inPurgeable. If inPurgeable is
127         * false, then this field is ignored. If inPurgeable is true, then this
128         * field determines whether the bitmap can share a reference to the
129         * input data (inputstream, array, etc.) or if it must make a deep copy.
130         *
131         * @hide pending API council approval
132         */
133        public boolean inInputShareable;
134
135        /**
136         * The resulting width of the bitmap, set independent of the state of
137         * inJustDecodeBounds. However, if there is an error trying to decode,
138         * outWidth will be set to -1.
139         */
140        public int outWidth;
141
142        /**
143         * The resulting height of the bitmap, set independent of the state of
144         * inJustDecodeBounds. However, if there is an error trying to decode,
145         * outHeight will be set to -1.
146         */
147        public int outHeight;
148
149        /**
150         * If known, this string is set to the mimetype of the decoded image.
151         * If not know, or there is an error, it is set to null.
152         */
153        public String outMimeType;
154
155        /**
156         * Temp storage to use for decoding.  Suggest 16K or so.
157         */
158        public byte[] inTempStorage;
159
160        private native void requestCancel();
161
162        /**
163         * Flag to indicate that cancel has been called on this object.  This
164         * is useful if there's an intermediary that wants to first decode the
165         * bounds and then decode the image.  In that case the intermediary
166         * can check, inbetween the bounds decode and the image decode, to see
167         * if the operation is canceled.
168         */
169        public boolean mCancel;
170
171        /**
172         *  This can be called from another thread while this options object is
173         *  inside a decode... call. Calling this will notify the decoder that
174         *  it should cancel its operation. This is not guaranteed to cancel
175         *  the decode, but if it does, the decoder... operation will return
176         *  null, or if inJustDecodeBounds is true, will set outWidth/outHeight
177         *  to -1
178         */
179        public void requestCancelDecode() {
180            mCancel = true;
181            requestCancel();
182        }
183    }
184
185    /**
186     * Decode a file path into a bitmap. If the specified file name is null,
187     * or cannot be decoded into a bitmap, the function returns null.
188     *
189     * @param pathName complete path name for the file to be decoded.
190     * @param opts null-ok; Options that control downsampling and whether the
191     *             image should be completely decoded, or just is size returned.
192     * @return The decoded bitmap, or null if the image data could not be
193     *         decoded, or, if opts is non-null, if opts requested only the
194     *         size be returned (in opts.outWidth and opts.outHeight)
195     */
196    public static Bitmap decodeFile(String pathName, Options opts) {
197        Bitmap bm = null;
198        InputStream stream = null;
199        try {
200            stream = new FileInputStream(pathName);
201            bm = decodeStream(stream, null, opts);
202        } catch (Exception e) {
203            /*  do nothing.
204                If the exception happened on open, bm will be null.
205            */
206        } finally {
207            if (stream != null) {
208                try {
209                    stream.close();
210                } catch (IOException e) {
211                    // do nothing here
212                }
213            }
214        }
215        return bm;
216    }
217
218    /**
219     * Decode a file path into a bitmap. If the specified file name is null,
220     * or cannot be decoded into a bitmap, the function returns null.
221     *
222     * @param pathName complete path name for the file to be decoded.
223     * @return the resulting decoded bitmap, or null if it could not be decoded.
224     */
225    public static Bitmap decodeFile(String pathName) {
226        return decodeFile(pathName, null);
227    }
228
229    /**
230     * Decode a new Bitmap from an InputStream. This InputStream was obtained from
231     * resources, which we pass to be able to scale the bitmap accordingly.
232     *
233     * @hide
234     */
235    public static Bitmap decodeStream(Resources res, TypedValue value, InputStream is,
236            Rect pad, Options opts) {
237
238        if (opts == null) {
239            opts = new Options();
240        }
241
242        Bitmap bm = decodeStream(is, pad, opts);
243
244        if (bm != null && res != null && value != null) {
245            byte[] np = bm.getNinePatchChunk();
246            final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np);
247
248            final int density = value.density;
249            if (opts.inDensity == 0) {
250                opts.inDensity = density == TypedValue.DENSITY_DEFAULT ?
251                        DisplayMetrics.DEFAULT_DENSITY : density;
252            }
253            float scale = opts.inDensity / (float) DisplayMetrics.DEFAULT_DENSITY;
254
255            if (opts.inScaled || isNinePatch) {
256                bm.setDensityScale(1.0f);
257                bm.setAutoScalingEnabled(false);
258                // Assume we are going to prescale for the screen
259                scale = res.getDisplayMetrics().density / scale;
260                if (scale != 1.0f) {
261                    // TODO: This is very inefficient and should be done in native by Skia
262                    final Bitmap oldBitmap = bm;
263                    bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f),
264                            (int) (bm.getHeight() * scale + 0.5f), true);
265                    oldBitmap.recycle();
266
267                    if (isNinePatch) {
268                        np = nativeScaleNinePatch(np, scale, pad);
269                        bm.setNinePatchChunk(np);
270                    }
271                }
272            } else {
273                bm.setDensityScale(scale);
274                bm.setAutoScalingEnabled(true);
275            }
276        }
277
278        return bm;
279    }
280
281    /**
282     * Decode an image referenced by a resource ID.
283     *
284     * @param res   The resources object containing the image data
285     * @param id The resource id of the image data
286     * @param opts null-ok; Options that control downsampling and whether the
287     *             image should be completely decoded, or just is size returned.
288     * @return The decoded bitmap, or null if the image data could not be
289     *         decoded, or, if opts is non-null, if opts requested only the
290     *         size be returned (in opts.outWidth and opts.outHeight)
291     */
292    public static Bitmap decodeResource(Resources res, int id, Options opts) {
293        Bitmap bm = null;
294
295        try {
296            final TypedValue value = new TypedValue();
297            final InputStream is = res.openRawResource(id, value);
298
299            bm = decodeStream(res, value, is, null, opts);
300            is.close();
301        } catch (java.io.IOException e) {
302            /*  do nothing.
303                If the exception happened on open, bm will be null.
304                If it happened on close, bm is still valid.
305            */
306        }
307        return bm;
308    }
309
310    /**
311     * Decode an image referenced by a resource ID.
312     *
313     * @param res The resources object containing the image data
314     * @param id The resource id of the image data
315     * @return The decoded bitmap, or null if the image could not be decode.
316     */
317    public static Bitmap decodeResource(Resources res, int id) {
318        return decodeResource(res, id, null);
319    }
320
321    /**
322     * Decode an immutable bitmap from the specified byte array.
323     *
324     * @param data byte array of compressed image data
325     * @param offset offset into imageData for where the decoder should begin
326     *               parsing.
327     * @param length the number of bytes, beginning at offset, to parse
328     * @param opts null-ok; Options that control downsampling and whether the
329     *             image should be completely decoded, or just is size returned.
330     * @return The decoded bitmap, or null if the image data could not be
331     *         decoded, or, if opts is non-null, if opts requested only the
332     *         size be returned (in opts.outWidth and opts.outHeight)
333     */
334    public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts) {
335        if ((offset | length) < 0 || data.length < offset + length) {
336            throw new ArrayIndexOutOfBoundsException();
337        }
338        return nativeDecodeByteArray(data, offset, length, opts);
339    }
340
341    /**
342     * Decode an immutable bitmap from the specified byte array.
343     *
344     * @param data byte array of compressed image data
345     * @param offset offset into imageData for where the decoder should begin
346     *               parsing.
347     * @param length the number of bytes, beginning at offset, to parse
348     * @return The decoded bitmap, or null if the image could not be decode.
349     */
350    public static Bitmap decodeByteArray(byte[] data, int offset, int length) {
351        return decodeByteArray(data, offset, length, null);
352    }
353
354    /**
355     * Decode an input stream into a bitmap. If the input stream is null, or
356     * cannot be used to decode a bitmap, the function returns null.
357     * The stream's position will be where ever it was after the encoded data
358     * was read.
359     *
360     * @param is The input stream that holds the raw data to be decoded into a
361     *           bitmap.
362     * @param outPadding If not null, return the padding rect for the bitmap if
363     *                   it exists, otherwise set padding to [-1,-1,-1,-1]. If
364     *                   no bitmap is returned (null) then padding is
365     *                   unchanged.
366     * @param opts null-ok; Options that control downsampling and whether the
367     *             image should be completely decoded, or just is size returned.
368     * @return The decoded bitmap, or null if the image data could not be
369     *         decoded, or, if opts is non-null, if opts requested only the
370     *         size be returned (in opts.outWidth and opts.outHeight)
371     */
372    public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
373        // we don't throw in this case, thus allowing the caller to only check
374        // the cache, and not force the image to be decoded.
375        if (is == null) {
376            return null;
377        }
378
379        // we need mark/reset to work properly
380
381        if (!is.markSupported()) {
382            is = new BufferedInputStream(is, 16 * 1024);
383        }
384
385        // so we can call reset() if a given codec gives up after reading up to
386        // this many bytes. FIXME: need to find out from the codecs what this
387        // value should be.
388        is.mark(1024);
389
390        Bitmap  bm;
391
392        if (is instanceof AssetManager.AssetInputStream) {
393            bm = nativeDecodeAsset(((AssetManager.AssetInputStream) is).getAssetInt(),
394                    outPadding, opts);
395        } else {
396            // pass some temp storage down to the native code. 1024 is made up,
397            // but should be large enough to avoid too many small calls back
398            // into is.read(...) This number is not related to the value passed
399            // to mark(...) above.
400            byte [] tempStorage = null;
401            if (opts != null)
402                tempStorage = opts.inTempStorage;
403            if (tempStorage == null)
404                tempStorage = new byte[16 * 1024];
405            bm = nativeDecodeStream(is, tempStorage, outPadding, opts);
406        }
407
408        return bm;
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     * @return The decoded bitmap, or null if the image data could not be
420     *         decoded, or, if opts is non-null, if opts requested only the
421     *         size be returned (in opts.outWidth and opts.outHeight)
422     */
423    public static Bitmap decodeStream(InputStream is) {
424        return decodeStream(is, null, null);
425    }
426
427    /**
428     * Decode a bitmap from the file descriptor. If the bitmap cannot be decoded
429     * return null. The position within the descriptor will not be changed when
430     * this returns, so the descriptor can be used again as is.
431     *
432     * @param fd The file descriptor containing the bitmap data to decode
433     * @param outPadding If not null, return the padding rect for the bitmap if
434     *                   it exists, otherwise set padding to [-1,-1,-1,-1]. If
435     *                   no bitmap is returned (null) then padding is
436     *                   unchanged.
437     * @param opts null-ok; Options that control downsampling and whether the
438     *             image should be completely decoded, or just is size returned.
439     * @return the decoded bitmap, or null
440     */
441    public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
442        return nativeDecodeFileDescriptor(fd, outPadding, opts);
443    }
444
445    /**
446     * Decode a bitmap from the file descriptor. If the bitmap cannot be decoded
447     * return null. The position within the descriptor will not be changed when
448     * this returns, so the descriptor can be used again as is.
449     *
450     * @param fd The file descriptor containing the bitmap data to decode
451     * @return the decoded bitmap, or null
452     */
453    public static Bitmap decodeFileDescriptor(FileDescriptor fd) {
454        return nativeDecodeFileDescriptor(fd, null, null);
455    }
456
457    private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,
458            Rect padding, Options opts);
459    private static native Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,
460            Rect padding, Options opts);
461    private static native Bitmap nativeDecodeAsset(int asset, Rect padding, Options opts);
462    private static native Bitmap nativeDecodeByteArray(byte[] data, int offset,
463            int length, Options opts);
464    private static native byte[] nativeScaleNinePatch(byte[] chunk, float scale, Rect pad);
465}
466
467