| Index: src/codec/SkJpegCodec.cpp
|
| diff --git a/src/codec/SkJpegCodec.cpp b/src/codec/SkJpegCodec.cpp
|
| index b4c794c90623111d3835b0673d5ec88eb5c42d32..c9dee9a663b9a404ba5a7696b4a1df462944ea7f 100644
|
| --- a/src/codec/SkJpegCodec.cpp
|
| +++ b/src/codec/SkJpegCodec.cpp
|
| @@ -155,14 +155,28 @@ static int get_row_bytes(const j_decompress_ptr dinfo) {
|
| return dinfo->output_width * colorBytes;
|
|
|
| }
|
| +
|
| +/*
|
| + * Calculate output dimensions based on the provided factors.
|
| + *
|
| + * Not to be used on the actual jpeg_decompress_struct used for decoding, since it will
|
| + * incorrectly modify num_components.
|
| + */
|
| +void calc_output_dimensions(jpeg_decompress_struct* dinfo, unsigned int num, unsigned int denom) {
|
| + dinfo->num_components = 0;
|
| + dinfo->scale_num = num;
|
| + dinfo->scale_denom = denom;
|
| + jpeg_calc_output_dimensions(dinfo);
|
| +}
|
| +
|
| /*
|
| * Return a valid set of output dimensions for this decoder, given an input scale
|
| */
|
| SkISize SkJpegCodec::onGetScaledDimensions(float desiredScale) const {
|
| // libjpeg-turbo supports scaling by 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, and 1/1, so we will
|
| // support these as well
|
| - long num;
|
| - long denom = 8;
|
| + unsigned int num;
|
| + unsigned int denom = 8;
|
| if (desiredScale > 0.875f) {
|
| num = 8;
|
| } else if (desiredScale > 0.75f) {
|
| @@ -187,10 +201,7 @@ SkISize SkJpegCodec::onGetScaledDimensions(float desiredScale) const {
|
| dinfo.image_width = this->getInfo().width();
|
| dinfo.image_height = this->getInfo().height();
|
| dinfo.global_state = fReadyState;
|
| - dinfo.num_components = 0;
|
| - dinfo.scale_num = num;
|
| - dinfo.scale_denom = denom;
|
| - jpeg_calc_output_dimensions(&dinfo);
|
| + calc_output_dimensions(&dinfo, num, denom);
|
|
|
| // Return the calculated output dimensions for the given scale
|
| return SkISize::Make(dinfo.output_width, dinfo.output_height);
|
| @@ -272,28 +283,40 @@ bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dst) {
|
| * Checks if we can natively scale to the requested dimensions and natively scales the
|
| * dimensions if possible
|
| */
|
| -bool SkJpegCodec::nativelyScaleToDimensions(uint32_t dstWidth, uint32_t dstHeight) {
|
| +bool SkJpegCodec::onDimensionsSupported(const SkISize& size) {
|
| + if (setjmp(fDecoderMgr->getJmpBuf())) {
|
| + return fDecoderMgr->returnFalse("onDimensionsSupported/setjmp");
|
| + }
|
| +
|
| + const unsigned int dstWidth = size.width();
|
| + const unsigned int dstHeight = size.height();
|
| +
|
| + // Set up a fake decompress struct in order to use libjpeg to calculate output dimensions
|
| + // FIXME: Why is this necessary?
|
| + jpeg_decompress_struct dinfo;
|
| + sk_bzero(&dinfo, sizeof(dinfo));
|
| + dinfo.image_width = this->getInfo().width();
|
| + dinfo.image_height = this->getInfo().height();
|
| + dinfo.global_state = fReadyState;
|
| +
|
| // libjpeg-turbo can scale to 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, and 1/1
|
| - fDecoderMgr->dinfo()->scale_denom = 8;
|
| - fDecoderMgr->dinfo()->scale_num = 8;
|
| - jpeg_calc_output_dimensions(fDecoderMgr->dinfo());
|
| - while (fDecoderMgr->dinfo()->output_width != dstWidth ||
|
| - fDecoderMgr->dinfo()->output_height != dstHeight) {
|
| + unsigned int num = 8;
|
| + const unsigned int denom = 8;
|
| + calc_output_dimensions(&dinfo, num, denom);
|
| + while (dinfo.output_width != dstWidth || dinfo.output_height != dstHeight) {
|
|
|
| // Return a failure if we have tried all of the possible scales
|
| - if (1 == fDecoderMgr->dinfo()->scale_num ||
|
| - dstWidth > fDecoderMgr->dinfo()->output_width ||
|
| - dstHeight > fDecoderMgr->dinfo()->output_height) {
|
| - // reset native scale settings on failure because this may be supported by the swizzler
|
| - this->fDecoderMgr->dinfo()->scale_num = 8;
|
| - jpeg_calc_output_dimensions(this->fDecoderMgr->dinfo());
|
| + if (1 == num || dstWidth > dinfo.output_width || dstHeight > dinfo.output_height) {
|
| return false;
|
| }
|
|
|
| // Try the next scale
|
| - fDecoderMgr->dinfo()->scale_num -= 1;
|
| - jpeg_calc_output_dimensions(fDecoderMgr->dinfo());
|
| + num -= 1;
|
| + calc_output_dimensions(&dinfo, num, denom);
|
| }
|
| +
|
| + fDecoderMgr->dinfo()->scale_num = num;
|
| + fDecoderMgr->dinfo()->scale_denom = denom;
|
| return true;
|
| }
|
|
|
| @@ -321,11 +344,6 @@ SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo,
|
| return fDecoderMgr->returnFailure("conversion_possible", kInvalidConversion);
|
| }
|
|
|
| - // Perform the necessary scaling
|
| - if (!this->nativelyScaleToDimensions(dstInfo.width(), dstInfo.height())) {
|
| - return fDecoderMgr->returnFailure("cannot scale to requested dims", kInvalidScale);
|
| - }
|
| -
|
| // Now, given valid output dimensions, we can start the decompress
|
| if (!jpeg_start_decompress(dinfo)) {
|
| return fDecoderMgr->returnFailure("startDecompress", kInvalidInput);
|
| @@ -376,7 +394,13 @@ SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo,
|
| return kSuccess;
|
| }
|
|
|
| -SkCodec::Result SkJpegCodec::initializeSwizzler(const SkImageInfo& info, const Options& options) {
|
| +SkSampler* SkJpegCodec::getSampler() {
|
| + if (fSwizzler) {
|
| + SkASSERT(fSrcRow && static_cast<uint8_t*>(fStorage.get()) == fSrcRow);
|
| + return fSwizzler;
|
| + }
|
| +
|
| + const SkImageInfo& info = this->dstInfo();
|
| SkSwizzler::SrcConfig srcConfig;
|
| switch (info.colorType()) {
|
| case kGray_8_SkColorType:
|
| @@ -396,13 +420,15 @@ SkCodec::Result SkJpegCodec::initializeSwizzler(const SkImageInfo& info, const O
|
| SkASSERT(false);
|
| }
|
|
|
| - fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, info, options.fZeroInitialized,
|
| - this->getInfo()));
|
| + fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, info,
|
| + this->options().fZeroInitialized));
|
| if (!fSwizzler) {
|
| - return SkCodec::kUnimplemented;
|
| + return nullptr;
|
| }
|
|
|
| - return kSuccess;
|
| + fStorage.reset(get_row_bytes(fDecoderMgr->dinfo()));
|
| + fSrcRow = static_cast<uint8_t*>(fStorage.get());
|
| + return fSwizzler;
|
| }
|
|
|
| SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
|
| @@ -418,25 +444,10 @@ SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
|
| return kInvalidConversion;
|
| }
|
|
|
| - // Perform the necessary scaling
|
| - if (!this->nativelyScaleToDimensions(dstInfo.width(), dstInfo.height())) {
|
| - // full native scaling to dstInfo dimensions not supported
|
| -
|
| - if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) {
|
| - return kInvalidScale;
|
| - }
|
| - // create swizzler for sampling
|
| - Result result = this->initializeSwizzler(dstInfo, options);
|
| - if (kSuccess != result) {
|
| - SkCodecPrintf("failed to initialize the swizzler.\n");
|
| - return result;
|
| - }
|
| - fStorage.reset(get_row_bytes(fDecoderMgr->dinfo()));
|
| - fSrcRow = static_cast<uint8_t*>(fStorage.get());
|
| - } else {
|
| - fSrcRow = nullptr;
|
| - fSwizzler.reset(nullptr);
|
| - }
|
| + // Remove objects used for sampling.
|
| + fSwizzler.reset(nullptr);
|
| + fSrcRow = nullptr;
|
| + fStorage.free();
|
|
|
| // Now, given valid output dimensions, we can start the decompress
|
| if (!jpeg_start_decompress(fDecoderMgr->dinfo())) {
|
|
|