| 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 |