• 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 <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