Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkImageGeneratorNDK.cpp
Go to the documentation of this file.
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
12
13#include <android/bitmap.h>
14#include <android/data_space.h>
15#include <android/imagedecoder.h>
16
17namespace {
18class ImageGeneratorNDK : public SkImageGenerator {
19public:
20 ImageGeneratorNDK(const SkImageInfo&, sk_sp<SkData>, AImageDecoder*);
21 ~ImageGeneratorNDK() override;
22
23protected:
25
26 bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
27 const Options& opts) override;
28
29private:
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
40};
41
42} // anonymous namespace
43
44static bool ok(int result) {
45 return result == ANDROID_IMAGE_DECODER_SUCCESS;
46}
47
48static bool set_android_bitmap_format(AImageDecoder* decoder, SkColorType colorType) {
50 return ok(AImageDecoder_setAndroidBitmapFormat(decoder, format));
51}
52
53static SkColorType colorType(AImageDecoder* decoder, const AImageDecoderHeaderInfo* headerInfo) {
54 // AImageDecoder never defaults to gray, but allows setting it if the image is 8 bit gray.
57 }
58
59 auto format = static_cast<AndroidBitmapFormat>(
60 AImageDecoderHeaderInfo_getAndroidBitmapFormat(headerInfo));
62}
63
64static 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
71}
72
73std::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
95ImageGeneratorNDK::ImageGeneratorNDK(const SkImageInfo& info, sk_sp<SkData> data,
96 AImageDecoder* decoder)
98 , fData(std::move(data))
99 , fDecoder(decoder)
100 , fPreviouslySetADataSpace(false)
101{
102 SkASSERT(fDecoder);
103}
104
105ImageGeneratorNDK::~ImageGeneratorNDK() {
106 AImageDecoder_delete(fDecoder);
107}
108
109static 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
139bool 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()) {
186 return false;
188 if (this->getInfo().alphaType() != kOpaque_SkAlphaType) {
189 return false;
190 }
191 break;
193 if (!ok(AImageDecoder_setUnpremultipliedRequired(fDecoder, true))) {
194 return false;
195 }
196 break;
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
220sk_sp<SkData> ImageGeneratorNDK::onRefEncodedData() {
221 return fData;
222}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
kUnpremul_SkAlphaType
SkAlphaType
Definition SkAlphaType.h:26
@ kUnknown_SkAlphaType
uninitialized
Definition SkAlphaType.h:27
@ kOpaque_SkAlphaType
pixel is opaque
Definition SkAlphaType.h:28
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition SkAlphaType.h:29
#define SkASSERT(cond)
Definition SkAssert.h:116
SkColorType
Definition SkColorType.h:19
@ kGray_8_SkColorType
pixel with grayscale level in 8-bit byte
Definition SkColorType.h:35
static bool set_android_bitmap_format(AImageDecoder *decoder, SkColorType colorType)
static sk_sp< SkColorSpace > get_default_colorSpace(const AImageDecoderHeaderInfo *headerInfo)
static bool set_target_size(AImageDecoder *decoder, const SkISize &size, const SkISize targetSize)
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
static bool ok(int result)
#define INHERITED(method,...)
static sk_sp< SkColorSpace > MakeSRGB()
virtual sk_sp< SkData > onRefEncodedData()
virtual bool onGetPixels(const SkImageInfo &, void *, size_t, const Options &)
GAsyncResult * result
uint32_t uint32_t * format
AndroidBitmapFormat toAndroidBitmapFormat(SkColorType colorType)
ADataSpace toDataSpace(SkColorSpace *cs)
SkColorType toColorType(AndroidBitmapFormat format)
sk_sp< SkColorSpace > toColorSpace(ADataSpace dataSpace)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switches.h:41
Definition ref_ptr.h:256
int32_t height
int32_t width
static constexpr SkISize Make(int32_t w, int32_t h)
Definition SkSize.h:20
constexpr int32_t width() const
Definition SkSize.h:36
constexpr int32_t height() const
Definition SkSize.h:37
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)