/** * Creates a bitmap from encoded JPEG bytes. Supports a partial JPEG image. * * @param encodedImage the encoded image with reference to the encoded bytes * @param bitmapConfig the {@link android.graphics.Bitmap.Config} used to create the decoded * Bitmap * @param length the number of encoded bytes in the buffer * @return the bitmap * @exception java.lang.OutOfMemoryError if the Bitmap cannot be allocated */ @Override public CloseableReference<Bitmap> decodeJPEGFromEncodedImage( EncodedImage encodedImage, Bitmap.Config bitmapConfig, int length) { boolean isJpegComplete = encodedImage.isCompleteAt(length); final BitmapFactory.Options options = getDecodeOptionsForStream(encodedImage, bitmapConfig); InputStream jpegDataStream = encodedImage.getInputStream(); // At this point the InputStream from the encoded image should not be null since in the // pipeline,this comes from a call stack where this was checked before. Also this method needs // the InputStream to decode the image so this can't be null. Preconditions.checkNotNull(jpegDataStream); if (encodedImage.getSize() > length) { jpegDataStream = new LimitedInputStream(jpegDataStream, length); } if (!isJpegComplete) { jpegDataStream = new TailAppendingInputStream(jpegDataStream, EOI_TAIL); } boolean retryOnFail = options.inPreferredConfig != Bitmap.Config.ARGB_8888; try { return decodeStaticImageFromStream(jpegDataStream, options); } catch (RuntimeException re) { if (retryOnFail) { return decodeFromEncodedImage(encodedImage, Bitmap.Config.ARGB_8888); } throw re; } }
/** * Creates a bitmap from encoded bytes. * * @param encodedImage the encoded image with a reference to the encoded bytes * @param bitmapConfig the {@link android.graphics.Bitmap.Config} used to create the decoded * Bitmap * @return the bitmap * @exception java.lang.OutOfMemoryError if the Bitmap cannot be allocated */ @Override public CloseableReference<Bitmap> decodeFromEncodedImage( EncodedImage encodedImage, Bitmap.Config bitmapConfig) { final BitmapFactory.Options options = getDecodeOptionsForStream(encodedImage, bitmapConfig); boolean retryOnFail = options.inPreferredConfig != Bitmap.Config.ARGB_8888; try { return decodeStaticImageFromStream(encodedImage.getInputStream(), options); } catch (RuntimeException re) { if (retryOnFail) { return decodeFromEncodedImage(encodedImage, Bitmap.Config.ARGB_8888); } throw re; } }
/** * Options returned by this method are configured with mDecodeBuffer which is GuardedBy("this") */ private static BitmapFactory.Options getDecodeOptionsForStream( EncodedImage encodedImage, Bitmap.Config bitmapConfig) { final BitmapFactory.Options options = new BitmapFactory.Options(); // Sample size should ONLY be different than 1 when downsampling is enabled in the pipeline options.inSampleSize = encodedImage.getSampleSize(); options.inJustDecodeBounds = true; // fill outWidth and outHeight BitmapFactory.decodeStream(encodedImage.getInputStream(), null, options); if (options.outWidth == -1 || options.outHeight == -1) { throw new IllegalArgumentException(); } options.inJustDecodeBounds = false; options.inDither = true; options.inPreferredConfig = bitmapConfig; options.inMutable = true; return options; }