diff options
author | 2015-08-14 07:44:46 -0700 | |
---|---|---|
committer | 2015-08-14 07:44:46 -0700 | |
commit | 8f4ba76742c329bc4d5e1b8ca376d27922bd00b1 (patch) | |
tree | ee3b69a6972cb3e16e4c0e85723477bea9dd5387 /src/codec/SkJpegCodec.cpp | |
parent | 1bef9f59c566cc54c2259cc4d0171c115157cd1c (diff) |
SkScaledCodec class
This class does scaling by using a scanlineDecoder.
getScanlines and skipScanlines are used for y sampling,
the swizzler is used for x sampling
this class is currently only working for png and jpeg images
I will update other Codec types to work soon
For SkJpegCodec to implement width wise swizzling it now
uses a swizzler. I ran performance tests on this change.
Here are the performance test results:
https://docs.google.com/a/google.com/spreadsheets/d/1D7-Q_GXD_dI68LZO005NNvb8Wq2Ee0wEBEPG72671yw/edit?usp=sharing
BUG=skia:
Committed: https://skia.googlesource.com/skia/+/0944100ac89f797714eeae0cf2875e2335ff52ee
Committed: https://skia.googlesource.com/skia/+/d518ea7927f9f4e0ed5b4134d1b4f48243855a47
Committed: https://skia.googlesource.com/skia/+/b157917507d4f7d2651f0aeb566d31603cc02240
Review URL: https://codereview.chromium.org/1260673002
Diffstat (limited to 'src/codec/SkJpegCodec.cpp')
-rw-r--r-- | src/codec/SkJpegCodec.cpp | 117 |
1 files changed, 100 insertions, 17 deletions
diff --git a/src/codec/SkJpegCodec.cpp b/src/codec/SkJpegCodec.cpp index 83656da42d..c094d50a3b 100644 --- a/src/codec/SkJpegCodec.cpp +++ b/src/codec/SkJpegCodec.cpp @@ -11,6 +11,7 @@ #include "SkJpegUtility_codec.h" #include "SkCodecPriv.h" #include "SkColorPriv.h" +#include "SkScaledCodec.h" #include "SkScanlineDecoder.h" #include "SkStream.h" #include "SkTemplates.h" @@ -149,6 +150,14 @@ SkJpegCodec::SkJpegCodec(const SkImageInfo& srcInfo, SkStream* stream, {} /* + * Return the row bytes of a particular image type and width + */ +static int get_row_bytes(const j_decompress_ptr dinfo) { + int colorBytes = (dinfo->out_color_space == JCS_RGB565) ? 2 : dinfo->out_color_components; + return dinfo->output_width * colorBytes; + +} +/* * Return a valid set of output dimensions for this decoder, given an input scale */ SkISize SkJpegCodec::onGetScaledDimensions(float desiredScale) const { @@ -258,10 +267,10 @@ bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dst) { } /* - * Checks if we can scale to the requested dimensions and scales the dimensions - * if possible + * Checks if we can natively scale to the requested dimensions and natively scales the + * dimensions if possible */ -bool SkJpegCodec::scaleToDimensions(uint32_t dstWidth, uint32_t dstHeight) { +bool SkJpegCodec::nativelyScaleToDimensions(uint32_t dstWidth, uint32_t dstHeight) { // 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; @@ -273,7 +282,10 @@ bool SkJpegCodec::scaleToDimensions(uint32_t dstWidth, uint32_t dstHeight) { if (1 == fDecoderMgr->dinfo()->scale_num || dstWidth > fDecoderMgr->dinfo()->output_width || dstHeight > fDecoderMgr->dinfo()->output_height) { - return fDecoderMgr->returnFalse("could not scale to requested dimensions"); + // reset native scale settings on failure because this may be supported by the swizzler + this->fDecoderMgr->dinfo()->scale_num = 8; + chromium_jpeg_calc_output_dimensions(this->fDecoderMgr->dinfo()); + return false; } // Try the next scale @@ -313,7 +325,7 @@ SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo, } // Perform the necessary scaling - if (!this->scaleToDimensions(dstInfo.width(), dstInfo.height())) { + if (!this->nativelyScaleToDimensions(dstInfo.width(), dstInfo.height())) { return fDecoderMgr->returnFailure("cannot scale to requested dims", kInvalidScale); } @@ -381,6 +393,47 @@ public: , fOpts() {} + /* + * Return a valid set of output dimensions for this decoder, given an input scale + */ + SkISize onGetScaledDimensions(float desiredScale) override { + return fCodec->onGetScaledDimensions(desiredScale); + } + + /* + * Create the swizzler based on the encoded format. + * The swizzler is only used for sampling in the x direction. + */ + + SkCodec::Result initializeSwizzler(const SkImageInfo& info, const SkCodec::Options& options) { + SkSwizzler::SrcConfig srcConfig; + switch (info.colorType()) { + case kGray_8_SkColorType: + srcConfig = SkSwizzler::kGray; + break; + case kRGBA_8888_SkColorType: + srcConfig = SkSwizzler::kRGBX; + break; + case kBGRA_8888_SkColorType: + srcConfig = SkSwizzler::kBGRX; + break; + case kRGB_565_SkColorType: + srcConfig = SkSwizzler::kRGB_565; + break; + default: + //would have exited before now if the colorType was supported by jpeg + SkASSERT(false); + } + + fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, NULL, info, options.fZeroInitialized, + this->getInfo())); + if (!fSwizzler) { + // FIXME: CreateSwizzler could fail for another reason. + return SkCodec::kUnimplemented; + } + return SkCodec::kSuccess; + } + SkCodec::Result onStart(const SkImageInfo& dstInfo, const SkCodec::Options& options, SkPMColor ctable[], int* ctableCount) override { @@ -401,8 +454,23 @@ public: } // Perform the necessary scaling - if (!fCodec->scaleToDimensions(dstInfo.width(), dstInfo.height())) { - return SkCodec::kInvalidScale; + if (!fCodec->nativelyScaleToDimensions(dstInfo.width(), dstInfo.height())) { + // full native scaling to dstInfo dimensions not supported + + if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) { + return SkCodec::kInvalidScale; + } + // create swizzler for sampling + SkCodec::Result result = this->initializeSwizzler(dstInfo, options); + if (SkCodec::kSuccess != result) { + SkCodecPrintf("failed to initialize the swizzler.\n"); + return result; + } + fStorage.reset(get_row_bytes(fCodec->fDecoderMgr->dinfo())); + fSrcRow = static_cast<uint8_t*>(fStorage.get()); + } else { + fSrcRow = NULL; + fSwizzler.reset(NULL); } // Now, given valid output dimensions, we can start the decompress @@ -433,9 +501,16 @@ public: if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvalidInput); } - // Read rows one at a time - JSAMPLE* dstRow = (JSAMPLE*) dst; + JSAMPLE* dstRow; + if (fSwizzler) { + // write data to storage row, then sample using swizzler + dstRow = fSrcRow; + } else { + // write data directly to dst + dstRow = (JSAMPLE*) dst; + } + for (int y = 0; y < count; y++) { // Read row of the image uint32_t rowsDecoded = @@ -452,13 +527,17 @@ public: // Convert to RGBA if necessary if (JCS_CMYK == fCodec->fDecoderMgr->dinfo()->out_color_space) { - convert_CMYK_to_RGBA(dstRow, this->dstInfo().width()); + convert_CMYK_to_RGBA(dstRow, fCodec->fDecoderMgr->dinfo()->output_width); } - // Move to the next row - dstRow = SkTAddOffset<JSAMPLE>(dstRow, rowBytes); + if(fSwizzler) { + // use swizzler to sample row + fSwizzler->swizzle(dst, dstRow); + dst = SkTAddOffset<JSAMPLE>(dst, rowBytes); + } else { + dstRow = SkTAddOffset<JSAMPLE>(dstRow, rowBytes); + } } - return SkCodec::kSuccess; } @@ -466,7 +545,7 @@ public: // TODO (msarett): Make this a member function and avoid reallocating the // memory buffer on each call to skip. #define chromium_jpeg_skip_scanlines(dinfo, count) \ - SkAutoMalloc storage(dinfo->output_width * dinfo->out_color_components); \ + SkAutoMalloc storage(get_row_bytes(dinfo)); \ uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); \ for (int y = 0; y < count; y++) { \ chromium_jpeg_read_scanlines(dinfo, &storagePtr, 1); \ @@ -484,13 +563,16 @@ public: return SkCodec::kSuccess; } -#ifndef TURBO_HAS_SKIP -#undef chromium_jpeg_skip_scanlines -#endif + SkEncodedFormat onGetEncodedFormat() const override { + return kJPEG_SkEncodedFormat; + } private: SkAutoTDelete<SkJpegCodec> fCodec; + SkAutoMalloc fStorage; // Only used if sampling is needed + uint8_t* fSrcRow; // Only used if sampling is needed SkCodec::Options fOpts; + SkAutoTDelete<SkSwizzler> fSwizzler; typedef SkScanlineDecoder INHERITED; }; @@ -502,6 +584,7 @@ SkScanlineDecoder* SkJpegCodec::NewSDFromStream(SkStream* stream) { } const SkImageInfo& srcInfo = codec->getInfo(); + // Return the new scanline decoder return SkNEW_ARGS(SkJpegScanlineDecoder, (srcInfo, codec.detach())); } |