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

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

Issue 1260673002: SkScaledCodec class (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Stop DM from running large interlaced images on 32-bit Ubuntu GCE bots b/c they are running out of … 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
« no previous file with comments | « src/codec/SkJpegCodec.cpp ('k') | src/codec/SkSwizzler.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // returns a scaled dimension based on the original dimension and the sampleSize
48 // NOTE: we round down here for scaled dimension to match the behavior of SkImag eDecoder
49 static int get_scaled_dimension(int srcDimension, int sampleSize) {
50 if (sampleSize > srcDimension) {
51 return 1;
52 }
53 return srcDimension / sampleSize;
54 }
55
56 static SkISize best_scaled_dimensions(const SkISize& origDims, const SkISize& na tiveDims,
57 const SkISize& scaledCodecDims, float desi redScale) {
58 if (nativeDims == scaledCodecDims) {
59 // does not matter which to return if equal. Return here to skip below c alculations
60 return nativeDims;
61 }
62 float idealWidth = origDims.width() * desiredScale;
63 float idealHeight = origDims.height() * desiredScale;
64
65 // calculate difference between native dimensions and ideal dimensions
66 float nativeWDiff = SkTAbs(idealWidth - nativeDims.width());
67 float nativeHDiff = SkTAbs(idealHeight - nativeDims.height());
68 float nativeDiff = (nativeWDiff + nativeHDiff) / 2;
69
70 // calculate difference between scaledCodec dimensions and ideal dimensions
71 float scaledCodecWDiff = SkTAbs(idealWidth - scaledCodecDims.width());
72 float scaledCodecHDiff = SkTAbs(idealHeight - scaledCodecDims.height());
73 float scaledCodecDiff = (scaledCodecWDiff + scaledCodecHDiff) / 2;
74
75 // return dimensions closest to ideal dimensions.
76 // If the differences are equal, return nativeDims, as native scaling is mor e efficient.
77 return nativeDiff > scaledCodecDiff ? scaledCodecDims : nativeDims;
78
79 }
80 /*
81 * Return a valid set of output dimensions for this decoder, given an input scal e
82 */
83 SkISize SkScaledCodec::onGetScaledDimensions(float desiredScale) const {
84 SkISize nativeDimensions = fScanlineDecoder->getScaledDimensions(desiredScal e);
85 // support scaling down by integer numbers. Ex: 1/2, 1/3, 1/4 ...
86 SkISize scaledCodecDimensions;
87 if (desiredScale > 0.5f) {
88 // sampleSize = 1
89 scaledCodecDimensions = fScanlineDecoder->getInfo().dimensions();
90 }
91 // sampleSize determines the step size between samples
92 // Ex: sampleSize = 2, sample every second pixel in x and y directions
93 int sampleSize = int(1 / desiredScale);
94
95 int scaledWidth = get_scaled_dimension(this->getInfo().width(), sampleSize);
96 int scaledHeight = get_scaled_dimension(this->getInfo().height(), sampleSize );
97
98 // Return the calculated output dimensions for the given scale
99 scaledCodecDimensions = SkISize::Make(scaledWidth, scaledHeight);
100
101 return best_scaled_dimensions(this->getInfo().dimensions(), nativeDimensions ,
102 scaledCodecDimensions, desiredScale);
103 }
104
105 // check if scaling to dstInfo size from srcInfo size using sampleSize is possib le
106 static bool scaling_supported(const SkImageInfo& dstInfo, const SkImageInfo& src Info,
107 int* sampleX, int* sampleY) {
108 SkScaledCodec::ComputeSampleSize(dstInfo, srcInfo, sampleX, sampleY);
109 const int dstWidth = dstInfo.width();
110 const int dstHeight = dstInfo.height();
111 const int srcWidth = srcInfo.width();
112 const int srcHeight = srcInfo.height();
113 // only support down sampling, not up sampling
114 if (dstWidth > srcWidth || dstHeight > srcHeight) {
115 return false;
116 }
117 // check that srcWidth is scaled down by an integer value
118 if (get_scaled_dimension(srcWidth, *sampleX) != dstWidth) {
119 return false;
120 }
121 // check that src height is scaled down by an integer value
122 if (get_scaled_dimension(srcHeight, *sampleY) != dstHeight) {
123 return false;
124 }
125 // sampleX and sampleY should be equal unless the original sampleSize reques ted was larger
126 // than srcWidth or srcHeight. If so, the result of this is dstWidth or dstH eight = 1.
127 // This functionality allows for tall thin images to still be scaled down by scaling factors.
128 if (*sampleX != *sampleY){
129 if (1 != dstWidth && 1 != dstHeight) {
130 return false;
131 }
132 }
133 return true;
134 }
135
136 // calculates sampleSize in x and y direction
137 void SkScaledCodec::ComputeSampleSize(const SkImageInfo& dstInfo, const SkImageI nfo& srcInfo,
138 int* sampleXPtr, int* sampleYPtr) {
139 int srcWidth = srcInfo.width();
140 int dstWidth = dstInfo.width();
141 int srcHeight = srcInfo.height();
142 int dstHeight = dstInfo.height();
143
144 int sampleX = srcWidth / dstWidth;
145 int sampleY = srcHeight / dstHeight;
146
147 // only support down sampling, not up sampling
148 SkASSERT(dstWidth <= srcWidth);
149 SkASSERT(dstHeight <= srcHeight);
150
151 // sampleX and sampleY should be equal unless the original sampleSize reques ted was
152 // larger than srcWidth or srcHeight.
153 // If so, the result of this is dstWidth or dstHeight = 1. This functionalit y
154 // allows for tall thin images to still be scaled down by scaling factors.
155
156 if (sampleX != sampleY){
157 if (1 != dstWidth && 1 != dstHeight) {
158
159 // rounding during onGetScaledDimensions can cause different sampleS izes
160 // Ex: srcWidth = 79, srcHeight = 20, sampleSize = 10
161 // dstWidth = 7, dstHeight = 2, sampleX = 79/7 = 11, sampleY = 20/2 = 10
162 // correct for this rounding by comparing width to sampleY and heigh t to sampleX
163
164 if (get_scaled_dimension(srcWidth, sampleY) == dstWidth) {
165 sampleX = sampleY;
166 } else if (get_scaled_dimension(srcHeight, sampleX) == dstHeight) {
167 sampleY = sampleX;
168 }
169 }
170 }
171
172 if (sampleXPtr) {
173 *sampleXPtr = sampleX;
174 }
175 if (sampleYPtr) {
176 *sampleYPtr = sampleY;
177 }
178 }
179
180 // TODO: Implement subsetting in onGetPixels which works when and when not sampl ing
181
182 SkCodec::Result SkScaledCodec::onGetPixels(const SkImageInfo& requestedInfo, voi d* dst,
183 size_t rowBytes, const Options& optio ns,
184 SkPMColor ctable[], int* ctableCount) {
185
186 if (options.fSubset) {
187 // Subsets are not supported.
188 return kUnimplemented;
189 }
190
191 Result result = fScanlineDecoder->start(requestedInfo, &options, ctable, cta bleCount);
192 if (kSuccess == result) {
193 // native decode supported
194 return fScanlineDecoder->getScanlines(dst, requestedInfo.height(), rowBy tes);
195
196 }
197
198 if (kInvalidScale != result) {
199 // no scaling requested
200 return result;
201 }
202
203 // scaling requested
204 int sampleX;
205 int sampleY;
206 if (!scaling_supported(requestedInfo, fScanlineDecoder->getInfo(), &sampleX, &sampleY)) {
207 return kInvalidScale;
208 }
209 // set first sample pixel in y direction
210 int Y0 = sampleY >> 1;
211
212 int dstHeight = requestedInfo.height();
213 int srcHeight = fScanlineDecoder->getInfo().height();
214
215 SkImageInfo info = requestedInfo;
216 // use original height as scanlineDecoder does not support y sampling native ly
217 info = info.makeWH(requestedInfo.width(), srcHeight);
218
219 // update scanlineDecoder with new info
220 result = fScanlineDecoder->start(info, &options, ctable, ctableCount);
221 if (kSuccess != result) {
222 return result;
223 }
224
225 const bool requiresPostYSampling = fScanlineDecoder->requiresPostYSampling() ;
226
227 if (requiresPostYSampling) {
228 SkAutoMalloc storage(srcHeight * rowBytes);
229 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get());
230 result = fScanlineDecoder->getScanlines(storagePtr, srcHeight, rowBytes) ;
231 if (kSuccess != result) {
232 return result;
233 }
234 storagePtr += Y0 * rowBytes;
235 for (int y = 0; y < dstHeight; y++) {
236 memcpy(dst, storagePtr, rowBytes);
237 storagePtr += sampleY * rowBytes;
238 dst = SkTAddOffset<void>(dst, rowBytes);
239 }
240 } else {
241 // does not require post y sampling
242 result = fScanlineDecoder->skipScanlines(Y0);
243 if (kSuccess != result) {
244 return result;
245 }
246 for (int y = 0; y < dstHeight; y++) {
247 result = fScanlineDecoder->getScanlines(dst, 1, rowBytes);
248 if (kSuccess != result) {
249 return result;
250 }
251 if (y < dstHeight - 1) {
252 result = fScanlineDecoder->skipScanlines(sampleY - 1);
253 if (kSuccess != result) {
254 return result;
255 }
256 }
257 dst = SkTAddOffset<void>(dst, rowBytes);
258 }
259 }
260 return kSuccess;
261 }
OLDNEW
« no previous file with comments | « src/codec/SkJpegCodec.cpp ('k') | src/codec/SkSwizzler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698