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