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