Home | History | Annotate | Download | only in graphics
      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 
    567