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

Unified Diff: src/codec/SkScaledCodec.cpp

Issue 1260673002: SkScaledCodec class (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: 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..30b048c06a97729881e048a28e9c598ddd62523b
--- /dev/null
+++ b/src/codec/SkScaledCodec.cpp
@@ -0,0 +1,158 @@
+/*
+ * 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"
+
+
+SkCodec* SkScaledCodec::NewFromStream(SkStream* stream) {
+ SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream));
scroggo 2015/07/27 15:09:19 This should be indented only four characters. A l
emmaleer 2015/07/27 18:31:38 Yes, it's usually set to 4 spaced per indent.. I t
+ if (NULL == codec) {
+ return NULL;
+ }
+ return SkNEW_ARGS(SkScaledCodec, (codec.detach()));
scroggo 2015/07/27 15:09:19 Since SkWebpCodec supports subsets and scaling nat
emmaleer 2015/07/27 18:31:38 Acknowledged.
+}
+
+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
+ * TODO: This should be the default implementation once the other codecs support this.
scroggo 2015/07/27 15:09:19 This TODO is no longer needed.
emmaleer 2015/07/27 18:31:38 Acknowledged.
+ */
+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());
+
+ 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;
+}
+
+SkCodec::Result SkScaledCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst,
+ size_t rowBytes, const Options& options,
+ SkPMColor ctable[], int* ctableCount) {
+
+ Result result = fCodec->getPixels(requestedInfo, dst, rowBytes, &options, ctable, ctableCount);
+ if (kInvalidScale != result) {
scroggo 2015/07/27 15:09:19 I wonder if there are other cases this should hand
emmaleer 2015/07/27 18:31:38 Maybe we should add a return value of kInvalidSubs
scroggo 2015/07/27 19:29:57 Yes. This is currently supported by BitmapRegionDe
emmaleer 2015/07/28 14:19:16 Acknowledged.
+ // no scaling requested
+ return result;
+ }
+ // scaling requested
+
+ if (!scaling_supported(requestedInfo, fCodec->getInfo())) {
+ return kInvalidScale;
+ }
+
+ bool isInterlaced = fCodec->isInterlaced();
+ Options scaledOptions = options;
+ scaledOptions.fScaled = true;
+
+ int dstHeight = requestedInfo.height();
+ int srcHeight = fCodec->getInfo().height();
+
+ SkImageInfo info = requestedInfo;
+ if (isInterlaced){
+ // must decode entire height for interlaced, then scale after
+ info = info.makeWH(requestedInfo.width(), srcHeight);
+ }
+
+ SkAutoTDelete<SkScanlineDecoder> scanlineDecoder(fCodec->getScanlineDecoder(info,
+ &scaledOptions, ctable, ctableCount));
+ if (NULL == scanlineDecoder) {
+ SkCodecPrintf("failed to create scanline decoder.\n");
+ return kInvalidInput;
+ }
+
+ // set sample values in x and y directions
+ fSampleY = srcHeight / dstHeight;
+ fY0 = fSampleY >> 1;
+ int sampleX = fCodec->getInfo().width() / requestedInfo.width();
+ if (!scanlineDecoder->setSampleX(sampleX)) {
+ return kInvalidScale;
+ }
+
+ if (!isInterlaced) {
scroggo 2015/07/27 15:09:19 nit: I tend to prefer: if (condition) { } else {
emmaleer 2015/07/27 18:31:38 Acknowledged.
+ scanlineDecoder->skipScanlines(fY0);
+ for (int y = 0; y < dstHeight; y++) {
+ scanlineDecoder->getScanlines(dst, 1, rowBytes);
+ if (y < dstHeight - 1) {
+ scanlineDecoder->skipScanlines(fSampleY - 1);
+ }
+ dst += rowBytes;
+ }
+ } else {
+ // interlaced
+ SkAutoMalloc storage(srcHeight * rowBytes);
+ void* storagePtr = storage.get();
+ result = scanlineDecoder->getScanlines(storagePtr, srcHeight, rowBytes);
+
+ storagePtr += fY0 * rowBytes;
+ for (int y = 0; y < dstHeight; y++) {
+ memcpy(dst, storagePtr, rowBytes);
+ storagePtr += fSampleY * rowBytes;
+ dst += rowBytes;
+ }
+ }
+ return kSuccess;
+}

Powered by Google App Engine
This is Rietveld 408576698