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