OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkCodec.h" | 8 #include "SkCodec.h" |
9 #include "SkCodecPriv.h" | 9 #include "SkCodecPriv.h" |
10 #include "SkMath.h" | |
10 #include "SkSampledCodec.h" | 11 #include "SkSampledCodec.h" |
11 | 12 |
13 #include <initializer_list> | |
14 | |
12 SkSampledCodec::SkSampledCodec(SkCodec* codec) | 15 SkSampledCodec::SkSampledCodec(SkCodec* codec) |
13 : INHERITED(codec->getInfo()) | 16 : INHERITED(codec->getInfo()) |
14 , fCodec(codec) | 17 , fCodec(codec) |
15 {} | 18 {} |
16 | 19 |
17 SkISize SkSampledCodec::onGetSampledDimensions(int sampleSize) const { | 20 SkISize SkSampledCodec::accountForNativeScaling(int* sampleSizePtr, int* nativeS ampleSize) const { |
21 SkISize preSampledSize = fCodec->getInfo().dimensions(); | |
22 int sampleSize = *sampleSizePtr; | |
23 if (nativeSampleSize) { | |
24 *nativeSampleSize = 1; | |
25 } | |
26 | |
18 // Fast path for when we are not scaling. | 27 // Fast path for when we are not scaling. |
19 if (1 == sampleSize) { | 28 if (1 == sampleSize) { |
20 return fCodec->getInfo().dimensions(); | 29 return preSampledSize; |
21 } | 30 } |
22 | 31 |
23 const int width = fCodec->getInfo().width(); | 32 // Only JPEG supports native downsampling. |
24 const int height = fCodec->getInfo().height(); | 33 if (fCodec->getEncodedFormat() == kJPEG_SkEncodedFormat) { |
msarett
2015/10/29 22:36:33
Admitting that we know a little bit about the inte
scroggo_chromium
2015/11/02 21:22:10
We can certainly consider adding this elsewhere, b
| |
34 // See if libjpeg supports this scale directly | |
35 switch (sampleSize) { | |
36 case 2: | |
37 case 4: | |
38 case 8: | |
39 // This class does not need to do any sampling. | |
40 *sampleSizePtr = 1; | |
41 return fCodec->getScaledDimensions(get_scale_from_sample_size(sa mpleSize)); | |
42 default: | |
43 break; | |
44 } | |
25 | 45 |
26 // Check if the codec can provide the scaling natively. | 46 // Check if sampleSize is a multiple of something libjpeg can support. |
msarett
2015/10/29 22:36:33
I'm quite happy that this block of code is gone.
scroggo_chromium
2015/11/02 21:22:10
Haha, yeah, I think the new code is much cleaner.
| |
27 float scale = get_scale_from_sample_size(sampleSize); | 47 int remainder; |
28 SkSize idealSize = SkSize::Make(scale * (float) width, scale * (float) heigh t); | 48 for (int supportedSampleSize : { 8 , 4 , 2 }) { |
29 SkISize nativeSize = fCodec->getScaledDimensions(scale); | 49 int actualSampleSize; |
30 float widthDiff = SkTAbs(((float) nativeSize.width()) - idealSize.width()); | 50 SkTDivMod(sampleSize, supportedSampleSize, &actualSampleSize, &remai nder); |
31 float heightDiff = SkTAbs(((float) nativeSize.height()) - idealSize.height() ); | 51 if (0 == remainder) { |
32 // Native scaling is preferred to sampling. If we can scale natively to | 52 float scale = get_scale_from_sample_size(supportedSampleSize); |
33 // within one of the ideal value, we should choose to scale natively. | 53 |
34 if (widthDiff < 1.0f && heightDiff < 1.0f) { | 54 // fCodec will scale to this size. |
35 return nativeSize; | 55 preSampledSize = fCodec->getScaledDimensions(scale); |
56 | |
57 // And then this class will sample it. | |
58 *sampleSizePtr = actualSampleSize; | |
59 if (nativeSampleSize) { | |
60 *nativeSampleSize = supportedSampleSize; | |
61 } | |
62 break; | |
63 } | |
64 } | |
36 } | 65 } |
37 | 66 |
38 // Provide the scaling by sampling. | 67 return preSampledSize; |
39 return SkISize::Make(get_scaled_dimension(width, sampleSize), | 68 } |
40 get_scaled_dimension(height, sampleSize)); | 69 |
70 SkISize SkSampledCodec::onGetSampledDimensions(int sampleSize) const { | |
71 // FIXME: Should this (or the baseclass) check for sample size of 1? | |
72 // I guess it would be a dumb client to call with sampleSize of 1... | |
msarett
2015/10/29 22:36:33
I think it's worth thinking about. We call this w
scroggo_chromium
2015/11/02 21:22:10
Well, that makes a good point. If we don't special
| |
73 const SkISize size = this->accountForNativeScaling(&sampleSize); | |
74 return SkISize::Make(get_scaled_dimension(size.width(), sampleSize), | |
75 get_scaled_dimension(size.height(), sampleSize)); | |
41 } | 76 } |
42 | 77 |
43 SkCodec::Result SkSampledCodec::onGetAndroidPixels(const SkImageInfo& info, void * pixels, | 78 SkCodec::Result SkSampledCodec::onGetAndroidPixels(const SkImageInfo& info, void * pixels, |
44 size_t rowBytes, AndroidOptions& options) { | 79 size_t rowBytes, AndroidOptions& options) { |
45 // Create an Options struct for the codec. | 80 // Create an Options struct for the codec. |
46 SkCodec::Options codecOptions; | 81 SkCodec::Options codecOptions; |
47 codecOptions.fZeroInitialized = options.fZeroInitialized; | 82 codecOptions.fZeroInitialized = options.fZeroInitialized; |
48 | 83 |
49 SkIRect* subset = options.fSubset; | 84 SkIRect* subset = options.fSubset; |
50 if (!subset || subset->size() == fCodec->getInfo().dimensions()) { | 85 if (!subset || subset->size() == fCodec->getInfo().dimensions()) { |
51 if (fCodec->dimensionsSupported(info.dimensions())) { | 86 if (fCodec->dimensionsSupported(info.dimensions())) { |
52 return fCodec->getPixels(info, pixels, rowBytes, &codecOptions, opti ons.fColorPtr, | 87 return fCodec->getPixels(info, pixels, rowBytes, &codecOptions, opti ons.fColorPtr, |
53 options.fColorCount); | 88 options.fColorCount); |
54 } | 89 } |
55 | 90 |
56 // If the native codec does not support the requested scale, scale by sa mpling. | 91 // If the native codec does not support the requested scale, scale by sa mpling. |
57 return this->sampledDecode(info, pixels, rowBytes, options); | 92 return this->sampledDecode(info, pixels, rowBytes, options); |
58 } | 93 } |
59 | 94 |
60 // We are performing a subset decode. | 95 // We are performing a subset decode. |
61 int sampleSize = options.fSampleSize; | 96 int sampleSize = options.fSampleSize; |
97 // FIXME: Can we avoid redoing this? | |
msarett
2015/10/29 22:36:33
I don't think that this is a redo.
We only make t
scroggo_chromium
2015/11/02 21:22:10
Good point. Removed.
| |
62 SkISize scaledSize = this->onGetSampledDimensions(sampleSize); | 98 SkISize scaledSize = this->onGetSampledDimensions(sampleSize); |
63 if (!fCodec->dimensionsSupported(scaledSize)) { | 99 if (!fCodec->dimensionsSupported(scaledSize)) { |
64 // If the native codec does not support the requested scale, scale by sa mpling. | 100 // If the native codec does not support the requested scale, scale by sa mpling. |
65 return this->sampledDecode(info, pixels, rowBytes, options); | 101 return this->sampledDecode(info, pixels, rowBytes, options); |
66 } | 102 } |
67 | 103 |
68 // Calculate the scaled subset bounds. | 104 // Calculate the scaled subset bounds. |
69 int scaledSubsetX = subset->x() / sampleSize; | 105 int scaledSubsetX = subset->x() / sampleSize; |
70 int scaledSubsetY = subset->y() / sampleSize; | 106 int scaledSubsetY = subset->y() / sampleSize; |
71 int scaledSubsetWidth = info.width(); | 107 int scaledSubsetWidth = info.width(); |
(...skipping 28 matching lines...) Expand all Loading... | |
100 } | 136 } |
101 default: | 137 default: |
102 SkASSERT(false); | 138 SkASSERT(false); |
103 return SkCodec::kUnimplemented; | 139 return SkCodec::kUnimplemented; |
104 } | 140 } |
105 } | 141 } |
106 | 142 |
107 | 143 |
108 SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix els, | 144 SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix els, |
109 size_t rowBytes, AndroidOptions& options) { | 145 size_t rowBytes, AndroidOptions& options) { |
146 // We should only call this function when sampling. | |
147 SkASSERT(options.fSampleSize > 1); | |
148 | |
110 // Create options struct for the codec. | 149 // Create options struct for the codec. |
111 SkCodec::Options sampledOptions; | 150 SkCodec::Options sampledOptions; |
112 sampledOptions.fZeroInitialized = options.fZeroInitialized; | 151 sampledOptions.fZeroInitialized = options.fZeroInitialized; |
113 | 152 |
153 // FIXME: This was already called by onGetAndroidPixels. Can we reduce that? | |
msarett
2015/10/29 22:36:33
If we are performing a subset decode, we have alre
| |
154 int sampleSize = options.fSampleSize; | |
155 int nativeSampleSize; | |
156 SkISize nativeSize = this->accountForNativeScaling(&sampleSize, &nativeSampl eSize); | |
157 | |
114 // Check if there is a subset. | 158 // Check if there is a subset. |
115 SkIRect subset; | 159 SkIRect subset; |
116 int subsetY = 0; | 160 int subsetY = 0; |
117 int subsetWidth = fCodec->getInfo().width(); | 161 int subsetWidth = nativeSize.width(); |
118 int subsetHeight = fCodec->getInfo().height(); | 162 int subsetHeight = nativeSize.height(); |
119 if (options.fSubset) { | 163 if (options.fSubset) { |
120 // We will need to know about subsetting in the y-dimension in order to use the | 164 // We will need to know about subsetting in the y-dimension in order to use the |
121 // scanline decoder. | 165 // scanline decoder. |
166 // Update the subset to account for scaling done by fCodec. | |
122 SkIRect* subsetPtr = options.fSubset; | 167 SkIRect* subsetPtr = options.fSubset; |
123 subsetY = subsetPtr->y(); | 168 |
124 subsetWidth = subsetPtr->width(); | 169 // Do the divide ourselves, instead of calling get_scaled_dimension. If |
125 subsetHeight = subsetPtr->height(); | 170 // X and Y are 0, they should remain 0, rather than being upgraded to 1 |
171 // due to being smaller than the sampleSize. | |
172 const int subsetX = subsetPtr->x() / nativeSampleSize; | |
173 subsetY = subsetPtr->y() / nativeSampleSize; | |
174 | |
175 subsetWidth = get_scaled_dimension(subsetPtr->width(), nativeSampleSize) ; | |
176 subsetHeight = get_scaled_dimension(subsetPtr->height(), nativeSampleSiz e); | |
126 | 177 |
127 // The scanline decoder only needs to be aware of subsetting in the x-di mension. | 178 // The scanline decoder only needs to be aware of subsetting in the x-di mension. |
128 subset.setXYWH(subsetPtr->x(), 0, subsetWidth, fCodec->getInfo().height( )); | 179 subset.setXYWH(subsetX, 0, subsetWidth, nativeSize.height()); |
129 sampledOptions.fSubset = ⊂ | 180 sampledOptions.fSubset = ⊂ |
130 } | 181 } |
131 | 182 |
132 // Start the scanline decode. | 183 // Start the scanline decode. |
133 SkCodec::Result result = fCodec->startScanlineDecode( | 184 SkCodec::Result result = fCodec->startScanlineDecode( |
134 info.makeWH(fCodec->getInfo().width(), fCodec->getInfo().height()), &sampledOptions, | 185 info.makeWH(nativeSize.width(), nativeSize.height()), &sampledOption s, |
135 options.fColorPtr, options.fColorCount); | 186 options.fColorPtr, options.fColorCount); |
136 if (SkCodec::kSuccess != result) { | 187 if (SkCodec::kSuccess != result) { |
137 return result; | 188 return result; |
138 } | 189 } |
139 | 190 |
140 SkSampler* sampler = fCodec->getSampler(true); | 191 SkSampler* sampler = fCodec->getSampler(true); |
141 if (!sampler) { | 192 if (!sampler) { |
142 return SkCodec::kUnimplemented; | 193 return SkCodec::kUnimplemented; |
143 } | 194 } |
144 | 195 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
203 // fCodec has already handled filling uninitialized memory. | 254 // fCodec has already handled filling uninitialized memory. |
204 return SkCodec::kIncompleteInput; | 255 return SkCodec::kIncompleteInput; |
205 } | 256 } |
206 return SkCodec::kSuccess; | 257 return SkCodec::kSuccess; |
207 } | 258 } |
208 default: | 259 default: |
209 SkASSERT(false); | 260 SkASSERT(false); |
210 return SkCodec::kUnimplemented; | 261 return SkCodec::kUnimplemented; |
211 } | 262 } |
212 } | 263 } |
OLD | NEW |