xref: /aosp_15_r20/external/skia/src/ports/SkImageEncoder_NDK.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/SkBitmap.h"
9 #include "include/core/SkPixmap.h"
10 #include "include/core/SkStream.h"
11 #include "include/encode/SkJpegEncoder.h"
12 #include "include/encode/SkPngEncoder.h"
13 #include "include/encode/SkWebpEncoder.h"
14 #include "include/private/base/SkTFitsIn.h"
15 #include "include/private/base/SkTo.h"
16 #include "src/encode/SkImageEncoderPriv.h"
17 #include "src/image/SkImage_Base.h"
18 #include "src/ports/SkNDKConversions.h"
19 
info_for_pixmap(const SkPixmap & pmap)20 static AndroidBitmapInfo info_for_pixmap(const SkPixmap& pmap) {
21     // If any of these values is invalid (e.g. set to zero), the info will be rejected by
22     // AndroidBitmap_compress.
23     AndroidBitmapInfo info {
24         .width  = SkTFitsIn<uint32_t>(pmap.width())    ? SkToU32(pmap.width())    : 0,
25         .height = SkTFitsIn<uint32_t>(pmap.height())   ? SkToU32(pmap.height())   : 0,
26         .stride = SkTFitsIn<uint32_t>(pmap.rowBytes()) ? SkToU32(pmap.rowBytes()) : 0,
27         .format = SkNDKConversions::toAndroidBitmapFormat(pmap.colorType())
28     };
29 
30     switch (pmap.alphaType()) {
31         case kPremul_SkAlphaType:
32             info.flags = ANDROID_BITMAP_FLAGS_ALPHA_PREMUL;
33             break;
34         case kOpaque_SkAlphaType:
35             info.flags = ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE;
36             break;
37         case kUnpremul_SkAlphaType:
38             info.flags = ANDROID_BITMAP_FLAGS_ALPHA_UNPREMUL;
39             break;
40         default:
41             SkDEBUGFAIL("unspecified alphaType");
42             info.flags = ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE;
43             break;
44     }
45     return info;
46 }
47 
write_image_to_stream(SkWStream * stream,const SkPixmap & pmap,AndroidBitmapCompressFormat androidFormat,int quality)48 static bool write_image_to_stream(SkWStream* stream,
49                                   const SkPixmap& pmap,
50                                   AndroidBitmapCompressFormat androidFormat,
51                                   int quality) {
52     AndroidBitmapInfo info = info_for_pixmap(pmap);
53 
54     auto write_to_stream = [](void* userContext, const void* data, size_t size) {
55         return reinterpret_cast<SkWStream*>(userContext)->write(data, size);
56     };
57 
58     return ANDROID_BITMAP_RESULT_SUCCESS == AndroidBitmap_compress(&info,
59             SkNDKConversions::toDataSpace(pmap.colorSpace()), pmap.addr(), androidFormat, quality,
60             reinterpret_cast<void*>(stream), write_to_stream);
61 }
62 
63 namespace SkPngEncoder {
Make(SkWStream *,const SkPixmap &,const Options &)64 std::unique_ptr<SkEncoder> Make(SkWStream*, const SkPixmap&, const Options&) {
65     SkDEBUGFAIL("Making an encoder is not supported via the NDK");
66     return nullptr;
67 }
68 
Encode(SkWStream * dst,const SkPixmap & src,const Options & options)69 bool Encode(SkWStream* dst, const SkPixmap& src, const Options& options) {
70     return write_image_to_stream(dst, src, ANDROID_BITMAP_COMPRESS_FORMAT_PNG, 100);
71 }
72 
Encode(GrDirectContext * ctx,const SkImage * img,const Options & options)73 sk_sp<SkData> Encode(GrDirectContext* ctx, const SkImage* img, const Options& options) {
74     if (!img) {
75         return nullptr;
76     }
77     SkBitmap bm;
78     if (!as_IB(img)->getROPixels(ctx, &bm)) {
79         return nullptr;
80     }
81     SkDynamicMemoryWStream stream;
82     if (Encode(&stream, bm.pixmap(), options)) {
83         return stream.detachAsData();
84     }
85     return nullptr;
86 }
87 }  // namespace SkPngEncoder
88 
89 namespace SkJpegEncoder {
90 
Encode(SkWStream * dst,const SkPixmap & src,const Options & options)91 bool Encode(SkWStream* dst, const SkPixmap& src, const Options& options) {
92     return write_image_to_stream(dst, src, ANDROID_BITMAP_COMPRESS_FORMAT_JPEG, options.fQuality);
93 }
94 
Encode(SkWStream *,const SkYUVAPixmaps &,const SkColorSpace *,const Options &)95 bool Encode(SkWStream*, const SkYUVAPixmaps&, const SkColorSpace*, const Options&) {
96     SkDEBUGFAIL("encoding a YUVA pixmap is not supported via the NDK");
97     return false;
98 }
99 
Encode(GrDirectContext * ctx,const SkImage * img,const Options & options)100 sk_sp<SkData> Encode(GrDirectContext* ctx, const SkImage* img, const Options& options) {
101     if (!img) {
102         return nullptr;
103     }
104     SkBitmap bm;
105     if (!as_IB(img)->getROPixels(ctx, &bm)) {
106         return nullptr;
107     }
108     SkDynamicMemoryWStream stream;
109     if (Encode(&stream, bm.pixmap(), options)) {
110         return stream.detachAsData();
111     }
112     return nullptr;
113 }
114 
Make(SkWStream *,const SkPixmap &,const Options &)115 std::unique_ptr<SkEncoder> Make(SkWStream*, const SkPixmap&, const Options&) {
116     SkDEBUGFAIL("Making an encoder is not supported via the NDK");
117     return nullptr;
118 }
119 
Make(SkWStream *,const SkYUVAPixmaps &,const SkColorSpace *,const Options &)120 std::unique_ptr<SkEncoder> Make(SkWStream*,
121                                 const SkYUVAPixmaps&,
122                                 const SkColorSpace*,
123                                 const Options&) {
124     SkDEBUGFAIL("Making an encoder is not supported via the NDK");
125     return nullptr;
126 }
127 
128 }  // namespace SkJpegEncoder
129 
130 namespace SkWebpEncoder {
131 
Encode(SkWStream * dst,const SkPixmap & src,const Options & options)132 bool Encode(SkWStream* dst, const SkPixmap& src, const Options& options) {
133     if (options.fCompression == Compression::kLossless) {
134         return write_image_to_stream(
135                 dst, src, ANDROID_BITMAP_COMPRESS_FORMAT_WEBP_LOSSLESS, options.fQuality);
136     }
137     return write_image_to_stream(
138             dst, src, ANDROID_BITMAP_COMPRESS_FORMAT_WEBP_LOSSY, options.fQuality);
139 }
140 
Encode(GrDirectContext * ctx,const SkImage * img,const Options & options)141 sk_sp<SkData> Encode(GrDirectContext* ctx, const SkImage* img, const Options& options) {
142     if (!img) {
143         return nullptr;
144     }
145     SkBitmap bm;
146     if (!as_IB(img)->getROPixels(ctx, &bm)) {
147         return nullptr;
148     }
149     SkDynamicMemoryWStream stream;
150     if (Encode(&stream, bm.pixmap(), options)) {
151         return stream.detachAsData();
152     }
153     return nullptr;
154 }
155 
EncodeAnimated(SkWStream *,SkSpan<const SkEncoder::Frame>,const Options &)156 bool EncodeAnimated(SkWStream*, SkSpan<const SkEncoder::Frame>, const Options&) {
157     SkDEBUGFAIL("Encoding Animated WebP images is not supported with the NDK.");
158     return false;
159 }
160 }  // namespace SkWebpEncoder
161