OSDN Git Service

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