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/private/SkTFitsIn.h"
9 #include "include/private/SkTo.h"
10 #include "src/images/SkImageEncoderPriv.h"
11 #include "src/ports/SkNDKConversions.h"
12
SkEncodeImageWithNDK(SkWStream * stream,const SkPixmap & pmap,SkEncodedImageFormat format,int quality)13 bool SkEncodeImageWithNDK(SkWStream* stream, const SkPixmap& pmap, SkEncodedImageFormat format,
14 int quality) {
15 // If any of these values is invalid (e.g. set to zero), the info will be rejected by
16 // AndroidBitmap_compress.
17 AndroidBitmapInfo info {
18 .width = SkTFitsIn<uint32_t>(pmap.width()) ? SkToU32(pmap.width()) : 0,
19 .height = SkTFitsIn<uint32_t>(pmap.height()) ? SkToU32(pmap.height()) : 0,
20 .stride = SkTFitsIn<uint32_t>(pmap.rowBytes()) ? SkToU32(pmap.rowBytes()) : 0,
21 .format = SkNDKConversions::toAndroidBitmapFormat(pmap.colorType())
22 };
23
24 switch (pmap.alphaType()) {
25 case kPremul_SkAlphaType:
26 info.flags = ANDROID_BITMAP_FLAGS_ALPHA_PREMUL;
27 break;
28 case kOpaque_SkAlphaType:
29 info.flags = ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE;
30 break;
31 case kUnpremul_SkAlphaType:
32 info.flags = ANDROID_BITMAP_FLAGS_ALPHA_UNPREMUL;
33 break;
34 default:
35 return false;
36 }
37
38 AndroidBitmapCompressFormat androidFormat;
39 switch (format) {
40 case SkEncodedImageFormat::kJPEG:
41 androidFormat = ANDROID_BITMAP_COMPRESS_FORMAT_JPEG;
42 break;
43 case SkEncodedImageFormat::kPNG:
44 androidFormat = ANDROID_BITMAP_COMPRESS_FORMAT_PNG;
45 break;
46 case SkEncodedImageFormat::kWEBP:
47 if (quality == 100) {
48 // Mimic the behavior of SkImageEncoder.cpp. In LOSSLESS mode, libwebp
49 // interprets quality as the amount of effort (time) to spend making
50 // the encoded image smaller, while the visual quality remains constant.
51 // This value of 75 (on a scale of 0 - 100, where 100 spends the most
52 // time for the smallest encoding) matches WebPConfigInit.
53 androidFormat = ANDROID_BITMAP_COMPRESS_FORMAT_WEBP_LOSSLESS;
54 quality = 75;
55 } else {
56 androidFormat = ANDROID_BITMAP_COMPRESS_FORMAT_WEBP_LOSSY;
57 }
58 break;
59 default:
60 return false;
61 }
62
63 auto write_to_stream = [](void* userContext, const void* data, size_t size) {
64 return reinterpret_cast<SkWStream*>(userContext)->write(data, size);
65 };
66
67 return ANDROID_BITMAP_RESULT_SUCCESS == AndroidBitmap_compress(&info,
68 SkNDKConversions::toDataSpace(pmap.colorSpace()), pmap.addr(), androidFormat, quality,
69 reinterpret_cast<void*>(stream), write_to_stream);
70 }
71