• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 Google LLC
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/core/SkImageGenerator.h"
9 #include "include/core/SkImageInfo.h"
10 #include "include/ports/SkImageGeneratorNDK.h"
11 #include "src/ports/SkNDKConversions.h"
12 
13 #include <android/bitmap.h>
14 #include <android/data_space.h>
15 #include <android/imagedecoder.h>
16 
17 namespace {
18 class ImageGeneratorNDK : public SkImageGenerator {
19 public:
20     ImageGeneratorNDK(const SkImageInfo&, sk_sp<SkData>, AImageDecoder*);
21     ~ImageGeneratorNDK() override;
22 
23 protected:
24     sk_sp<SkData> onRefEncodedData() override;
25 
26     bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
27                      const Options& opts) override;
28 
29 private:
30     sk_sp<SkData>  fData;
31     AImageDecoder* fDecoder;
32     // Setting the ADataSpace is sticky - it is set for all future decodes
33     // until it is set again. But as of R there is no way to reset it to
34     // ADATASPACE_UNKNOWN to skip color correction. If the client requests
35     // skipping correction after having set it to something else, we need
36     // to recreate the AImageDecoder.
37     bool           fPreviouslySetADataSpace;
38 
39     using INHERITED = SkImageGenerator;
40 };
41 
42 } // anonymous namespace
43 
ok(int result)44 static bool ok(int result) {
45     return result == ANDROID_IMAGE_DECODER_SUCCESS;
46 }
47 
set_android_bitmap_format(AImageDecoder * decoder,SkColorType colorType)48 static bool set_android_bitmap_format(AImageDecoder* decoder, SkColorType colorType) {
49     auto format = SkNDKConversions::toAndroidBitmapFormat(colorType);
50     return ok(AImageDecoder_setAndroidBitmapFormat(decoder, format));
51 }
52 
colorType(AImageDecoder * decoder,const AImageDecoderHeaderInfo * headerInfo)53 static SkColorType colorType(AImageDecoder* decoder, const AImageDecoderHeaderInfo* headerInfo) {
54     // AImageDecoder never defaults to gray, but allows setting it if the image is 8 bit gray.
55     if (set_android_bitmap_format(decoder, kGray_8_SkColorType)) {
56         return kGray_8_SkColorType;
57     }
58 
59     auto format = static_cast<AndroidBitmapFormat>(
60             AImageDecoderHeaderInfo_getAndroidBitmapFormat(headerInfo));
61     return SkNDKConversions::toColorType(format);
62 }
63 
get_default_colorSpace(const AImageDecoderHeaderInfo * headerInfo)64 static sk_sp<SkColorSpace> get_default_colorSpace(const AImageDecoderHeaderInfo* headerInfo) {
65     auto dataSpace = static_cast<ADataSpace>(AImageDecoderHeaderInfo_getDataSpace(headerInfo));
66     if (auto cs = SkNDKConversions::toColorSpace(dataSpace)) {
67         return cs;
68     }
69 
70     return SkColorSpace::MakeSRGB();
71 }
72 
MakeFromEncodedNDK(sk_sp<SkData> data)73 std::unique_ptr<SkImageGenerator> SkImageGeneratorNDK::MakeFromEncodedNDK(sk_sp<SkData> data) {
74     if (!data) return nullptr;
75 
76     AImageDecoder* rawDecoder;
77     if (!ok(AImageDecoder_createFromBuffer(data->data(), data->size(), &rawDecoder))) {
78         return nullptr;
79     }
80 
81     const AImageDecoderHeaderInfo* headerInfo = AImageDecoder_getHeaderInfo(rawDecoder);
82     int32_t width  = AImageDecoderHeaderInfo_getWidth(headerInfo);
83     int32_t height = AImageDecoderHeaderInfo_getHeight(headerInfo);
84     SkColorType ct = colorType(rawDecoder, headerInfo);
85 
86     // Although the encoded data stores unpremultiplied pixels, AImageDecoder defaults to premul
87     // (if the image may have alpha).
88     SkAlphaType at = AImageDecoderHeaderInfo_getAlphaFlags(headerInfo)
89             == ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
90     auto imageInfo = SkImageInfo::Make(width, height, ct, at, get_default_colorSpace(headerInfo));
91     return std::unique_ptr<SkImageGenerator>(
92             new ImageGeneratorNDK(imageInfo, std::move(data), rawDecoder));
93 }
94 
ImageGeneratorNDK(const SkImageInfo & info,sk_sp<SkData> data,AImageDecoder * decoder)95 ImageGeneratorNDK::ImageGeneratorNDK(const SkImageInfo& info, sk_sp<SkData> data,
96                                      AImageDecoder* decoder)
97     : INHERITED(info)
98     , fData(std::move(data))
99     , fDecoder(decoder)
100     , fPreviouslySetADataSpace(false)
101 {
102     SkASSERT(fDecoder);
103 }
104 
~ImageGeneratorNDK()105 ImageGeneratorNDK::~ImageGeneratorNDK() {
106     AImageDecoder_delete(fDecoder);
107 }
108 
set_target_size(AImageDecoder * decoder,const SkISize & size,const SkISize targetSize)109 static bool set_target_size(AImageDecoder* decoder, const SkISize& size, const SkISize targetSize) {
110     if (size != targetSize) {
111         // AImageDecoder will scale to arbitrary sizes. Only support a size if it's supported by the
112         // underlying library.
113         const AImageDecoderHeaderInfo* headerInfo = AImageDecoder_getHeaderInfo(decoder);
114         const char* mimeType = AImageDecoderHeaderInfo_getMimeType(headerInfo);
115         if (0 == strcmp(mimeType, "image/jpeg")) {
116             bool supported = false;
117             for (int sampleSize : { 2, 4, 8 }) {
118                 int32_t width;
119                 int32_t height;
120                 if (ok(AImageDecoder_computeSampledSize(decoder, sampleSize, &width, &height))
121                         && targetSize == SkISize::Make(width, height)) {
122                     supported = true;
123                     break;
124                 }
125             }
126             if (!supported) return false;
127         } else if (0 == strcmp(mimeType, "image/webp")) {
128             // libwebp supports arbitrary downscaling.
129             if (targetSize.width() > size.width() || targetSize.height() > size.height()) {
130                 return false;
131             }
132         } else {
133             return false;
134         }
135     }
136     return ok(AImageDecoder_setTargetSize(decoder, targetSize.width(), targetSize.height()));
137 }
138 
onGetPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,const Options & opts)139 bool ImageGeneratorNDK::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
140                                     const Options& opts) {
141     if (auto* cs = info.colorSpace()) {
142         if (!ok(AImageDecoder_setDataSpace(fDecoder, SkNDKConversions::toDataSpace(cs)))) {
143             return false;
144         }
145         fPreviouslySetADataSpace = true;
146     } else {
147         // If the requested SkColorSpace is null, the client wants the "raw" colors, without color
148         // space transformations applied. (This is primarily useful for a client that wants to do
149         // their own color transformations.) This is AImageDecoder's default, but if a previous call
150         // set an ADataSpace, AImageDecoder is no longer using its default, so we need to set it
151         // back.
152         if (fPreviouslySetADataSpace) {
153             // AImageDecoderHeaderInfo_getDataSpace always returns the same value for the same
154             // image, regardless of prior calls to AImageDecoder_setDataSpace. Check if it's
155             // ADATASPACE_UNKNOWN, which needs to be handled specially.
156             const AImageDecoderHeaderInfo* headerInfo = AImageDecoder_getHeaderInfo(fDecoder);
157             const auto defaultDataSpace = AImageDecoderHeaderInfo_getDataSpace(headerInfo);
158             if (defaultDataSpace == ADATASPACE_UNKNOWN) {
159                 // As of R, there's no way to reset AImageDecoder to ADATASPACE_UNKNOWN, so
160                 // create a new one.
161                 AImageDecoder* decoder;
162                 if (!ok(AImageDecoder_createFromBuffer(fData->data(), fData->size(), &decoder))) {
163                     return false;
164                 }
165                 AImageDecoder_delete(fDecoder);
166                 fDecoder = decoder;
167             } else {
168                 if (!ok(AImageDecoder_setDataSpace(fDecoder, defaultDataSpace))) {
169                     return false;
170                 }
171             }
172 
173             // Whether by recreating AImageDecoder or calling AImageDecoder_setDataSpace, the
174             // AImageDecoder is back to its default, so if the next call has a null SkColorSpace, it
175             // does not need to reset it again.
176             fPreviouslySetADataSpace = false;
177         }
178     }
179 
180     if (!set_android_bitmap_format(fDecoder, info.colorType())) {
181         return false;
182     }
183 
184     switch (info.alphaType()) {
185         case kUnknown_SkAlphaType:
186             return false;
187         case kOpaque_SkAlphaType:
188             if (this->getInfo().alphaType() != kOpaque_SkAlphaType) {
189                 return false;
190             }
191             break;
192         case kUnpremul_SkAlphaType:
193             if (!ok(AImageDecoder_setUnpremultipliedRequired(fDecoder, true))) {
194                 return false;
195             }
196             break;
197         case kPremul_SkAlphaType:
198             break;
199     }
200 
201     if (!set_target_size(fDecoder, getInfo().dimensions(), info.dimensions())) {
202         return false;
203     }
204 
205     auto byteSize = info.computeByteSize(rowBytes);
206     switch (AImageDecoder_decodeImage(fDecoder, pixels, rowBytes, byteSize)) {
207         case ANDROID_IMAGE_DECODER_INCOMPLETE:
208             // The image was partially decoded, but the input was truncated. The client may be
209             // happy with the partial image.
210         case ANDROID_IMAGE_DECODER_ERROR:
211             // Similarly, the image was partially decoded, but the input had an error. The client
212             // may be happy with the partial image.
213         case ANDROID_IMAGE_DECODER_SUCCESS:
214             return true;
215         default:
216             return false;
217     }
218 }
219 
onRefEncodedData()220 sk_sp<SkData> ImageGeneratorNDK::onRefEncodedData() {
221     return fData;
222 }
223