Flutter Engine
The Flutter Engine
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,...)
Definition: SkRecorder.cpp:128
static sk_sp< SkColorSpace > MakeSRGB()
SkImageGenerator(const SkImageInfo &info, uint32_t uniqueId=kNeedNewImageUniqueID)
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)
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
Definition: ref_ptr.h:256
int32_t height
int32_t width
Definition: SkSize.h:16
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)
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63