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