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

Unified Diff: src/codec/SkScaledCodec.cpp

Issue 1260673002: SkScaledCodec class (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Works for jpeg images Created 5 years, 5 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/SkScaledCodec.cpp
diff --git a/src/codec/SkScaledCodec.cpp b/src/codec/SkScaledCodec.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a68310ceb854f054620eed89ebe37b2e6ebe8e68
--- /dev/null
+++ b/src/codec/SkScaledCodec.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCodecPriv.h"
+#include "SkScaledCodec.h"
+#include "SkStream.h"
+#include "SkWebpCodec.h"
+
+
+SkCodec* SkScaledCodec::NewFromStream(SkStream* stream) {
+ SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream));
+ if (NULL == codec) {
+ return NULL;
+ }
+ if (codec->getEncodedFormat() == SkEncodedFormat::kWEBP_SkEncodedFormat) {
+ // Webp codec supports scaling and subsetting natively
+ return codec.detach();
+ }
+ // wrap in new SkScaledCodec
+ return SkNEW_ARGS(SkScaledCodec, (codec.detach()));
+}
+
+SkCodec* SkScaledCodec::NewFromData(SkData* data) {
+ if (!data) {
+ return NULL;
+ }
+ return NewFromStream(SkNEW_ARGS(SkMemoryStream, (data)));
+}
+
+SkScaledCodec::SkScaledCodec(SkCodec* codec)
+ : INHERITED(codec->getInfo(), NULL)
+ , fCodec(codec)
+{}
+
+SkScaledCodec::~SkScaledCodec() {}
+
+/*
+ * Return a valid set of output dimensions for this decoder, given an input scale
+ */
+SkISize SkScaledCodec::onGetScaledDimensions(float desiredScale) const {
+ // support scaling down by integer numbers. Ex: 1/2, 1/3, 1/4 ...
+
+ if (desiredScale > 0.5f) {
+ // sampleSize = 1
+ return fCodec->getInfo().dimensions();
+ }
+ // sampleSize determines the step size between samples
+ // Ex: sampleSize = 2, sample every second pixel in x and y directions
+ int sampleSize = 1 / desiredScale;
+
+ // if sampleSize > width or height, will only sample 1 pixel in that direction
+ int sampleX = SkMin32(sampleSize, this->getInfo().width());
+ int sampleY = SkMin32(sampleSize, this->getInfo().height());
+
+ // NOTE: we round down here for scaledWidth and scaledHeight
+ // Can be changed in the future to round up, or round to closest integer if we want
msarett 2015/07/30 13:55:38 I think Leon made a good point here. I would say
emmaleer 2015/07/30 17:50:39 Okay, I've create the function get_scaled_dimensio
+ int scaledWidth = this->getInfo().width() / sampleX;
+ int scaledHeight = this->getInfo().height() / sampleY;
+
+ // Return the calculated output dimensions for the given scale
+ return SkISize::Make(scaledWidth, scaledHeight);
+}
+
+// check if scaling to dstInfo size from srcInfo size is possible
+static bool scaling_supported(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo){
+ const int dstWidth = dstInfo.width();
+ const int dstHeight = dstInfo.height();
+ const int srcWidth = srcInfo.width();
+ const int srcHeight = srcInfo.height();
+ // only support down sampling, not up sampling
+ if (dstWidth > srcWidth || dstHeight > srcHeight) {
+ return false;
+ }
+ // check that srcWidth is scaled down by an integer value
+ int sampleSizeX = srcWidth / dstWidth;
+ if (srcWidth / sampleSizeX != dstWidth) {
+ return false;
+ }
+ // check that src height is scaled down by an integer value
+ int sampleSizeY = srcHeight / dstHeight;
+ if (srcHeight / sampleSizeY != dstHeight) {
+ return false;
+ }
+ // sampleX and sampleY should be equal unless the original sampleSize requested was larger
+ // than srcWidth or srcHeight. If so, the result of this is dstWidth or dstHeight = 1.
+ // This functionality allows for tall thin images to still be scaled down by scaling factors.
+ if (sampleSizeX != sampleSizeY){
+ if (1 != dstWidth && 1 != dstHeight) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// TODO: Implement subsetting in onGetPixels which works when and when not sampling
+
+SkCodec::Result SkScaledCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst,
+ size_t rowBytes, const Options& options,
+ SkPMColor ctable[], int* ctableCount) {
+
+ // try to do a fCodec native decode, as some types of code support scaling and subsetting
+ Result result = fCodec->getPixels(requestedInfo, dst, rowBytes, &options, ctable, ctableCount);
+ if (kInvalidScale != result) {
+ // no scaling requested
+ return result;
+ }
+ // scaling requested
+ if (!scaling_supported(requestedInfo, fCodec->getInfo())) {
+ return kInvalidScale;
+ }
+
+ int dstHeight = requestedInfo.height();
+ int srcHeight = fCodec->getInfo().height();
+
+ // set sample values in x and y directions
+ int sampleY = srcHeight / dstHeight;
+ int Y0 = sampleY >> 1;
+
+ SkImageInfo info = requestedInfo;
+ // use original height as scanlineDecoder does not support y sampling natively
+ info = info.makeWH(requestedInfo.width(), srcHeight);
+
+ SkAutoTDelete<SkScanlineDecoder> scanlineDecoder(fCodec->getScanlineDecoder(info,
+ &options, ctable, ctableCount));
+ if (NULL == scanlineDecoder) {
+ SkCodecPrintf("failed to create scanline decoder.\n");
+ return kInvalidInput;
+ }
+
+ bool isHardToSample = scanlineDecoder->isHardToSample();
+
+ if (isHardToSample) {
+ SkAutoMalloc storage(srcHeight * rowBytes);
+ void* storagePtr = storage.get();
+ scanlineDecoder->getScanlines(storagePtr, srcHeight, rowBytes);
scroggo 2015/07/30 17:53:01 In one sense, this is correct, to remove result if
emmaleer 2015/07/30 22:27:56 Acknowledged.
+
+ storagePtr += Y0 * rowBytes;
+ for (int y = 0; y < dstHeight; y++) {
+ memcpy(dst, storagePtr, rowBytes);
+ storagePtr += sampleY * rowBytes;
+ dst += rowBytes;
+ }
+ } else {
+ // not interlaced
msarett 2015/07/30 13:55:38 nit: change comment
emmaleer 2015/07/30 17:50:39 Acknowledged.
+ scanlineDecoder->skipScanlines(Y0);
+ for (int y = 0; y < dstHeight; y++) {
+ scanlineDecoder->getScanlines(dst, 1, rowBytes);
+ if (y < dstHeight - 1) {
+ scanlineDecoder->skipScanlines(sampleY - 1);
+ }
+ dst += rowBytes;
+ }
+ }
+ return kSuccess;
+}

Powered by Google App Engine
This is Rietveld 408576698