• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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