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