1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "ImageDecoder.h"
18
19 #include <hwui/Bitmap.h>
20 #include <log/log.h>
21
22 #include <SkAndroidCodec.h>
23 #include <SkBitmap.h>
24 #include <SkBlendMode.h>
25 #include <SkCanvas.h>
26 #include <SkEncodedOrigin.h>
27 #include <SkFilterQuality.h>
28 #include <SkPaint.h>
29
30 #undef LOG_TAG
31 #define LOG_TAG "ImageDecoder"
32
33 using namespace android;
34
getDefaultColorSpace() const35 sk_sp<SkColorSpace> ImageDecoder::getDefaultColorSpace() const {
36 const skcms_ICCProfile* encodedProfile = mCodec->getICCProfile();
37 if (encodedProfile) {
38 // If the profile maps directly to an SkColorSpace, that SkColorSpace
39 // will be returned. Otherwise, nullptr will be returned. In either
40 // case, using this SkColorSpace results in doing no color correction.
41 return SkColorSpace::Make(*encodedProfile);
42 }
43
44 // The image has no embedded color profile, and should be treated as SRGB.
45 return SkColorSpace::MakeSRGB();
46 }
47
ImageDecoder(std::unique_ptr<SkAndroidCodec> codec,sk_sp<SkPngChunkReader> peeker,SkCodec::ZeroInitialized zeroInit)48 ImageDecoder::ImageDecoder(std::unique_ptr<SkAndroidCodec> codec, sk_sp<SkPngChunkReader> peeker,
49 SkCodec::ZeroInitialized zeroInit)
50 : mCodec(std::move(codec))
51 , mPeeker(std::move(peeker))
52 , mDecodeSize(mCodec->codec()->dimensions())
53 , mOutColorType(mCodec->computeOutputColorType(kN32_SkColorType))
54 , mUnpremultipliedRequired(false)
55 , mOutColorSpace(getDefaultColorSpace())
56 , mHandleRestorePrevious(true)
57 {
58 mTargetSize = swapWidthHeight() ? SkISize { mDecodeSize.height(), mDecodeSize.width() }
59 : mDecodeSize;
60 this->rewind();
61 mOptions.fZeroInitialized = zeroInit;
62 }
63
64 ImageDecoder::~ImageDecoder() = default;
65
getOutAlphaType() const66 SkAlphaType ImageDecoder::getOutAlphaType() const {
67 return opaque() ? kOpaque_SkAlphaType
68 : mUnpremultipliedRequired ? kUnpremul_SkAlphaType : kPremul_SkAlphaType;
69 }
70
swapped(const SkISize & size)71 static SkISize swapped(const SkISize& size) {
72 return SkISize { size.height(), size.width() };
73 }
74
requires_matrix_scaling(bool swapWidthHeight,const SkISize & decodeSize,const SkISize & targetSize)75 static bool requires_matrix_scaling(bool swapWidthHeight, const SkISize& decodeSize,
76 const SkISize& targetSize) {
77 return (swapWidthHeight && decodeSize != swapped(targetSize))
78 || (!swapWidthHeight && decodeSize != targetSize);
79 }
80
getSampledDimensions(int sampleSize) const81 SkISize ImageDecoder::getSampledDimensions(int sampleSize) const {
82 auto size = mCodec->getSampledDimensions(sampleSize);
83 return swapWidthHeight() ? swapped(size) : size;
84 }
85
setTargetSize(int width,int height)86 bool ImageDecoder::setTargetSize(int width, int height) {
87 if (width <= 0 || height <= 0) {
88 return false;
89 }
90
91 auto info = SkImageInfo::Make(width, height, mOutColorType, getOutAlphaType());
92 size_t rowBytes = info.minRowBytes();
93 if (rowBytes == 0) {
94 // This would have overflowed.
95 return false;
96 }
97
98 size_t pixelMemorySize;
99 if (!Bitmap::computeAllocationSize(rowBytes, height, &pixelMemorySize)) {
100 return false;
101 }
102
103 if (mCropRect) {
104 if (mCropRect->right() > width || mCropRect->bottom() > height) {
105 return false;
106 }
107 }
108
109 const bool swap = swapWidthHeight();
110 const SkISize targetSize = { width, height };
111 SkISize decodeSize = swap ? SkISize { height, width } : targetSize;
112 int sampleSize = mCodec->computeSampleSize(&decodeSize);
113
114 if (mUnpremultipliedRequired && !opaque()) {
115 // Allow using a matrix to handle orientation, but not scaling.
116 if (requires_matrix_scaling(swap, decodeSize, targetSize)) {
117 return false;
118 }
119 }
120
121 mTargetSize = targetSize;
122 mDecodeSize = decodeSize;
123 mOptions.fSampleSize = sampleSize;
124 return true;
125 }
126
setCropRect(const SkIRect * crop)127 bool ImageDecoder::setCropRect(const SkIRect* crop) {
128 if (!crop) {
129 mCropRect.reset();
130 return true;
131 }
132
133 if (crop->left() >= crop->right() || crop->top() >= crop->bottom()) {
134 return false;
135 }
136
137 const auto& size = mTargetSize;
138 if (crop->left() < 0 || crop->top() < 0
139 || crop->right() > size.width() || crop->bottom() > size.height()) {
140 return false;
141 }
142
143 mCropRect.emplace(*crop);
144 return true;
145 }
146
setOutColorType(SkColorType colorType)147 bool ImageDecoder::setOutColorType(SkColorType colorType) {
148 switch (colorType) {
149 case kRGB_565_SkColorType:
150 if (!opaque()) {
151 return false;
152 }
153 break;
154 case kGray_8_SkColorType:
155 if (!gray()) {
156 return false;
157 }
158 break;
159 case kN32_SkColorType:
160 break;
161 case kRGBA_F16_SkColorType:
162 break;
163 default:
164 return false;
165 }
166
167 mOutColorType = colorType;
168 return true;
169 }
170
setUnpremultipliedRequired(bool required)171 bool ImageDecoder::setUnpremultipliedRequired(bool required) {
172 if (required && !opaque()) {
173 if (requires_matrix_scaling(swapWidthHeight(), mDecodeSize, mTargetSize)) {
174 return false;
175 }
176 }
177 mUnpremultipliedRequired = required;
178 return true;
179 }
180
setOutColorSpace(sk_sp<SkColorSpace> colorSpace)181 void ImageDecoder::setOutColorSpace(sk_sp<SkColorSpace> colorSpace) {
182 mOutColorSpace = std::move(colorSpace);
183 }
184
getOutputColorSpace() const185 sk_sp<SkColorSpace> ImageDecoder::getOutputColorSpace() const {
186 // kGray_8 is used for ALPHA_8, which ignores the color space.
187 return mOutColorType == kGray_8_SkColorType ? nullptr : mOutColorSpace;
188 }
189
190
getOutputInfo() const191 SkImageInfo ImageDecoder::getOutputInfo() const {
192 SkISize size = mCropRect ? mCropRect->size() : mTargetSize;
193 return SkImageInfo::Make(size, mOutColorType, getOutAlphaType(), getOutputColorSpace());
194 }
195
swapWidthHeight() const196 bool ImageDecoder::swapWidthHeight() const {
197 return SkEncodedOriginSwapsWidthHeight(mCodec->codec()->getOrigin());
198 }
199
width() const200 int ImageDecoder::width() const {
201 return swapWidthHeight()
202 ? mCodec->codec()->dimensions().height()
203 : mCodec->codec()->dimensions().width();
204 }
205
height() const206 int ImageDecoder::height() const {
207 return swapWidthHeight()
208 ? mCodec->codec()->dimensions().width()
209 : mCodec->codec()->dimensions().height();
210 }
211
opaque() const212 bool ImageDecoder::opaque() const {
213 return mCurrentFrameIsOpaque;
214 }
215
gray() const216 bool ImageDecoder::gray() const {
217 return mCodec->getInfo().colorType() == kGray_8_SkColorType;
218 }
219
isAnimated()220 bool ImageDecoder::isAnimated() {
221 return mCodec->codec()->getFrameCount() > 1;
222 }
223
currentFrame() const224 int ImageDecoder::currentFrame() const {
225 return mOptions.fFrameIndex;
226 }
227
rewind()228 bool ImageDecoder::rewind() {
229 mOptions.fFrameIndex = 0;
230 mOptions.fPriorFrame = SkCodec::kNoFrame;
231 mCurrentFrameIsIndependent = true;
232 mCurrentFrameIsOpaque = mCodec->getInfo().isOpaque();
233 mRestoreState = RestoreState::kDoNothing;
234 mRestoreFrame = nullptr;
235
236 // TODO: Rewind the input now instead of in the next call to decode, and
237 // plumb through whether rewind succeeded.
238 return true;
239 }
240
setHandleRestorePrevious(bool handle)241 void ImageDecoder::setHandleRestorePrevious(bool handle) {
242 mHandleRestorePrevious = handle;
243 if (!handle) {
244 mRestoreFrame = nullptr;
245 }
246 }
247
advanceFrame()248 bool ImageDecoder::advanceFrame() {
249 const int frameIndex = ++mOptions.fFrameIndex;
250 const int frameCount = mCodec->codec()->getFrameCount();
251 if (frameIndex >= frameCount) {
252 // Prevent overflow from repeated calls to advanceFrame.
253 mOptions.fFrameIndex = frameCount;
254 return false;
255 }
256
257 SkCodec::FrameInfo frameInfo;
258 if (!mCodec->codec()->getFrameInfo(frameIndex, &frameInfo)
259 || !frameInfo.fFullyReceived) {
260 // Mark the decoder as finished, requiring a rewind.
261 mOptions.fFrameIndex = frameCount;
262 return false;
263 }
264
265 mCurrentFrameIsIndependent = frameInfo.fRequiredFrame == SkCodec::kNoFrame;
266 mCurrentFrameIsOpaque = frameInfo.fAlphaType == kOpaque_SkAlphaType;
267
268 if (frameInfo.fDisposalMethod == SkCodecAnimation::DisposalMethod::kRestorePrevious) {
269 switch (mRestoreState) {
270 case RestoreState::kDoNothing:
271 case RestoreState::kNeedsRestore:
272 mRestoreState = RestoreState::kFirstRPFrame;
273 mOptions.fPriorFrame = frameIndex - 1;
274 break;
275 case RestoreState::kFirstRPFrame:
276 mRestoreState = RestoreState::kRPFrame;
277 break;
278 case RestoreState::kRPFrame:
279 // Unchanged.
280 break;
281 }
282 } else { // New frame is not restore previous
283 switch (mRestoreState) {
284 case RestoreState::kFirstRPFrame:
285 case RestoreState::kRPFrame:
286 mRestoreState = RestoreState::kNeedsRestore;
287 break;
288 case RestoreState::kNeedsRestore:
289 mRestoreState = RestoreState::kDoNothing;
290 mRestoreFrame = nullptr;
291 [[fallthrough]];
292 case RestoreState::kDoNothing:
293 mOptions.fPriorFrame = frameIndex - 1;
294 break;
295 }
296 }
297
298 return true;
299 }
300
getCurrentFrameInfo()301 SkCodec::FrameInfo ImageDecoder::getCurrentFrameInfo() {
302 LOG_ALWAYS_FATAL_IF(finished());
303
304 auto dims = mCodec->codec()->dimensions();
305 SkCodec::FrameInfo info;
306 if (!mCodec->codec()->getFrameInfo(mOptions.fFrameIndex, &info)) {
307 // SkCodec may return false for a non-animated image. Provide defaults.
308 info.fRequiredFrame = SkCodec::kNoFrame;
309 info.fDuration = 0;
310 info.fFullyReceived = true;
311 info.fAlphaType = mCodec->codec()->getInfo().alphaType();
312 info.fHasAlphaWithinBounds = info.fAlphaType != kOpaque_SkAlphaType;
313 info.fDisposalMethod = SkCodecAnimation::DisposalMethod::kKeep;
314 info.fBlend = SkCodecAnimation::Blend::kSrc;
315 info.fFrameRect = SkIRect::MakeSize(dims);
316 }
317
318 if (auto origin = mCodec->codec()->getOrigin(); origin != kDefault_SkEncodedOrigin) {
319 if (SkEncodedOriginSwapsWidthHeight(origin)) {
320 dims = swapped(dims);
321 }
322 auto matrix = SkEncodedOriginToMatrix(origin, dims.width(), dims.height());
323 auto rect = SkRect::Make(info.fFrameRect);
324 LOG_ALWAYS_FATAL_IF(!matrix.mapRect(&rect));
325 rect.roundIn(&info.fFrameRect);
326 }
327 return info;
328 }
329
finished() const330 bool ImageDecoder::finished() const {
331 return mOptions.fFrameIndex >= mCodec->codec()->getFrameCount();
332 }
333
handleRestorePrevious(const SkImageInfo & outputInfo,void * pixels,size_t rowBytes)334 bool ImageDecoder::handleRestorePrevious(const SkImageInfo& outputInfo, void* pixels,
335 size_t rowBytes) {
336 if (!mHandleRestorePrevious) {
337 return true;
338 }
339
340 switch (mRestoreState) {
341 case RestoreState::kFirstRPFrame:{
342 // This frame is marked kRestorePrevious. The prior frame should be in
343 // |pixels|, and it is what we'll restore after each consecutive
344 // kRestorePrevious frame. Cache it now.
345 if (!(mRestoreFrame = Bitmap::allocateHeapBitmap(outputInfo))) {
346 return false;
347 }
348
349 const uint8_t* srcRow = static_cast<uint8_t*>(pixels);
350 uint8_t* dstRow = static_cast<uint8_t*>(mRestoreFrame->pixels());
351 for (int y = 0; y < outputInfo.height(); y++) {
352 memcpy(dstRow, srcRow, outputInfo.minRowBytes());
353 srcRow += rowBytes;
354 dstRow += mRestoreFrame->rowBytes();
355 }
356 break;
357 }
358 case RestoreState::kRPFrame:
359 case RestoreState::kNeedsRestore:
360 // Restore the cached frame. It's possible that the client skipped decoding a frame, so
361 // we never cached it.
362 if (mRestoreFrame) {
363 const uint8_t* srcRow = static_cast<uint8_t*>(mRestoreFrame->pixels());
364 uint8_t* dstRow = static_cast<uint8_t*>(pixels);
365 for (int y = 0; y < outputInfo.height(); y++) {
366 memcpy(dstRow, srcRow, outputInfo.minRowBytes());
367 srcRow += mRestoreFrame->rowBytes();
368 dstRow += rowBytes;
369 }
370 }
371 break;
372 case RestoreState::kDoNothing:
373 break;
374 }
375 return true;
376 }
377
decode(void * pixels,size_t rowBytes)378 SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) {
379 // This was checked inside setTargetSize, but it's possible the first frame
380 // was opaque, so that method succeeded, but after calling advanceFrame, the
381 // current frame is not opaque.
382 if (mUnpremultipliedRequired && !opaque()) {
383 // Allow using a matrix to handle orientation, but not scaling.
384 if (requires_matrix_scaling(swapWidthHeight(), mDecodeSize, mTargetSize)) {
385 return SkCodec::kInvalidScale;
386 }
387 }
388
389 const auto outputInfo = getOutputInfo();
390 if (!handleRestorePrevious(outputInfo, pixels, rowBytes)) {
391 return SkCodec::kInternalError;
392 }
393
394 void* decodePixels = pixels;
395 size_t decodeRowBytes = rowBytes;
396 const auto decodeInfo = SkImageInfo::Make(mDecodeSize, mOutColorType, getOutAlphaType(),
397 getOutputColorSpace());
398 // Used if we need a temporary before scaling or subsetting.
399 // FIXME: Use scanline decoding on only a couple lines to save memory. b/70709380.
400 SkBitmap tmp;
401 const bool scale = mDecodeSize != mTargetSize;
402 const auto origin = mCodec->codec()->getOrigin();
403 const bool handleOrigin = origin != kDefault_SkEncodedOrigin;
404 SkMatrix outputMatrix;
405 if (scale || handleOrigin || mCropRect) {
406 if (mCropRect) {
407 outputMatrix.setTranslate(-mCropRect->fLeft, -mCropRect->fTop);
408 }
409
410 int targetWidth = mTargetSize.width();
411 int targetHeight = mTargetSize.height();
412 if (handleOrigin) {
413 outputMatrix.preConcat(SkEncodedOriginToMatrix(origin, targetWidth, targetHeight));
414 if (SkEncodedOriginSwapsWidthHeight(origin)) {
415 std::swap(targetWidth, targetHeight);
416 }
417 }
418 if (scale) {
419 float scaleX = (float) targetWidth / mDecodeSize.width();
420 float scaleY = (float) targetHeight / mDecodeSize.height();
421 outputMatrix.preScale(scaleX, scaleY);
422 }
423 // It's possible that this portion *does* have alpha, even if the
424 // composed frame does not. In that case, the SkBitmap needs to have
425 // alpha so it blends properly.
426 if (!tmp.setInfo(decodeInfo.makeAlphaType(mUnpremultipliedRequired ? kUnpremul_SkAlphaType
427 : kPremul_SkAlphaType)))
428 {
429 return SkCodec::kInternalError;
430 }
431 if (!Bitmap::allocateHeapBitmap(&tmp)) {
432 return SkCodec::kInternalError;
433 }
434 decodePixels = tmp.getPixels();
435 decodeRowBytes = tmp.rowBytes();
436
437 if (!mCurrentFrameIsIndependent) {
438 SkMatrix inverse;
439 if (outputMatrix.invert(&inverse)) {
440 SkCanvas canvas(tmp, SkCanvas::ColorBehavior::kLegacy);
441 canvas.setMatrix(inverse);
442 SkBitmap priorFrame;
443 priorFrame.installPixels(outputInfo, pixels, rowBytes);
444 priorFrame.setImmutable(); // Don't want asImage() to force a copy
445 canvas.drawImage(priorFrame.asImage(), 0, 0,
446 SkSamplingOptions(SkFilterMode::kLinear));
447 } else {
448 ALOGE("Failed to invert matrix!");
449 }
450 }
451
452 // Even if the client did not provide zero initialized memory, the
453 // memory we decode into is.
454 mOptions.fZeroInitialized = SkCodec::kYes_ZeroInitialized;
455 }
456
457 auto result = mCodec->getAndroidPixels(decodeInfo, decodePixels, decodeRowBytes, &mOptions);
458
459 // The next call to decode() may not provide zero initialized memory.
460 mOptions.fZeroInitialized = SkCodec::kNo_ZeroInitialized;
461
462 if (scale || handleOrigin || mCropRect) {
463 SkBitmap scaledBm;
464 if (!scaledBm.installPixels(outputInfo, pixels, rowBytes)) {
465 return SkCodec::kInternalError;
466 }
467
468 SkPaint paint;
469 paint.setBlendMode(SkBlendMode::kSrc);
470
471 SkCanvas canvas(scaledBm, SkCanvas::ColorBehavior::kLegacy);
472 canvas.setMatrix(outputMatrix);
473 tmp.setImmutable(); // Don't want asImage() to force copy
474 canvas.drawImage(tmp.asImage(), 0, 0, SkSamplingOptions(SkFilterMode::kLinear), &paint);
475 }
476
477 return result;
478 }
479
480