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 { |
18 // Fast path for when we are not scaling. | 21 SkISize preSampledSize = fCodec->getInfo().dimensions(); |
19 if (1 == sampleSize) { | 22 int sampleSize = *sampleSizePtr; |
20 return fCodec->getInfo().dimensions(); | 23 SkASSERT(sampleSize > 1); |
24 | |
25 if (nativeSampleSize) { | |
26 *nativeSampleSize = 1; | |
21 } | 27 } |
22 | 28 |
23 const int width = fCodec->getInfo().width(); | 29 // Only JPEG supports native downsampling. |
24 const int height = fCodec->getInfo().height(); | 30 if (fCodec->getEncodedFormat() == kJPEG_SkEncodedFormat) { |
31 // See if libjpeg supports this scale directly | |
32 switch (sampleSize) { | |
33 case 2: | |
34 case 4: | |
35 case 8: | |
36 // This class does not need to do any sampling. | |
37 *sampleSizePtr = 1; | |
38 return fCodec->getScaledDimensions(get_scale_from_sample_size(sa mpleSize)); | |
39 default: | |
40 break; | |
41 } | |
25 | 42 |
26 // Check if the codec can provide the scaling natively. | 43 // Check if sampleSize is a multiple of something libjpeg can support. |
27 float scale = get_scale_from_sample_size(sampleSize); | 44 int remainder; |
28 SkSize idealSize = SkSize::Make(scale * (float) width, scale * (float) heigh t); | 45 for (int supportedSampleSize : { 8 , 4 , 2 }) { |
29 SkISize nativeSize = fCodec->getScaledDimensions(scale); | 46 int actualSampleSize; |
30 float widthDiff = SkTAbs(((float) nativeSize.width()) - idealSize.width()); | 47 SkTDivMod(sampleSize, supportedSampleSize, &actualSampleSize, &remai nder); |
31 float heightDiff = SkTAbs(((float) nativeSize.height()) - idealSize.height() ); | 48 if (0 == remainder) { |
32 // Native scaling is preferred to sampling. If we can scale natively to | 49 float scale = get_scale_from_sample_size(supportedSampleSize); |
33 // within one of the ideal value, we should choose to scale natively. | 50 |
34 if (widthDiff < 1.0f && heightDiff < 1.0f) { | 51 // fCodec will scale to this size. |
35 return nativeSize; | 52 preSampledSize = fCodec->getScaledDimensions(scale); |
53 | |
54 // And then this class will sample it. | |
55 *sampleSizePtr = actualSampleSize; | |
56 if (nativeSampleSize) { | |
57 *nativeSampleSize = supportedSampleSize; | |
58 } | |
59 break; | |
60 } | |
61 } | |
36 } | 62 } |
37 | 63 |
38 // Provide the scaling by sampling. | 64 return preSampledSize; |
39 return SkISize::Make(get_scaled_dimension(width, sampleSize), | 65 } |
40 get_scaled_dimension(height, sampleSize)); | 66 |
67 SkISize SkSampledCodec::onGetSampledDimensions(int sampleSize) const { | |
68 const SkISize size = this->accountForNativeScaling(&sampleSize); | |
69 return SkISize::Make(get_scaled_dimension(size.width(), sampleSize), | |
70 get_scaled_dimension(size.height(), sampleSize)); | |
41 } | 71 } |
42 | 72 |
43 SkCodec::Result SkSampledCodec::onGetAndroidPixels(const SkImageInfo& info, void * pixels, | 73 SkCodec::Result SkSampledCodec::onGetAndroidPixels(const SkImageInfo& info, void * pixels, |
44 size_t rowBytes, AndroidOptions& options) { | 74 size_t rowBytes, AndroidOptions& options) { |
45 // Create an Options struct for the codec. | 75 // Create an Options struct for the codec. |
46 SkCodec::Options codecOptions; | 76 SkCodec::Options codecOptions; |
47 codecOptions.fZeroInitialized = options.fZeroInitialized; | 77 codecOptions.fZeroInitialized = options.fZeroInitialized; |
48 | 78 |
49 SkIRect* subset = options.fSubset; | 79 SkIRect* subset = options.fSubset; |
50 if (!subset || subset->size() == fCodec->getInfo().dimensions()) { | 80 if (!subset || subset->size() == fCodec->getInfo().dimensions()) { |
51 if (fCodec->dimensionsSupported(info.dimensions())) { | 81 if (fCodec->dimensionsSupported(info.dimensions())) { |
52 return fCodec->getPixels(info, pixels, rowBytes, &codecOptions, opti ons.fColorPtr, | 82 return fCodec->getPixels(info, pixels, rowBytes, &codecOptions, opti ons.fColorPtr, |
53 options.fColorCount); | 83 options.fColorCount); |
54 } | 84 } |
55 | 85 |
56 // If the native codec does not support the requested scale, scale by sa mpling. | 86 // If the native codec does not support the requested scale, scale by sa mpling. |
57 return this->sampledDecode(info, pixels, rowBytes, options); | 87 return this->sampledDecode(info, pixels, rowBytes, options); |
58 } | 88 } |
59 | 89 |
60 // We are performing a subset decode. | 90 // We are performing a subset decode. |
61 int sampleSize = options.fSampleSize; | 91 int sampleSize = options.fSampleSize; |
62 SkISize scaledSize = this->onGetSampledDimensions(sampleSize); | 92 SkISize scaledSize = this->getSampledDimensions(sampleSize); |
63 if (!fCodec->dimensionsSupported(scaledSize)) { | 93 if (!fCodec->dimensionsSupported(scaledSize)) { |
64 // If the native codec does not support the requested scale, scale by sa mpling. | 94 // If the native codec does not support the requested scale, scale by sa mpling. |
65 return this->sampledDecode(info, pixels, rowBytes, options); | 95 return this->sampledDecode(info, pixels, rowBytes, options); |
66 } | 96 } |
67 | 97 |
68 // Calculate the scaled subset bounds. | 98 // Calculate the scaled subset bounds. |
69 int scaledSubsetX = subset->x() / sampleSize; | 99 int scaledSubsetX = subset->x() / sampleSize; |
70 int scaledSubsetY = subset->y() / sampleSize; | 100 int scaledSubsetY = subset->y() / sampleSize; |
71 int scaledSubsetWidth = info.width(); | 101 int scaledSubsetWidth = info.width(); |
72 int scaledSubsetHeight = info.height(); | 102 int scaledSubsetHeight = info.height(); |
(...skipping 27 matching lines...) Expand all Loading... | |
100 } | 130 } |
101 default: | 131 default: |
102 SkASSERT(false); | 132 SkASSERT(false); |
103 return SkCodec::kUnimplemented; | 133 return SkCodec::kUnimplemented; |
104 } | 134 } |
105 } | 135 } |
106 | 136 |
107 | 137 |
108 SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix els, | 138 SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix els, |
109 size_t rowBytes, AndroidOptions& options) { | 139 size_t rowBytes, AndroidOptions& options) { |
140 // We should only call this function when sampling. | |
141 SkASSERT(options.fSampleSize > 1); | |
142 | |
110 // Create options struct for the codec. | 143 // Create options struct for the codec. |
111 SkCodec::Options sampledOptions; | 144 SkCodec::Options sampledOptions; |
112 sampledOptions.fZeroInitialized = options.fZeroInitialized; | 145 sampledOptions.fZeroInitialized = options.fZeroInitialized; |
113 | 146 |
147 // FIXME: This was already called by onGetAndroidPixels. Can we reduce that? | |
148 int sampleSize = options.fSampleSize; | |
149 int nativeSampleSize; | |
150 SkISize nativeSize = this->accountForNativeScaling(&sampleSize, &nativeSampl eSize); | |
151 | |
114 // Check if there is a subset. | 152 // Check if there is a subset. |
115 SkIRect subset; | 153 SkIRect subset; |
116 int subsetY = 0; | 154 int subsetY = 0; |
117 int subsetWidth = fCodec->getInfo().width(); | 155 int subsetWidth = nativeSize.width(); |
118 int subsetHeight = fCodec->getInfo().height(); | 156 int subsetHeight = nativeSize.height(); |
119 if (options.fSubset) { | 157 if (options.fSubset) { |
120 // We will need to know about subsetting in the y-dimension in order to use the | 158 // We will need to know about subsetting in the y-dimension in order to use the |
121 // scanline decoder. | 159 // scanline decoder. |
160 // Update the subset to account for scaling done by fCodec. | |
122 SkIRect* subsetPtr = options.fSubset; | 161 SkIRect* subsetPtr = options.fSubset; |
123 subsetY = subsetPtr->y(); | 162 |
124 subsetWidth = subsetPtr->width(); | 163 // Do the divide ourselves, instead of calling get_scaled_dimension. If |
125 subsetHeight = subsetPtr->height(); | 164 // X and Y are 0, they should remain 0, rather than being upgraded to 1 |
165 // due to being smaller than the sampleSize. | |
166 const int subsetX = subsetPtr->x() / nativeSampleSize; | |
167 subsetY = subsetPtr->y() / nativeSampleSize; | |
168 | |
169 subsetWidth = get_scaled_dimension(subsetPtr->width(), nativeSampleSize) ; | |
msarett
2015/11/02 22:31:57
Ahh this is where it doesn't work. Because the na
scroggo
2015/11/03 15:17:37
I think there's another wrinkle here, too. Our sam
msarett
2015/11/03 15:23:29
Acknowledged.
| |
170 subsetHeight = get_scaled_dimension(subsetPtr->height(), nativeSampleSiz e); | |
126 | 171 |
127 // The scanline decoder only needs to be aware of subsetting in the x-di mension. | 172 // 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( )); | 173 subset.setXYWH(subsetX, 0, subsetWidth, nativeSize.height()); |
129 sampledOptions.fSubset = ⊂ | 174 sampledOptions.fSubset = ⊂ |
130 } | 175 } |
131 | 176 |
132 // Start the scanline decode. | 177 // Start the scanline decode. |
133 SkCodec::Result result = fCodec->startScanlineDecode( | 178 SkCodec::Result result = fCodec->startScanlineDecode( |
134 info.makeWH(fCodec->getInfo().width(), fCodec->getInfo().height()), &sampledOptions, | 179 info.makeWH(nativeSize.width(), nativeSize.height()), &sampledOption s, |
135 options.fColorPtr, options.fColorCount); | 180 options.fColorPtr, options.fColorCount); |
136 if (SkCodec::kSuccess != result) { | 181 if (SkCodec::kSuccess != result) { |
137 return result; | 182 return result; |
138 } | 183 } |
139 | 184 |
140 SkSampler* sampler = fCodec->getSampler(true); | 185 SkSampler* sampler = fCodec->getSampler(true); |
141 if (!sampler) { | 186 if (!sampler) { |
142 return SkCodec::kUnimplemented; | 187 return SkCodec::kUnimplemented; |
143 } | 188 } |
144 | 189 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
203 // fCodec has already handled filling uninitialized memory. | 248 // fCodec has already handled filling uninitialized memory. |
204 return SkCodec::kIncompleteInput; | 249 return SkCodec::kIncompleteInput; |
205 } | 250 } |
206 return SkCodec::kSuccess; | 251 return SkCodec::kSuccess; |
207 } | 252 } |
208 default: | 253 default: |
209 SkASSERT(false); | 254 SkASSERT(false); |
210 return SkCodec::kUnimplemented; | 255 return SkCodec::kUnimplemented; |
211 } | 256 } |
212 } | 257 } |
OLD | NEW |