/** * 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; } }
/** Performs the decode synchronously. */ private void doDecode(EncodedImage encodedImage, boolean isLast) { if (isFinished() || !EncodedImage.isValid(encodedImage)) { return; } try { long queueTime = mJobScheduler.getQueuedTime(); int length = isLast ? encodedImage.getSize() : getIntermediateImageEndOffset(encodedImage); QualityInfo quality = isLast ? ImmutableQualityInfo.FULL_QUALITY : getQualityInfo(); mProducerListener.onProducerStart(mProducerContext.getId(), PRODUCER_NAME); CloseableImage image = null; try { image = mImageDecoder.decodeImage(encodedImage, length, quality, mImageDecodeOptions); } catch (Exception e) { Map<String, String> extraMap = getExtraMap(image, queueTime, quality, isLast); mProducerListener.onProducerFinishWithFailure( mProducerContext.getId(), PRODUCER_NAME, e, extraMap); handleError(e); return; } Map<String, String> extraMap = getExtraMap(image, queueTime, quality, isLast); mProducerListener.onProducerFinishWithSuccess( mProducerContext.getId(), PRODUCER_NAME, extraMap); handleResult(image, isLast); } finally { EncodedImage.closeSafely(encodedImage); } }
@Override protected int getIntermediateImageEndOffset(EncodedImage encodedImage) { return encodedImage.getSize(); }