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