Flutter Engine
The Flutter Engine
NdkEncodeTest.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
9#ifdef SK_ENABLE_NDK_IMAGES
21#include "tests/Test.h"
22#include "tools/Resources.h"
23#include "tools/ToolUtils.h"
24
25#include <stdint.h>
26#include <vector>
27
28static const char* kPng = "png";
29static const char* kJpeg = "jpeg";
30static const char* kWebpLossless = "webp_lossless";
31static const char* kWebpLossy = "webp_lossy";
32
33namespace {
34static const struct {
36 int quality;
37 const char* name;
38} gRecs[] = {
39 { SkEncodedImageFormat::kPNG, 100, kPng},
40 { SkEncodedImageFormat::kJPEG, 100, kJpeg},
41 { SkEncodedImageFormat::kWEBP, 100, kWebpLossless},
42 { SkEncodedImageFormat::kWEBP, 80, kWebpLossy},
43};
44}
45
46static sk_sp<SkData> encode_ndk(const SkPixmap& pmap, SkEncodedImageFormat format, int quality) {
49 switch (format) {
51 bool success = SkPngEncoder::Encode(&buf, pmap, {});
52 return success ? buf.detachAsData() : nullptr;
53 }
56 opts.fQuality = quality;
57 bool success = SkJpegEncoder::Encode(&buf, pmap, opts);
58 return success ? buf.detachAsData() : nullptr;
59 }
62 opts.fQuality = quality;
63 bool success = SkWebpEncoder::Encode(&buf, pmap, opts);
64 return success ? buf.detachAsData() : nullptr;
65 }
66 default:
68 }
69}
70
71DEF_TEST(NdkEncode, r) {
72 for (auto ct : { kRGBA_8888_SkColorType,
75 SkBitmap bm;
78 for (const auto& rec : gRecs) {
79 auto encoded = encode_ndk(bm.pixmap(), rec.format, rec.quality);
80 if (!encoded) {
81 ERRORF(r, "Failed to encode %s to %s\n", ToolUtils::colortype_name(ct), rec.name);
82 continue;
83 }
84 auto gen = SkImageGenerators::MakeFromEncoded(std::move(encoded));
85 if (!gen) {
86 ERRORF(r, "Failed to decode from %s as %s\n", ToolUtils::colortype_name(ct),
87 rec.name);
88 continue;
89 }
90
91 if (rec.name == kPng && bm.colorType() == kRGB_565_SkColorType) {
92 REPORTER_ASSERT(r, gen->getInfo().colorType() == kRGB_565_SkColorType);
93 } else {
94 REPORTER_ASSERT(r, gen->getInfo().colorType() == kN32_SkColorType);
95 }
96
97 SkBitmap bm2;
98 bm2.allocPixels(bm.info());
99 REPORTER_ASSERT(r, gen->getPixels(bm2.pixmap()));
100
101 for (int x = 0; x < bm.width(); x++)
102 for (int y = 0; y < bm.height(); y++) {
103 SkColor orig = bm .getColor(x, y);
104 SkColor actual = bm2.getColor(x, y);
105
106 REPORTER_ASSERT(r, SkColorGetA(orig) == SkColorGetA(actual));
107 REPORTER_ASSERT(r, SkColorGetA(orig) == 0xFF);
108
109 if (rec.name == kPng || rec.name == kWebpLossless) {
110 REPORTER_ASSERT(r, orig == actual);
111 } else {
112 int diffR = std::abs((int) SkColorGetR(orig) - (int) SkColorGetR(actual));
113 int diffG = std::abs((int) SkColorGetG(orig) - (int) SkColorGetG(actual));
114 int diffB = std::abs((int) SkColorGetB(orig) - (int) SkColorGetB(actual));
115 REPORTER_ASSERT(r, diffR <= 2 && diffG <= 1 && diffB <= 1);
116 }
117 }
118 }
119 }
120}
121
122DEF_TEST(NdkEncode_unsupportedFormats, r) {
123 for (auto ct : { kRGBA_8888_SkColorType,
126 SkBitmap bm;
138 REPORTER_ASSERT(r, !encode_ndk(bm.pixmap(), format, 100));
139 }
140 }
141}
142
143DEF_TEST(NdkEncode_badQuality, r) {
144 for (auto ct : { kRGBA_8888_SkColorType,
147 SkBitmap bm;
153 for (int quality : {-1, -100, 101, 200}) {
154 REPORTER_ASSERT(r, !encode_ndk(bm.pixmap(), format, quality));
155 }
156 }
157 }
158}
159
160DEF_TEST(NdkEncode_nullPixels, r) {
161 for (auto info : { SkImageInfo::MakeUnknown(),
164 SkPixmap pm(info, nullptr, info.minRowBytes());
165 for (const auto& rec : gRecs) {
166 REPORTER_ASSERT(r, !encode_ndk(pm, rec.format, rec.quality));
167 }
168 }
169}
170
171DEF_TEST(NdkEncode_badInfo, r) {
172 // Allocate an arbitrary amount of memory. These infos don't have a natural
173 // amount to allocate, and the encoder shouldn't touch the memory anyway.
174 // But this allows us to verify that the bad info fails, even when the pixel
175 // pointer is not null.
176 void* pixels = sk_malloc_throw(1024);
177 std::vector<SkPixmap> pixmaps{ SkPixmap(SkImageInfo::MakeN32Premul(-10, 10), pixels, 1000),
178 SkPixmap(SkImageInfo::MakeN32Premul(10, -10), pixels, 200),
179 SkPixmap(SkImageInfo::MakeN32Premul(10, 10), pixels, 20),
180 SkPixmap(SkImageInfo::MakeN32Premul(10, 10), pixels, 41),
181 SkPixmap(SkImageInfo::MakeN32Premul(10, 10), pixels, 0),
182 SkPixmap(SkImageInfo::MakeN32Premul( 0, 0), pixels, 40)};
183 if (sizeof(size_t) > sizeof(uint32_t)) {
184 pixmaps.emplace_back(SkImageInfo::MakeN32Premul(10, 10), pixels,
185 static_cast<size_t>(UINT32_MAX) + 1);
186 }
187 for (const auto& pm : pixmaps) {
188 for (const auto& rec : gRecs) {
189 REPORTER_ASSERT(r, !encode_ndk(pm, rec.format, rec.quality));
190 }
191 }
192 free(pixels);
193}
194
195DEF_TEST(NdkEncode_unsupportedColorTypes, r) {
196 for (SkColorType ct : {
215 }) {
217 SkBitmap bm;
218 bm.allocPixels(info);
220 for (const auto& rec : gRecs) {
221 REPORTER_ASSERT(r, !encode_ndk(bm.pixmap(), rec.format, rec.quality));
222 }
223 if (!SkColorTypeIsAlwaysOpaque(ct)) {
224 for (auto at : { kPremul_SkAlphaType, kUnpremul_SkAlphaType}) {
225 info = info.makeAlphaType(at);
226 bm.allocPixels(info);
227 bm.eraseARGB(0x7F, 0xFF, 0xFF, 0xFF);
228 }
229 for (const auto& rec : gRecs) {
230 REPORTER_ASSERT(r, !encode_ndk(bm.pixmap(), rec.format, rec.quality));
231 }
232 }
233 }
234}
235
236DEF_TEST(NdkEncode_unsupportedAlphaTypes, r) {
237 for (auto ct : { kRGBA_8888_SkColorType,
240 for (auto at : { kUnknown_SkAlphaType, (SkAlphaType) -1}) {
241 auto info = SkImageInfo::Make(10, 10, ct, at);
242 size_t rowBytes = info.minRowBytes();
243 void* pixels = sk_malloc_throw(info.computeByteSize(rowBytes));
244 SkPixmap pm(info, pixels, rowBytes);
245 for (const auto& rec : gRecs) {
246 REPORTER_ASSERT(r, !encode_ndk(pm, rec.format, rec.quality));
247 }
248 free(pixels);
249 }
250 }
251}
252
253static constexpr skcms_TransferFunction k2Dot6 = {2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
254
255static constexpr skcms_Matrix3x3 kDCIP3 = {{
256 {0.486143, 0.323835, 0.154234},
257 {0.226676, 0.710327, 0.0629966},
258 {0.000800549, 0.0432385, 0.78275},
259}};
260
261
262static bool nearly_equal(float a, float b) {
263 return fabs(a - b) < .002f;
264}
265
267 return nearly_equal(x.g, y.g)
268 && nearly_equal(x.a, y.a)
269 && nearly_equal(x.b, y.b)
270 && nearly_equal(x.c, y.c)
271 && nearly_equal(x.d, y.d)
272 && nearly_equal(x.e, y.e)
273 && nearly_equal(x.f, y.f);
274}
275
276static bool nearly_equal(const skcms_Matrix3x3& a, const skcms_Matrix3x3& b) {
277 for (int i = 0; i < 3; i++)
278 for (int j = 0; j < 3; j++) {
279 if (!nearly_equal(a.vals[i][j], b.vals[i][j])) return false;
280 }
281 return true;
282}
283
284static bool nearly_equal(SkColorSpace* a, SkColorSpace* b) {
285 skcms_TransferFunction fnA, fnB;
286 skcms_Matrix3x3 gamutA, gamutB;
287 return a && b && a->isNumericalTransferFn(&fnA) && a->toXYZD50(&gamutA)
288 && b->isNumericalTransferFn(&fnB) && b->toXYZD50(&gamutB)
289 && nearly_equal(fnA, fnB) && nearly_equal(gamutA, gamutB);
290}
291
292DEF_TEST(NdkEncode_ColorSpace, r) {
293 const struct {
295 const char* name;
296 } colorSpaces[] = {
297 { sk_sp<SkColorSpace>(nullptr), "null" },
298 { SkColorSpace::MakeSRGB(), "srgb" },
299 { SkColorSpace::MakeSRGBLinear(), "srgb-linear"},
304 { SkColorSpace::MakeRGB(k2Dot6, kDCIP3), "dci-p3" },
305 };
306 for (const auto& colorSpace : colorSpaces) {
308 SkBitmap bm;
309 bm.allocPixels(SkImageInfo::Make(10, 10, ct, kOpaque_SkAlphaType, colorSpace.cs));
311
312 for (const auto& rec : gRecs) {
313 auto encoded = encode_ndk(bm.pixmap(), rec.format, rec.quality);
314 REPORTER_ASSERT(r, encoded);
315 auto gen = SkImageGenerators::MakeFromEncoded(std::move(encoded));
317
318 auto expected = colorSpace.cs ? colorSpace.cs : SkColorSpace::MakeSRGB();
319 auto* actual = gen->getInfo().colorSpace();
320 if (!nearly_equal(actual, expected.get())) {
321 const char* name = "unknown";
322 for (auto named : colorSpaces) {
323 if (nearly_equal(actual, named.cs.get())) {
324 name = named.name;
325 break;
326 }
327 }
328
329 ERRORF(r, "Mismatch: expected: %s\tactual:%s", colorSpace.name, name);
330 }
331 }
332 }
333 }
334}
335
336DEF_TEST(NdkEncode_unsupportedColorSpace, r) {
337 std::vector<sk_sp<SkColorSpace>> unsupportedCs;
340 unsupportedCs.push_back(SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, gamut));
341 unsupportedCs.push_back(SkColorSpace::MakeRGB(SkNamedTransferFn::kHLG, gamut));
342 unsupportedCs.push_back(SkColorSpace::MakeRGB(k2Dot6, gamut));
343 }
344
347 unsupportedCs.push_back(SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2, gamut));
348 }
349
352 unsupportedCs.push_back(SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, gamut));
353 }
354
357 unsupportedCs.push_back(SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, gamut));
358 }
359
360 for (auto gamut : { SkNamedGamut::kAdobeRGB,
362 unsupportedCs.push_back(SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut));
363 }
364
367 unsupportedCs.push_back(SkColorSpace::MakeRGB(fn, kDCIP3));
368 }
369
370 for (auto unsupported : unsupportedCs) {
372 SkBitmap bm;
375
376 for (const auto& rec : gRecs) {
377 REPORTER_ASSERT(r, !encode_ndk(bm.pixmap(), rec.format, rec.quality));
378 }
379 }
380 }
381}
382
383#endif // SK_ENABLE_NDK_IMAGES
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 SkUNREACHABLE
Definition: SkAssert.h:135
SkColorType
Definition: SkColorType.h:19
@ kR16G16B16A16_unorm_SkColorType
pixel with a little endian uint16_t for red, green, blue
Definition: SkColorType.h:50
@ kBGR_101010x_SkColorType
pixel with 10 bits each for blue, green, red; in 32-bit word
Definition: SkColorType.h:30
@ kARGB_4444_SkColorType
pixel with 4 bits for alpha, red, green, blue; in 16-bit word
Definition: SkColorType.h:23
@ kR8G8_unorm_SkColorType
pixel with a uint8_t for red and green
Definition: SkColorType.h:43
@ kBGRA_8888_SkColorType
pixel with 8 bits for blue, green, red, alpha; in 32-bit word
Definition: SkColorType.h:26
@ kA16_unorm_SkColorType
pixel with a little endian uint16_t for alpha
Definition: SkColorType.h:48
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
Definition: SkColorType.h:38
@ kAlpha_8_SkColorType
pixel with alpha in 8-bit byte
Definition: SkColorType.h:21
@ kRGB_101010x_SkColorType
pixel with 10 bits each for red, green, blue; in 32-bit word
Definition: SkColorType.h:29
@ kGray_8_SkColorType
pixel with grayscale level in 8-bit byte
Definition: SkColorType.h:35
@ kRGB_565_SkColorType
pixel with 5 bits red, 6 bits green, 5 bits blue, in 16-bit word
Definition: SkColorType.h:22
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
@ kRGB_888x_SkColorType
pixel with 8 bits each for red, green, blue; in 32-bit word
Definition: SkColorType.h:25
@ kBGRA_1010102_SkColorType
10 bits for blue, green, red; 2 bits for alpha; in 32-bit word
Definition: SkColorType.h:28
@ kA16_float_SkColorType
pixel with a half float for alpha
Definition: SkColorType.h:45
@ kRGBA_F32_SkColorType
pixel using C float for red, green, blue, alpha; in 128-bit word
Definition: SkColorType.h:40
@ kRGBA_1010102_SkColorType
10 bits for red, green, blue; 2 bits for alpha; in 32-bit word
Definition: SkColorType.h:27
@ kR16G16_unorm_SkColorType
pixel with a little endian uint16_t for red and green
Definition: SkColorType.h:49
@ kRGBA_F16Norm_SkColorType
pixel with half floats in [0,1] for red, green, blue, alpha;
Definition: SkColorType.h:36
@ kUnknown_SkColorType
uninitialized
Definition: SkColorType.h:20
@ kR16G16_float_SkColorType
pixel with a half float for red and green
Definition: SkColorType.h:46
#define SkColorGetR(color)
Definition: SkColor.h:65
#define SkColorGetG(color)
Definition: SkColor.h:69
uint32_t SkColor
Definition: SkColor.h:37
constexpr SkColor SK_ColorBLUE
Definition: SkColor.h:135
constexpr SkColor SK_ColorRED
Definition: SkColor.h:126
constexpr SkColor SK_ColorGREEN
Definition: SkColor.h:131
#define SkColorGetA(color)
Definition: SkColor.h:61
#define SkColorGetB(color)
Definition: SkColor.h:73
SkEncodedImageFormat
SK_API bool SkColorTypeIsAlwaysOpaque(SkColorType ct)
Definition: SkImageInfo.cpp:48
static void * sk_malloc_throw(size_t size)
Definition: SkMalloc.h:67
static constexpr skcms_TransferFunction k2Dot6
static constexpr skcms_Matrix3x3 kDCIP3
#define DEF_TEST(name, reporter)
Definition: Test.h:312
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286
#define ERRORF(r,...)
Definition: Test.h:293
void allocPixels(const SkImageInfo &info, size_t rowBytes)
Definition: SkBitmap.cpp:258
void eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) const
Definition: SkBitmap.h:817
SkColor getColor(int x, int y) const
Definition: SkBitmap.h:874
int width() const
Definition: SkBitmap.h:149
const SkPixmap & pixmap() const
Definition: SkBitmap.h:133
SkColorType colorType() const
Definition: SkBitmap.h:160
const SkImageInfo & info() const
Definition: SkBitmap.h:139
int height() const
Definition: SkBitmap.h:158
void eraseColor(SkColor4f) const
Definition: SkBitmap.cpp:442
static sk_sp< SkColorSpace > MakeSRGB()
static sk_sp< SkColorSpace > MakeRGB(const skcms_TransferFunction &transferFn, const skcms_Matrix3x3 &toXYZ)
static sk_sp< SkColorSpace > MakeSRGBLinear()
sk_sp< SkData > detachAsData()
Definition: SkStream.cpp:707
static bool b
struct MyStruct a[10]
uint32_t uint32_t * format
double y
double x
std::unique_ptr< SkImageGenerator > MakeFromEncoded(sk_sp< SkData > data, std::optional< SkAlphaType > at)
SK_API bool Encode(SkWStream *dst, const SkPixmap &src, const Options &options)
static constexpr skcms_Matrix3x3 kSRGB
Definition: SkColorSpace.h:67
static constexpr skcms_Matrix3x3 kAdobeRGB
Definition: SkColorSpace.h:77
static constexpr skcms_Matrix3x3 kXYZ
Definition: SkColorSpace.h:99
static constexpr skcms_Matrix3x3 kRec2020
Definition: SkColorSpace.h:93
static constexpr skcms_Matrix3x3 kDisplayP3
Definition: SkColorSpace.h:87
static constexpr skcms_TransferFunction kRec2020
Definition: SkColorSpace.h:54
static constexpr skcms_TransferFunction k2Dot2
Definition: SkColorSpace.h:48
static constexpr skcms_TransferFunction kSRGB
Definition: SkColorSpace.h:45
static constexpr skcms_TransferFunction kHLG
Definition: SkColorSpace.h:60
static constexpr skcms_TransferFunction kPQ
Definition: SkColorSpace.h:57
static constexpr skcms_TransferFunction kLinear
Definition: SkColorSpace.h:51
SK_API bool Encode(SkWStream *dst, const SkPixmap &src, const Options &options)
SK_API bool Encode(SkWStream *dst, const SkPixmap &src, const Options &options)
const char * colortype_name(SkColorType ct)
Definition: ToolUtils.cpp:65
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
Definition: gen.py:1
SIN Vec< N, float > abs(const Vec< N, float > &x)
Definition: SkVx.h:707
static bool nearly_equal(SkColor4f x, SkColor4f y)
Definition: p3.cpp:35
static SkImageInfo MakeN32Premul(int width, int height)
static SkImageInfo MakeUnknown()
Definition: SkImageInfo.h:357
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)