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