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

Side by Side Diff: src/codec/SkScaledCodec.cpp

Issue 1260673002: SkScaledCodec class (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Fix sampleSize rounding error by creating SampleSize struct 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 unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkCodecPriv.h"
9 #include "SkScaledCodec.h"
10 #include "SkStream.h"
11 #include "SkWebpCodec.h"
12
13
14 SkCodec* SkScaledCodec::NewFromStream(SkStream* stream) {
15 bool isWebp = SkWebpCodec::IsWebp(stream);
16 if (!stream->rewind()) {
17 return NULL;
18 }
19 if (isWebp) {
20 // Webp codec supports scaling and subsetting natively
21 return SkWebpCodec::NewFromStream(stream);
22 }
23
24 SkAutoTDelete<SkScanlineDecoder> scanlineDecoder(SkScanlineDecoder::NewFromS tream(stream));
25 if (NULL == scanlineDecoder) {
26 return NULL;
27 }
28
29 // wrap in new SkScaledCodec
30 return SkNEW_ARGS(SkScaledCodec, (scanlineDecoder.detach()));
31 }
32
33 SkCodec* SkScaledCodec::NewFromData(SkData* data) {
34 if (!data) {
35 return NULL;
36 }
37 return NewFromStream(SkNEW_ARGS(SkMemoryStream, (data)));
38 }
39
40 SkScaledCodec::SkScaledCodec(SkScanlineDecoder* scanlineDecoder)
41 : INHERITED(scanlineDecoder->getInfo(), NULL)
42 , fScanlineDecoder(scanlineDecoder)
43 {}
44
45 SkScaledCodec::~SkScaledCodec() {}
46
47 static SkISize best_scaled_dimensions(const SkISize& origDims, const SkISize& na tiveDims,
48 const SkISize& scaledCodecDims, float desi redScale) {
49 if (nativeDims == scaledCodecDims) {
50 // does not matter which to return if equal. Return here to skip below c alculations
51 return nativeDims;
52 }
53 float idealWidth = origDims.width() * desiredScale;
54 float idealHeight = origDims.height() * desiredScale;
55
56 // calculate difference between native dimensions and ideal dimensions
57 float nativeWDiff = SkTAbs(idealWidth - nativeDims.width());
58 float nativeHDiff = SkTAbs(idealHeight - nativeDims.height());
59 float nativeDiff = (nativeWDiff + nativeHDiff) / 2;
60
61 // calculate difference between scaledCodec dimensions and ideal dimensions
62 float scaledCodecWDiff = SkTAbs(idealWidth - scaledCodecDims.width());
63 float scaledCodecHDiff = SkTAbs(idealHeight - scaledCodecDims.height());
64 float scaledCodecDiff = (scaledCodecWDiff + scaledCodecHDiff) / 2;
65
66 // return dimensions closest to ideal dimensions.
67 // If the differences are equal, return nativeDims, as native scaling is mor e efficient.
68 return nativeDiff > scaledCodecDiff ? scaledCodecDims : nativeDims;
69
70 }
71 /*
72 * Return a valid set of output dimensions for this decoder, given an input scal e
73 */
74 SkISize SkScaledCodec::onGetScaledDimensions(float desiredScale) const {
75 SkISize nativeDimensions = fScanlineDecoder->getScaledDimensions(desiredScal e);
76 // support scaling down by integer numbers. Ex: 1/2, 1/3, 1/4 ...
77 SkISize scaledCodecDimensions;
78 if (desiredScale > 0.5f) {
79 // sampleSize = 1
80 scaledCodecDimensions = fScanlineDecoder->getInfo().dimensions();
81 }
82 // sampleSize determines the step size between samples
83 // Ex: sampleSize = 2, sample every second pixel in x and y directions
84 int sampleSize = int(1 / desiredScale);
85
86 int scaledWidth = getScaledDimension(this->getInfo().width(), sampleSize);
87 int scaledHeight = getScaledDimension(this->getInfo().height(), sampleSize);
88
89 // Return the calculated output dimensions for the given scale
90 scaledCodecDimensions = SkISize::Make(scaledWidth, scaledHeight);
91
92 return best_scaled_dimensions(this->getInfo().dimensions(), nativeDimensions ,
93 scaledCodecDimensions, desiredScale);
94 }
95
96 // check if scaling to dstInfo size from srcInfo size using sampleSize is possib le
97 static bool scaling_supported(const SkScaledCodec::SampleSize& sampleSize,
scroggo 2015/08/13 16:10:45 It seems a little odd to me that you pass a Sample
emmaleer 2015/08/13 17:49:11 This function is still necessary, as when we call
scroggo 2015/08/13 18:01:21 What if you did the following: static bool scalin
98 const SkImageInfo& dstInfo, const SkImageInfo& sr cInfo) {
99 const int dstWidth = dstInfo.width();
100 const int dstHeight = dstInfo.height();
101 const int srcWidth = srcInfo.width();
102 const int srcHeight = srcInfo.height();
103 // only support down sampling, not up sampling
104 if (dstWidth > srcWidth || dstHeight > srcHeight) {
105 return false;
106 }
107 // check that srcWidth is scaled down by an integer value
108 if (SkScaledCodec::getScaledDimension(srcWidth, sampleSize.sampleX) != dstW idth) {
109 return false;
110 }
111 // check that src height is scaled down by an integer value
112 if (SkScaledCodec::getScaledDimension(srcHeight, sampleSize.sampleY) != dst Height) {
113 return false;
114 }
115 // sampleX and sampleY should be equal unless the original sampleSize reque sted was larger
116 // than srcWidth or srcHeight. If so, the result of this is dstWidth or dst Height = 1.
117 // This functionality allows for tall thin images to still be scaled down b y scaling factors.
118 if (sampleSize.sampleX != sampleSize.sampleY){
119 if (1 != dstWidth && 1 != dstHeight) {
120 return false;
121 }
122 }
123 return true;
124 }
125
126 // TODO: Implement subsetting in onGetPixels which works when and when not sampl ing
127
128 SkCodec::Result SkScaledCodec::onGetPixels(const SkImageInfo& requestedInfo, voi d* dst,
129 size_t rowBytes, const Options& optio ns,
130 SkPMColor ctable[], int* ctableCount) {
131
132 if (options.fSubset) {
133 // Subsets are not supported.
134 return kUnimplemented;
135 }
136
137 Result result = fScanlineDecoder->start(requestedInfo, &options, ctable, cta bleCount);
138 if (kSuccess == result) {
139 // native decode supported
140 return fScanlineDecoder->getScanlines(dst, requestedInfo.height(), rowBy tes);
141
142 }
143
144 if (kInvalidScale != result) {
145 // no scaling requested
146 return result;
147 }
148
149 // scaling requested
150 SampleSize sampleSize(fScanlineDecoder->getInfo(), requestedInfo);
151 if (!scaling_supported(sampleSize, requestedInfo, fScanlineDecoder->getInfo( ))) {
152 return kInvalidScale;
153 }
154
155 int dstHeight = requestedInfo.height();
156 int srcHeight = fScanlineDecoder->getInfo().height();
157
158 // set sample values in y direction
159 int sampleY = sampleSize.sampleY;
160 int Y0 = sampleY >> 1;
161
162 SkImageInfo info = requestedInfo;
163 // use original height as scanlineDecoder does not support y sampling native ly
164 info = info.makeWH(requestedInfo.width(), srcHeight);
165
166 // update scanlineDecoder with new info
167 result = fScanlineDecoder->start(info, &options, ctable, ctableCount);
168 if (kSuccess != result) {
169 return result;
170 }
171
172 const bool requiresPostYSampling = fScanlineDecoder->requiresPostYSampling() ;
173
174 if (requiresPostYSampling) {
175 SkAutoMalloc storage(srcHeight * rowBytes);
176 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get());
177 result = fScanlineDecoder->getScanlines(storagePtr, srcHeight, rowBytes) ;
178 if (kSuccess != result) {
179 return result;
180 }
181 storagePtr += Y0 * rowBytes;
182 for (int y = 0; y < dstHeight; y++) {
183 memcpy(dst, storagePtr, rowBytes);
184 storagePtr += sampleY * rowBytes;
185 dst = SkTAddOffset<void>(dst, rowBytes);
186 }
187 } else {
188 // does not require post y sampling
189 result = fScanlineDecoder->skipScanlines(Y0);
190 if (kSuccess != result) {
191 return result;
192 }
193 for (int y = 0; y < dstHeight; y++) {
194 result = fScanlineDecoder->getScanlines(dst, 1, rowBytes);
195 if (kSuccess != result) {
196 return result;
197 }
198 if (y < dstHeight - 1) {
199 result = fScanlineDecoder->skipScanlines(sampleY - 1);
200 if (kSuccess != result) {
201 return result;
202 }
203 }
204 dst = SkTAddOffset<void>(dst, rowBytes);
205 }
206 }
207 return kSuccess;
208 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698