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