diff options
Diffstat (limited to 'src/codec/SkJpegCodec.cpp')
-rw-r--r-- | src/codec/SkJpegCodec.cpp | 278 |
1 files changed, 114 insertions, 164 deletions
diff --git a/src/codec/SkJpegCodec.cpp b/src/codec/SkJpegCodec.cpp index 4557e45673..dac0c17b77 100644 --- a/src/codec/SkJpegCodec.cpp +++ b/src/codec/SkJpegCodec.cpp @@ -12,7 +12,6 @@ #include "SkCodecPriv.h" #include "SkColorPriv.h" #include "SkScaledCodec.h" -#include "SkScanlineDecoder.h" #include "SkStream.h" #include "SkTemplates.h" #include "SkTypes.h" @@ -382,160 +381,136 @@ SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo, return kSuccess; } -/* - * Enable scanline decoding for jpegs - */ -class SkJpegScanlineDecoder : public SkScanlineDecoder { -public: - SkJpegScanlineDecoder(const SkImageInfo& srcInfo, SkJpegCodec* codec) - : INHERITED(srcInfo) - , fCodec(codec) - , fOpts() - {} - - /* - * Return a valid set of output dimensions for this decoder, given an input scale - */ - SkISize onGetScaledDimensions(float desiredScale) override { - return fCodec->onGetScaledDimensions(desiredScale); +SkCodec::Result SkJpegCodec::initializeSwizzler(const SkImageInfo& info, const 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: + // This function should only be called if the colorType is supported by jpeg + SkASSERT(false); } - /* - * 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, nullptr, info, options.fZeroInitialized, - this->getInfo())); - if (!fSwizzler) { - // FIXME: CreateSwizzler could fail for another reason. - return SkCodec::kUnimplemented; - } - return SkCodec::kSuccess; + fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, info, options.fZeroInitialized, + this->getInfo())); + if (!fSwizzler) { + return SkCodec::kUnimplemented; } - SkCodec::Result onStart(const SkImageInfo& dstInfo, const SkCodec::Options& options, - SkPMColor ctable[], int* ctableCount) override { + return kSuccess; +} - // Rewind the stream if needed - if (!fCodec->rewindIfNeeded()) { - return SkCodec::kCouldNotRewind; - } +SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, + const Options& options, SkPMColor ctable[], int* ctableCount) { + // Rewind the stream if needed + if (!this->rewindIfNeeded()) { + return kCouldNotRewind; + } - // Set the jump location for libjpeg errors - if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { - SkCodecPrintf("setjmp: Error from libjpeg\n"); - return SkCodec::kInvalidInput; - } + // Set the jump location for libjpeg errors + if (setjmp(fDecoderMgr->getJmpBuf())) { + SkCodecPrintf("setjmp: Error from libjpeg\n"); + return kInvalidInput; + } - // Check if we can decode to the requested destination and set the output color space - if (!fCodec->setOutputColorSpace(dstInfo)) { - return SkCodec::kInvalidConversion; - } + // Check if we can decode to the requested destination and set the output color space + if (!this->setOutputColorSpace(dstInfo)) { + return kInvalidConversion; + } - // Perform the necessary scaling - if (!fCodec->nativelyScaleToDimensions(dstInfo.width(), dstInfo.height())) { - // full native scaling to dstInfo dimensions not supported + // 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 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 = nullptr; - fSwizzler.reset(nullptr); + if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) { + return kInvalidScale; } - - // Now, given valid output dimensions, we can start the decompress - if (!jpeg_start_decompress(fCodec->fDecoderMgr->dinfo())) { - SkCodecPrintf("start decompress failed\n"); - return SkCodec::kInvalidInput; + // 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); + } + + // Now, given valid output dimensions, we can start the decompress + if (!jpeg_start_decompress(fDecoderMgr->dinfo())) { + SkCodecPrintf("start decompress failed\n"); + return kInvalidInput; + } - fOpts = options; + return kSuccess; +} - return SkCodec::kSuccess; +SkJpegCodec::~SkJpegCodec() { + // FIXME: This probably does not need to be called after a full decode + // FIXME: Is it safe to call when it doesn't need to be called? + if (setjmp(fDecoderMgr->getJmpBuf())) { + SkCodecPrintf("setjmp: Error in libjpeg finish_decompress\n"); + return; } - virtual ~SkJpegScanlineDecoder() { - if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { - SkCodecPrintf("setjmp: Error in libjpeg finish_decompress\n"); - return; - } + // We may not have decoded the entire image. Prevent libjpeg-turbo from failing on a + // partial decode. + fDecoderMgr->dinfo()->output_scanline = this->getInfo().height(); + jpeg_finish_decompress(fDecoderMgr->dinfo()); +} - // We may not have decoded the entire image. Prevent libjpeg-turbo from failing on a - // partial decode. - fCodec->fDecoderMgr->dinfo()->output_scanline = fCodec->getInfo().height(); - jpeg_finish_decompress(fCodec->fDecoderMgr->dinfo()); +SkCodec::Result SkJpegCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { + // Set the jump location for libjpeg errors + if (setjmp(fDecoderMgr->getJmpBuf())) { + return fDecoderMgr->returnFailure("setjmp", kInvalidInput); + } + // Read rows one at a time + JSAMPLE* dstRow; + if (fSwizzler) { + // write data to storage row, then sample using swizzler + dstRow = fSrcRow; + } else { + // write data directly to dst + dstRow = (JSAMPLE*) dst; } - SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) override { - // Set the jump location for libjpeg errors - if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { - return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvalidInput); - } - // Read rows one at a time - 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 = jpeg_read_scanlines(fDecoderMgr->dinfo(), &dstRow, 1); + if (rowsDecoded != 1) { + SkSwizzler::Fill(dstRow, this->dstInfo(), rowBytes, count - y, + SK_ColorBLACK, nullptr, this->options().fZeroInitialized); + fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height(); + return kIncompleteInput; } - for (int y = 0; y < count; y++) { - // Read row of the image - uint32_t rowsDecoded = jpeg_read_scanlines(fCodec->fDecoderMgr->dinfo(), &dstRow, 1); - if (rowsDecoded != 1) { - SkSwizzler::Fill(dstRow, this->dstInfo(), rowBytes, count - y, - SK_ColorBLACK, nullptr, fOpts.fZeroInitialized); - fCodec->fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height(); - return SkCodec::kIncompleteInput; - } - - // Convert to RGBA if necessary - if (JCS_CMYK == fCodec->fDecoderMgr->dinfo()->out_color_space) { - convert_CMYK_to_RGBA(dstRow, fCodec->fDecoderMgr->dinfo()->output_width); - } + // Convert to RGBA if necessary + if (JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) { + convert_CMYK_to_RGBA(dstRow, fDecoderMgr->dinfo()->output_width); + } - if(fSwizzler) { - // use swizzler to sample row - fSwizzler->swizzle(dst, dstRow); - dst = SkTAddOffset<JSAMPLE>(dst, rowBytes); - } else { - 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; } + return kSuccess; +} #ifndef TURBO_HAS_SKIP // TODO (msarett): Make this a member function and avoid reallocating the @@ -548,39 +523,14 @@ public: } #endif - SkCodec::Result onSkipScanlines(int count) override { - // Set the jump location for libjpeg errors - if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) { - return fCodec->fDecoderMgr->returnFailure("setjmp", SkCodec::kInvalidInput); - } - - jpeg_skip_scanlines(fCodec->fDecoderMgr->dinfo(), count); - - return SkCodec::kSuccess; - } - - 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; -}; - -SkScanlineDecoder* SkJpegCodec::NewSDFromStream(SkStream* stream) { - SkAutoTDelete<SkJpegCodec> codec(static_cast<SkJpegCodec*>(SkJpegCodec::NewFromStream(stream))); - if (!codec) { - return nullptr; +SkCodec::Result SkJpegCodec::onSkipScanlines(int count) { + // Set the jump location for libjpeg errors + if (setjmp(fDecoderMgr->getJmpBuf())) { + return fDecoderMgr->returnFailure("setjmp", kInvalidInput); } - const SkImageInfo& srcInfo = codec->getInfo(); + jpeg_skip_scanlines(fDecoderMgr->dinfo(), count); - // Return the new scanline decoder - return new SkJpegScanlineDecoder(srcInfo, codec.detach()); + return kSuccess; } + |