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