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

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 error caused by adding to void pointer 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 = 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 is possible
106 static bool scaling_supported(const SkImageInfo& dstInfo, const SkImageInfo& sr cInfo){
107 const int dstWidth = dstInfo.width();
108 const int dstHeight = dstInfo.height();
109 const int srcWidth = srcInfo.width();
110 const int srcHeight = srcInfo.height();
111 // only support down sampling, not up sampling
112 if (dstWidth > srcWidth || dstHeight > srcHeight) {
113 return false;
114 }
115 // check that srcWidth is scaled down by an integer value
116 int sampleSizeX = SkScaledCodec::GetSampleSize(srcWidth, dstWidth);
117 if (get_scaled_dimension(srcWidth, sampleSizeX) != dstWidth) {
118 return false;
119 }
120 // check that src height is scaled down by an integer value
121 int sampleSizeY = SkScaledCodec::GetSampleSize(srcHeight, dstHeight);
122 if (get_scaled_dimension(srcHeight, sampleSizeY) != 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 (sampleSizeX != sampleSizeY){
129 if (1 != dstWidth && 1 != dstHeight) {
130 return false;
131 }
132 }
133 return true;
134 }
135
136 // TODO: Implement subsetting in onGetPixels which works when and when not sampl ing
137
138 SkCodec::Result SkScaledCodec::onGetPixels(const SkImageInfo& requestedInfo, voi d* dst,
139 size_t rowBytes, const Options& optio ns,
140 SkPMColor ctable[], int* ctableCount) {
141
142 if (options.fSubset) {
143 // Subsets are not supported.
144 return kUnimplemented;
145 }
146
147 Result result = fScanlineDecoder->start(requestedInfo, &options, ctable, cta bleCount);
148 if (kSuccess == result) {
149 // native decode supported
150 return fScanlineDecoder->getScanlines(dst, requestedInfo.height(), rowBy tes);
151
152 }
153
154 if (kInvalidScale != result) {
155 // no scaling requested
156 return result;
157 }
158
159 // scaling requested
160 if (!scaling_supported(requestedInfo, fScanlineDecoder->getInfo())) {
161 return kInvalidScale;
162 }
163
164 int dstHeight = requestedInfo.height();
165 int srcHeight = fScanlineDecoder->getInfo().height();
166
167 // set sample values in x and y directions
168 int sampleY = GetSampleSize(srcHeight, dstHeight);
169 int Y0 = sampleY >> 1;
170
171 SkImageInfo info = requestedInfo;
172 // use original height as scanlineDecoder does not support y sampling native ly
173 info = info.makeWH(requestedInfo.width(), srcHeight);
174
175 // update scanlineDecoder with new info
176 result = fScanlineDecoder->start(info, &options, ctable, ctableCount);
177 if (kSuccess != result) {
178 return result;
179 }
180
181 const bool requiresPostYSampling = fScanlineDecoder->requiresPostYSampling() ;
182
183 if (requiresPostYSampling) {
184 SkAutoMalloc storage(srcHeight * rowBytes);
185 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get());
186 result = fScanlineDecoder->getScanlines(storagePtr, srcHeight, rowBytes) ;
187 if (kSuccess != result) {
188 return result;
189 }
190 uint8_t* dstRow = static_cast<uint8_t*>(dst);
191 storagePtr += Y0 * rowBytes;
192 for (int y = 0; y < dstHeight; y++) {
193 memcpy(dstRow, storagePtr, rowBytes);
194 storagePtr += sampleY * rowBytes;
195 dstRow += rowBytes;
scroggo 2015/08/12 21:49:26 You could also do: dstRow = SkTAddOffset<>(dstRow
emmaleer 2015/08/12 22:19:20 Acknowledged.
196 }
197 } else {
198 // does not require post y sampling
199 result = fScanlineDecoder->skipScanlines(Y0);
200 if (kSuccess != result) {
201 return result;
202 }
203 for (int y = 0; y < dstHeight; y++) {
204 result = fScanlineDecoder->getScanlines(dst, 1, rowBytes);
205 if (kSuccess != result) {
206 return result;
207 }
208 if (y < dstHeight - 1) {
209 result = fScanlineDecoder->skipScanlines(sampleY - 1);
210 if (kSuccess != result) {
211 return result;
212 }
213 }
214 dst += rowBytes;
215 }
216 }
217 return kSuccess;
218 }
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