Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(72)

Unified Diff: src/codec/SkJpegCodec.cpp

Issue 1260673002: SkScaledCodec class (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Make SkScaledCodec constructor explicit Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/codec/SkJpegCodec.cpp
diff --git a/src/codec/SkJpegCodec.cpp b/src/codec/SkJpegCodec.cpp
index 84e90d444249142d69a68cd52cab59cebb37c30a..c1ae545b1c7cd4d7c10977a47308b8d1bca7a55b 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"
@@ -146,6 +147,8 @@ SkJpegCodec::SkJpegCodec(const SkImageInfo& srcInfo, SkStream* stream,
JpegDecoderMgr* decoderMgr)
: INHERITED(srcInfo, stream)
, fDecoderMgr(decoderMgr)
+ , fPartialNum(1)
+ , fPartialDenom(1)
{}
/*
@@ -189,6 +192,44 @@ SkISize SkJpegCodec::onGetScaledDimensions(float desiredScale) const {
return SkISize::Make(dinfo.output_width, dinfo.output_height);
}
+// The swizzler is only used for sampling in the x direction
+// when sampling a scanlineDecoder is used. The swizzler is not used in onGetPixels
+SkCodec::Result SkJpegCodec::initializeSwizzler(const SkImageInfo& requestedInfo,
+ void* dst, size_t rowBytes,
+ const Options& options,
+ SkPMColor ctable[],
+ int* ctableCount,
+ int srcWidth) {
+
+ const SkColorType srcColorType = requestedInfo.colorType();
+ SkSwizzler::SrcConfig srcConfig;
+ switch (srcColorType) {
+ 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, requestedInfo,
+ options.fZeroInitialized, srcWidth));
+ if (!fSwizzler) {
+ // FIXME: CreateSwizzler could fail for another reason.
+ return kUnimplemented;
+ }
+ return kSuccess;
+}
+
/*
* Handles rewinding the input stream if it is necessary
*/
@@ -272,10 +313,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;
@@ -287,7 +328,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;
+ turbo_jpeg_calc_output_dimensions(this->fDecoderMgr->dinfo());
+ return false;
}
// Try the next scale
@@ -297,6 +341,37 @@ bool SkJpegCodec::scaleToDimensions(uint32_t dstWidth, uint32_t dstHeight) {
return true;
}
+int SkJpegCodec::onPartiallyNativelyScale(float desiredScale) {
msarett 2015/08/04 20:39:36 I think this function is clever :)
+ float nativeScales[7] = {0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875};
scroggo 2015/08/04 20:05:21 nit: I think these can (should?) be static const (
emmaleer 2015/08/05 14:47:51 Acknowledged.
+ int numerators[7] = {1, 1, 3, 1, 5, 3, 7};
+ int denomonators[7] = {8, 4, 8, 2, 8, 4, 8};
+
+ int index = 0;
+ int sampleSize = 1;
+ float totalScale = nativeScales[index] / sampleSize;
scroggo 2015/08/04 20:05:21 Can this just be "nativeScales[0]"? Or do you thi
emmaleer 2015/08/05 14:47:51 Yes, it can just be gNativeScales[0]
+
+ while(totalScale != desiredScale) {
scroggo 2015/08/04 20:05:21 nit: there should be a space between while and (
emmaleer 2015/08/05 14:47:51 Acknowledged.
+ if (totalScale < desiredScale) {
+ // scaling too much, scale less natively
+ if (index == 7) {
+ // have tried all possible combinations, partial native scaling not supported
+ return -1;
+ }
+ index++;
+ } else {
+ // not scaling enough, scale more by increasing sampleSize
+ sampleSize++;
+ }
+ totalScale = nativeScales[index] / sampleSize;
+ }
+
+ // partial native scaling supported
+ fPartialDenom = denomonators[index];
+ fPartialNum = numerators[index];
+
+ return sampleSize;
+}
+
/*
* Performs the jpeg decode
*/
@@ -327,7 +402,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);
}
@@ -394,7 +469,15 @@ public:
: INHERITED(dstInfo)
, fCodec(codec)
, fOpts(opts)
- {}
+ {
+ if(fCodec->fSwizzler) {
+ fStorage.reset(codec->fDecoderMgr->dinfo()->output_width *
msarett 2015/08/04 20:39:36 This will always be enough, but is overkill in the
emmaleer 2015/08/05 14:47:51 Acknowledged.
+ codec->fDecoderMgr->dinfo()->out_color_components);
+ fSrcRow = static_cast<uint8_t*>(fStorage.get());
+ } else {
+ fSrcRow = NULL;
+ }
+ }
virtual ~SkJpegScanlineDecoder() {
if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) {
@@ -413,9 +496,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 (fCodec->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 =
@@ -432,13 +522,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);
msarett 2015/08/04 20:39:36 Nice!
}
- // Move to the next row
- dstRow = SkTAddOffset<JSAMPLE>(dstRow, rowBytes);
+ if(fCodec->fSwizzler) {
+ // use swizzler to sample row
+ fCodec->fSwizzler->swizzle(dst, dstRow);
+ dst = SkTAddOffset<JSAMPLE>(dst, rowBytes);
+ } else {
+ dstRow = SkTAddOffset<JSAMPLE>(dstRow, rowBytes);
+ }
}
-
return SkCodec::kSuccess;
}
@@ -464,6 +558,8 @@ public:
private:
SkAutoTDelete<SkJpegCodec> fCodec;
+ SkAutoMalloc fStorage; // Only used if sampling is needed
+ uint8_t* fSrcRow; // Only used if sampling is needed
const SkCodec::Options& fOpts;
typedef SkScanlineDecoder INHERITED;
@@ -499,10 +595,34 @@ SkScanlineDecoder* SkJpegCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo,
return NULL;
}
+ SkImageInfo scaledInfo = dstInfo;
+
// Perform the necessary scaling
- if (!codec->scaleToDimensions(dstInfo.width(), dstInfo.height())) {
- SkCodecPrintf("Cannot scale to output dimensions\n");
- return NULL;
+ if (!codec->nativelyScaleToDimensions(dstInfo.width(), dstInfo.height())) {
+ // full native scaling to dstInfo dimensions not supported
+
+ if (fPartialNum != 1 || fPartialDenom != 1) {
+ // update num and denom as partiallyNativelyScale was previously called
msarett 2015/08/04 20:39:36 Ah this is the part where we are unhappy. We need
+ codec->fDecoderMgr->dinfo()->scale_denom = fPartialDenom;
+ codec->fDecoderMgr->dinfo()->scale_num = fPartialNum;
+ turbo_jpeg_calc_output_dimensions(codec->fDecoderMgr->dinfo());
+
+ // update scanlineDecoder's info to reflect partial native scaling
+ scaledInfo = dstInfo.makeWH(codec->fDecoderMgr->dinfo()->output_width,
+ codec->fDecoderMgr->dinfo()->output_height);
+ } else {
+ // no native scaling (full or partial) supported
+ if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) {
+ return NULL;
+ }
+ }
+ // create swizzler for sampling
+ if (codec->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), options, ctable,
+ ctableCount, codec->fDecoderMgr->dinfo()->output_width)
+ != kSuccess) {
+ SkCodecPrintf("failed to initialize the swizzler.\n");
+ return NULL;
+ }
}
// Now, given valid output dimensions, we can start the decompress
@@ -512,5 +632,5 @@ SkScanlineDecoder* SkJpegCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo,
}
// Return the new scanline decoder
- return SkNEW_ARGS(SkJpegScanlineDecoder, (dstInfo, codec.detach(), options));
+ return SkNEW_ARGS(SkJpegScanlineDecoder, (scaledInfo, codec.detach(), options));
}

Powered by Google App Engine
This is Rietveld 408576698