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