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