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