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 <Gainmap.h>
20 #include <SkAlphaType.h>
21 #include <SkAndroidCodec.h>
22 #include <SkBitmap.h>
23 #include <SkBlendMode.h>
24 #include <SkCanvas.h>
25 #include <SkCodec.h>
26 #include <SkCodecAnimation.h>
27 #include <SkColorSpace.h>
28 #include <SkColorType.h>
29 #include <SkEncodedOrigin.h>
30 #include <SkImageInfo.h>
31 #include <SkGainmapInfo.h>
32 #include <SkMatrix.h>
33 #include <SkPaint.h>
34 #include <SkPngChunkReader.h>
35 #include <SkRect.h>
36 #include <SkRefCnt.h>
37 #include <SkSamplingOptions.h>
38 #include <SkSize.h>
39 #include <SkStream.h>
40 #include <hwui/Bitmap.h>
41 #include <log/log.h>
42 #include <utils/Trace.h>
43
44 #include <memory>
45
46 #undef LOG_TAG
47 #define LOG_TAG "ImageDecoder"
48
49 using namespace android;
50
getDefaultColorSpace() const51 sk_sp<SkColorSpace> ImageDecoder::getDefaultColorSpace() const {
52 const skcms_ICCProfile* encodedProfile = mCodec->getICCProfile();
53 if (encodedProfile) {
54 if (encodedProfile->has_CICP) {
55 return mCodec->computeOutputColorSpace(kN32_SkColorType);
56 }
57 // If the profile maps directly to an SkColorSpace, that SkColorSpace
58 // will be returned. Otherwise, nullptr will be returned. In either
59 // case, using this SkColorSpace results in doing no color correction.
60 return SkColorSpace::Make(*encodedProfile);
61 }
62
63 // The image has no embedded color profile, and should be treated as SRGB.
64 return SkColorSpace::MakeSRGB();
65 }
66
ImageDecoder(std::unique_ptr<SkAndroidCodec> codec,sk_sp<SkPngChunkReader> peeker,SkCodec::ZeroInitialized zeroInit)67 ImageDecoder::ImageDecoder(std::unique_ptr<SkAndroidCodec> codec, sk_sp<SkPngChunkReader> peeker,
68 SkCodec::ZeroInitialized zeroInit)
69 : mCodec(std::move(codec))
70 , mPeeker(std::move(peeker))
71 , mDecodeSize(mCodec->codec()->dimensions())
72 , mOutColorType(mCodec->computeOutputColorType(kN32_SkColorType))
73 , mUnpremultipliedRequired(false)
74 , mOutColorSpace(getDefaultColorSpace())
75 , mHandleRestorePrevious(true)
76 {
77 mTargetSize = swapWidthHeight() ? SkISize { mDecodeSize.height(), mDecodeSize.width() }
78 : mDecodeSize;
79 this->rewind();
80 mOptions.fZeroInitialized = zeroInit;
81 }
82
83 ImageDecoder::~ImageDecoder() = default;
84
getOutAlphaType() const85 SkAlphaType ImageDecoder::getOutAlphaType() const {
86 return opaque() ? kOpaque_SkAlphaType
87 : mUnpremultipliedRequired ? kUnpremul_SkAlphaType : kPremul_SkAlphaType;
88 }
89
swapped(const SkISize & size)90 static SkISize swapped(const SkISize& size) {
91 return SkISize { size.height(), size.width() };
92 }
93
requires_matrix_scaling(bool swapWidthHeight,const SkISize & decodeSize,const SkISize & targetSize)94 static bool requires_matrix_scaling(bool swapWidthHeight, const SkISize& decodeSize,
95 const SkISize& targetSize) {
96 return (swapWidthHeight && decodeSize != swapped(targetSize))
97 || (!swapWidthHeight && decodeSize != targetSize);
98 }
99
getSampledDimensions(int sampleSize) const100 SkISize ImageDecoder::getSampledDimensions(int sampleSize) const {
101 auto size = mCodec->getSampledDimensions(sampleSize);
102 return swapWidthHeight() ? swapped(size) : size;
103 }
104
setTargetSize(int width,int height)105 bool ImageDecoder::setTargetSize(int width, int height) {
106 if (width <= 0 || height <= 0) {
107 return false;
108 }
109
110 auto info = SkImageInfo::Make(width, height, mOutColorType, getOutAlphaType());
111 size_t rowBytes = info.minRowBytes();
112 if (rowBytes == 0) {
113 // This would have overflowed.
114 return false;
115 }
116
117 size_t pixelMemorySize;
118 if (!Bitmap::computeAllocationSize(rowBytes, height, &pixelMemorySize)) {
119 return false;
120 }
121
122 if (mCropRect) {
123 if (mCropRect->right() > width || mCropRect->bottom() > height) {
124 return false;
125 }
126 }
127
128 const bool swap = swapWidthHeight();
129 const SkISize targetSize = { width, height };
130 SkISize decodeSize = swap ? SkISize { height, width } : targetSize;
131 int sampleSize = mCodec->computeSampleSize(&decodeSize);
132
133 if (mUnpremultipliedRequired && !opaque()) {
134 // Allow using a matrix to handle orientation, but not scaling.
135 if (requires_matrix_scaling(swap, decodeSize, targetSize)) {
136 return false;
137 }
138 }
139
140 mTargetSize = targetSize;
141 mDecodeSize = decodeSize;
142 mOptions.fSampleSize = sampleSize;
143 return true;
144 }
145
setCropRect(const SkIRect * crop)146 bool ImageDecoder::setCropRect(const SkIRect* crop) {
147 if (!crop) {
148 mCropRect.reset();
149 return true;
150 }
151
152 if (crop->left() >= crop->right() || crop->top() >= crop->bottom()) {
153 return false;
154 }
155
156 const auto& size = mTargetSize;
157 if (crop->left() < 0 || crop->top() < 0
158 || crop->right() > size.width() || crop->bottom() > size.height()) {
159 return false;
160 }
161
162 mCropRect.emplace(*crop);
163 return true;
164 }
165
setOutColorType(SkColorType colorType)166 bool ImageDecoder::setOutColorType(SkColorType colorType) {
167 switch (colorType) {
168 case kRGB_565_SkColorType:
169 if (!opaque()) {
170 return false;
171 }
172 break;
173 case kGray_8_SkColorType:
174 if (!gray()) {
175 return false;
176 }
177 break;
178 case kN32_SkColorType:
179 break;
180 case kRGBA_F16_SkColorType:
181 break;
182 case kRGBA_1010102_SkColorType:
183 break;
184 default:
185 return false;
186 }
187
188 mOutColorType = colorType;
189 return true;
190 }
191
setUnpremultipliedRequired(bool required)192 bool ImageDecoder::setUnpremultipliedRequired(bool required) {
193 if (required && !opaque()) {
194 if (requires_matrix_scaling(swapWidthHeight(), mDecodeSize, mTargetSize)) {
195 return false;
196 }
197 }
198 mUnpremultipliedRequired = required;
199 return true;
200 }
201
setOutColorSpace(sk_sp<SkColorSpace> colorSpace)202 void ImageDecoder::setOutColorSpace(sk_sp<SkColorSpace> colorSpace) {
203 mOutColorSpace = std::move(colorSpace);
204 }
205
getOutputColorSpace() const206 sk_sp<SkColorSpace> ImageDecoder::getOutputColorSpace() const {
207 // kGray_8 is used for ALPHA_8, which ignores the color space.
208 return mOutColorType == kGray_8_SkColorType ? nullptr : mOutColorSpace;
209 }
210
211
getOutputInfo() const212 SkImageInfo ImageDecoder::getOutputInfo() const {
213 SkISize size = mCropRect ? mCropRect->size() : mTargetSize;
214 return SkImageInfo::Make(size, mOutColorType, getOutAlphaType(), getOutputColorSpace());
215 }
216
swapWidthHeight() const217 bool ImageDecoder::swapWidthHeight() const {
218 return SkEncodedOriginSwapsWidthHeight(getOrigin());
219 }
220
width() const221 int ImageDecoder::width() const {
222 return swapWidthHeight()
223 ? mCodec->codec()->dimensions().height()
224 : mCodec->codec()->dimensions().width();
225 }
226
height() const227 int ImageDecoder::height() const {
228 return swapWidthHeight()
229 ? mCodec->codec()->dimensions().width()
230 : mCodec->codec()->dimensions().height();
231 }
232
opaque() const233 bool ImageDecoder::opaque() const {
234 return mCurrentFrameIsOpaque;
235 }
236
gray() const237 bool ImageDecoder::gray() const {
238 return mCodec->getInfo().colorType() == kGray_8_SkColorType;
239 }
240
isAnimated()241 bool ImageDecoder::isAnimated() {
242 return mCodec->codec()->getFrameCount() > 1;
243 }
244
currentFrame() const245 int ImageDecoder::currentFrame() const {
246 return mOptions.fFrameIndex;
247 }
248
rewind()249 bool ImageDecoder::rewind() {
250 mOptions.fFrameIndex = 0;
251 mOptions.fPriorFrame = SkCodec::kNoFrame;
252 mCurrentFrameIsIndependent = true;
253 mCurrentFrameIsOpaque = mCodec->getInfo().isOpaque();
254 mRestoreState = RestoreState::kDoNothing;
255 mRestoreFrame = nullptr;
256
257 // TODO: Rewind the input now instead of in the next call to decode, and
258 // plumb through whether rewind succeeded.
259 return true;
260 }
261
setHandleRestorePrevious(bool handle)262 void ImageDecoder::setHandleRestorePrevious(bool handle) {
263 mHandleRestorePrevious = handle;
264 if (!handle) {
265 mRestoreFrame = nullptr;
266 }
267 }
268
advanceFrame()269 bool ImageDecoder::advanceFrame() {
270 const int frameIndex = ++mOptions.fFrameIndex;
271 const int frameCount = mCodec->codec()->getFrameCount();
272 if (frameIndex >= frameCount) {
273 // Prevent overflow from repeated calls to advanceFrame.
274 mOptions.fFrameIndex = frameCount;
275 return false;
276 }
277
278 SkCodec::FrameInfo frameInfo;
279 if (!mCodec->codec()->getFrameInfo(frameIndex, &frameInfo)
280 || !frameInfo.fFullyReceived) {
281 // Mark the decoder as finished, requiring a rewind.
282 mOptions.fFrameIndex = frameCount;
283 return false;
284 }
285
286 mCurrentFrameIsIndependent = frameInfo.fRequiredFrame == SkCodec::kNoFrame;
287 mCurrentFrameIsOpaque = frameInfo.fAlphaType == kOpaque_SkAlphaType;
288
289 if (frameInfo.fDisposalMethod == SkCodecAnimation::DisposalMethod::kRestorePrevious) {
290 switch (mRestoreState) {
291 case RestoreState::kDoNothing:
292 case RestoreState::kNeedsRestore:
293 mRestoreState = RestoreState::kFirstRPFrame;
294 mOptions.fPriorFrame = frameIndex - 1;
295 break;
296 case RestoreState::kFirstRPFrame:
297 mRestoreState = RestoreState::kRPFrame;
298 break;
299 case RestoreState::kRPFrame:
300 // Unchanged.
301 break;
302 }
303 } else { // New frame is not restore previous
304 switch (mRestoreState) {
305 case RestoreState::kFirstRPFrame:
306 case RestoreState::kRPFrame:
307 mRestoreState = RestoreState::kNeedsRestore;
308 break;
309 case RestoreState::kNeedsRestore:
310 mRestoreState = RestoreState::kDoNothing;
311 mRestoreFrame = nullptr;
312 [[fallthrough]];
313 case RestoreState::kDoNothing:
314 mOptions.fPriorFrame = frameIndex - 1;
315 break;
316 }
317 }
318
319 return true;
320 }
321
getCurrentFrameInfo()322 SkCodec::FrameInfo ImageDecoder::getCurrentFrameInfo() {
323 LOG_ALWAYS_FATAL_IF(finished());
324
325 auto dims = mCodec->codec()->dimensions();
326 SkCodec::FrameInfo info;
327 if (!mCodec->codec()->getFrameInfo(mOptions.fFrameIndex, &info)) {
328 // SkCodec may return false for a non-animated image. Provide defaults.
329 info.fRequiredFrame = SkCodec::kNoFrame;
330 info.fDuration = 0;
331 info.fFullyReceived = true;
332 info.fAlphaType = mCodec->codec()->getInfo().alphaType();
333 info.fHasAlphaWithinBounds = info.fAlphaType != kOpaque_SkAlphaType;
334 info.fDisposalMethod = SkCodecAnimation::DisposalMethod::kKeep;
335 info.fBlend = SkCodecAnimation::Blend::kSrc;
336 info.fFrameRect = SkIRect::MakeSize(dims);
337 }
338
339 if (auto origin = getOrigin(); origin != kDefault_SkEncodedOrigin) {
340 if (SkEncodedOriginSwapsWidthHeight(origin)) {
341 dims = swapped(dims);
342 }
343 auto matrix = SkEncodedOriginToMatrix(origin, dims.width(), dims.height());
344 auto rect = SkRect::Make(info.fFrameRect);
345 LOG_ALWAYS_FATAL_IF(!matrix.mapRect(&rect));
346 rect.roundIn(&info.fFrameRect);
347 }
348 return info;
349 }
350
finished() const351 bool ImageDecoder::finished() const {
352 return mOptions.fFrameIndex >= mCodec->codec()->getFrameCount();
353 }
354
handleRestorePrevious(const SkImageInfo & outputInfo,void * pixels,size_t rowBytes)355 bool ImageDecoder::handleRestorePrevious(const SkImageInfo& outputInfo, void* pixels,
356 size_t rowBytes) {
357 if (!mHandleRestorePrevious) {
358 return true;
359 }
360
361 switch (mRestoreState) {
362 case RestoreState::kFirstRPFrame:{
363 // This frame is marked kRestorePrevious. The prior frame should be in
364 // |pixels|, and it is what we'll restore after each consecutive
365 // kRestorePrevious frame. Cache it now.
366 if (!(mRestoreFrame = Bitmap::allocateHeapBitmap(outputInfo))) {
367 return false;
368 }
369
370 const uint8_t* srcRow = static_cast<uint8_t*>(pixels);
371 uint8_t* dstRow = static_cast<uint8_t*>(mRestoreFrame->pixels());
372 for (int y = 0; y < outputInfo.height(); y++) {
373 memcpy(dstRow, srcRow, outputInfo.minRowBytes());
374 srcRow += rowBytes;
375 dstRow += mRestoreFrame->rowBytes();
376 }
377 break;
378 }
379 case RestoreState::kRPFrame:
380 case RestoreState::kNeedsRestore:
381 // Restore the cached frame. It's possible that the client skipped decoding a frame, so
382 // we never cached it.
383 if (mRestoreFrame) {
384 const uint8_t* srcRow = static_cast<uint8_t*>(mRestoreFrame->pixels());
385 uint8_t* dstRow = static_cast<uint8_t*>(pixels);
386 for (int y = 0; y < outputInfo.height(); y++) {
387 memcpy(dstRow, srcRow, outputInfo.minRowBytes());
388 srcRow += mRestoreFrame->rowBytes();
389 dstRow += rowBytes;
390 }
391 }
392 break;
393 case RestoreState::kDoNothing:
394 break;
395 }
396 return true;
397 }
398
decode(void * pixels,size_t rowBytes)399 SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) {
400 // This was checked inside setTargetSize, but it's possible the first frame
401 // was opaque, so that method succeeded, but after calling advanceFrame, the
402 // current frame is not opaque.
403 if (mUnpremultipliedRequired && !opaque()) {
404 // Allow using a matrix to handle orientation, but not scaling.
405 if (requires_matrix_scaling(swapWidthHeight(), mDecodeSize, mTargetSize)) {
406 return SkCodec::kInvalidScale;
407 }
408 }
409
410 const auto outputInfo = getOutputInfo();
411 if (!handleRestorePrevious(outputInfo, pixels, rowBytes)) {
412 return SkCodec::kInternalError;
413 }
414
415 void* decodePixels = pixels;
416 size_t decodeRowBytes = rowBytes;
417 const auto decodeInfo = SkImageInfo::Make(mDecodeSize, mOutColorType, getOutAlphaType(),
418 getOutputColorSpace());
419 // Used if we need a temporary before scaling or subsetting.
420 // FIXME: Use scanline decoding on only a couple lines to save memory. b/70709380.
421 SkBitmap tmp;
422 const bool scale = mDecodeSize != mTargetSize;
423 const auto origin = getOrigin();
424 const bool handleOrigin = origin != kDefault_SkEncodedOrigin;
425 SkMatrix outputMatrix;
426 if (scale || handleOrigin || mCropRect) {
427 if (mCropRect) {
428 outputMatrix.setTranslate(-mCropRect->fLeft, -mCropRect->fTop);
429 }
430
431 int targetWidth = mTargetSize.width();
432 int targetHeight = mTargetSize.height();
433 if (handleOrigin) {
434 outputMatrix.preConcat(SkEncodedOriginToMatrix(origin, targetWidth, targetHeight));
435 if (SkEncodedOriginSwapsWidthHeight(origin)) {
436 std::swap(targetWidth, targetHeight);
437 }
438 }
439 if (scale) {
440 float scaleX = (float) targetWidth / mDecodeSize.width();
441 float scaleY = (float) targetHeight / mDecodeSize.height();
442 outputMatrix.preScale(scaleX, scaleY);
443 }
444 // It's possible that this portion *does* have alpha, even if the
445 // composed frame does not. In that case, the SkBitmap needs to have
446 // alpha so it blends properly.
447 if (!tmp.setInfo(decodeInfo.makeAlphaType(mUnpremultipliedRequired ? kUnpremul_SkAlphaType
448 : kPremul_SkAlphaType)))
449 {
450 return SkCodec::kInternalError;
451 }
452 if (!Bitmap::allocateHeapBitmap(&tmp)) {
453 return SkCodec::kInternalError;
454 }
455 decodePixels = tmp.getPixels();
456 decodeRowBytes = tmp.rowBytes();
457
458 if (!mCurrentFrameIsIndependent) {
459 SkMatrix inverse;
460 if (outputMatrix.invert(&inverse)) {
461 SkCanvas canvas(tmp, SkCanvas::ColorBehavior::kLegacy);
462 canvas.setMatrix(inverse);
463 SkBitmap priorFrame;
464 priorFrame.installPixels(outputInfo, pixels, rowBytes);
465 priorFrame.setImmutable(); // Don't want asImage() to force a copy
466 canvas.drawImage(priorFrame.asImage(), 0, 0,
467 SkSamplingOptions(SkFilterMode::kLinear));
468 } else {
469 ALOGE("Failed to invert matrix!");
470 }
471 }
472
473 // Even if the client did not provide zero initialized memory, the
474 // memory we decode into is.
475 mOptions.fZeroInitialized = SkCodec::kYes_ZeroInitialized;
476 }
477
478 ATRACE_BEGIN("getAndroidPixels");
479 auto result = mCodec->getAndroidPixels(decodeInfo, decodePixels, decodeRowBytes, &mOptions);
480 ATRACE_END();
481
482 // The next call to decode() may not provide zero initialized memory.
483 mOptions.fZeroInitialized = SkCodec::kNo_ZeroInitialized;
484
485 if (scale || handleOrigin || mCropRect) {
486 ATRACE_NAME("Handling scale/origin/crop");
487 SkBitmap scaledBm;
488 if (!scaledBm.installPixels(outputInfo, pixels, rowBytes)) {
489 return SkCodec::kInternalError;
490 }
491
492 SkPaint paint;
493 paint.setBlendMode(SkBlendMode::kSrc);
494
495 SkCanvas canvas(scaledBm, SkCanvas::ColorBehavior::kLegacy);
496 canvas.setMatrix(outputMatrix);
497 tmp.setImmutable(); // Don't want asImage() to force copy
498 canvas.drawImage(tmp.asImage(), 0, 0, SkSamplingOptions(SkFilterMode::kLinear), &paint);
499 }
500
501 return result;
502 }
503
extractGainmap(Bitmap * destination,bool isShared)504 SkCodec::Result ImageDecoder::extractGainmap(Bitmap* destination, bool isShared) {
505 ATRACE_CALL();
506 SkGainmapInfo gainmapInfo;
507 std::unique_ptr<SkStream> gainmapStream;
508 {
509 ATRACE_NAME("getAndroidGainmap");
510 if (!mCodec->getAndroidGainmap(&gainmapInfo, &gainmapStream)) {
511 return SkCodec::kSuccess;
512 }
513 }
514 auto gainmapCodec = SkAndroidCodec::MakeFromStream(std::move(gainmapStream));
515 if (!gainmapCodec) {
516 ALOGW("Failed to create codec for gainmap stream");
517 return SkCodec::kInvalidInput;
518 }
519 ImageDecoder decoder{std::move(gainmapCodec)};
520 // Gainmap inherits the origin of the containing image
521 decoder.mOverrideOrigin.emplace(getOrigin());
522 // Update mDecodeSize / mTargetSize for the overridden origin
523 decoder.setTargetSize(decoder.width(), decoder.height());
524 if (decoder.gray()) {
525 decoder.setOutColorType(kGray_8_SkColorType);
526 }
527
528 const bool isScaled = width() != mTargetSize.width() || height() != mTargetSize.height();
529
530 if (isScaled) {
531 float scaleX = (float)mTargetSize.width() / width();
532 float scaleY = (float)mTargetSize.height() / height();
533 decoder.setTargetSize(decoder.width() * scaleX, decoder.height() * scaleY);
534 }
535
536 if (mCropRect) {
537 float sX = decoder.mTargetSize.width() / (float)mTargetSize.width();
538 float sY = decoder.mTargetSize.height() / (float)mTargetSize.height();
539 SkIRect crop = *mCropRect;
540 // TODO: Tweak rounding?
541 crop.fLeft *= sX;
542 crop.fRight *= sX;
543 crop.fTop *= sY;
544 crop.fBottom *= sY;
545 decoder.setCropRect(&crop);
546 }
547
548 SkImageInfo bitmapInfo = decoder.getOutputInfo();
549 if (bitmapInfo.colorType() == kGray_8_SkColorType) {
550 bitmapInfo = bitmapInfo.makeColorType(kAlpha_8_SkColorType);
551 }
552
553 SkBitmap bm;
554 if (!bm.setInfo(bitmapInfo)) {
555 ALOGE("Failed to setInfo properly");
556 return SkCodec::kInternalError;
557 }
558
559 sk_sp<Bitmap> nativeBitmap;
560 if (isShared) {
561 nativeBitmap = Bitmap::allocateAshmemBitmap(&bm);
562 } else {
563 nativeBitmap = Bitmap::allocateHeapBitmap(&bm);
564 }
565 if (!nativeBitmap) {
566 ALOGE("OOM allocating Bitmap with dimensions %i x %i", bitmapInfo.width(),
567 bitmapInfo.height());
568 return SkCodec::kInternalError;
569 }
570
571 SkCodec::Result result = decoder.decode(bm.getPixels(), bm.rowBytes());
572 bm.setImmutable();
573
574 if (result == SkCodec::kSuccess) {
575 auto gainmap = sp<uirenderer::Gainmap>::make();
576 gainmap->info = gainmapInfo;
577 gainmap->bitmap = std::move(nativeBitmap);
578 destination->setGainmap(std::move(gainmap));
579 }
580
581 return result;
582 }
583