Add F16 and gamma correct support to webp encoder
[platform/upstream/libSkiaSharp.git] / gm / encode-srgb.cpp
1 /*
2  * Copyright 2016 Google Inc.
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 "gm.h"
9
10 #include "Resources.h"
11 #include "SkCanvas.h"
12 #include "SkCodec.h"
13 #include "SkColorSpace_Base.h"
14 #include "SkData.h"
15 #include "SkImageEncoderPriv.h"
16 #include "SkPM4f.h"
17 #include "SkSRGB.h"
18
19 namespace skiagm {
20
21 static const int imageWidth = 128;
22 static const int imageHeight = 128;
23
24 static inline int div_round_up(int a, int b) {
25     return (a + b - 1) / b;
26 }
27
28 sk_sp<SkColorSpace> fix_for_colortype(sk_sp<SkColorSpace> colorSpace, SkColorType colorType) {
29     if (kRGBA_F16_SkColorType == colorType) {
30         if (!colorSpace) {
31             return SkColorSpace::MakeNamed(SkColorSpace::kSRGBLinear_Named);
32         }
33
34         return as_CSB(colorSpace)->makeLinearGamma();
35     }
36
37     return colorSpace;
38 }
39
40 static void make_index8(SkBitmap* bitmap, SkAlphaType alphaType, sk_sp<SkColorSpace> colorSpace) {
41     const SkColor colors[] = {
42             0x800000FF, 0x8000FF00, 0x80FF0000, 0x80FFFF00,
43     };
44
45     auto toPMColor = [alphaType, colorSpace](SkColor color) {
46         // In the opaque/unpremul case, just convert to SkPMColor ordering.
47         if (kPremul_SkAlphaType != alphaType) {
48             return SkSwizzle_BGRA_to_PMColor(color);
49         }
50
51         // Linear premultiply.
52         if (colorSpace) {
53             uint32_t result;
54             Sk4f pmFloat = SkColor4f::FromColor(color).premul().to4f_pmorder();
55             SkNx_cast<uint8_t>(sk_linear_to_srgb_needs_trunc(pmFloat)).store(&result);
56             result = (result & 0x00FFFFFF) | (color & 0xFF000000);
57             return result;
58         }
59
60         // Legacy premultiply.
61         return SkPreMultiplyColor(color);
62     };
63
64     // Note that these are not necessarily premultiplied, but they are platform byte ordering.
65     SkPMColor pmColors[SK_ARRAY_COUNT(colors)];
66     for (int i = 0; i < (int) SK_ARRAY_COUNT(colors); i++) {
67         pmColors[i] = toPMColor(colors[i]);
68     }
69
70     sk_sp<SkColorTable> colorTable(new SkColorTable(pmColors, SK_ARRAY_COUNT(pmColors)));
71     SkImageInfo info = SkImageInfo::Make(imageWidth, imageHeight, kIndex_8_SkColorType,
72                                          alphaType, colorSpace);
73     bitmap->allocPixels(info, nullptr, colorTable.get());
74     for (int y = 0; y < imageHeight; y++) {
75         for (int x = 0; x < imageWidth; x++) {
76             *bitmap->getAddr8(x, y) = (x / div_round_up(imageWidth, 2)) +
77                                       (y / div_round_up(imageHeight, 3));
78         }
79     }
80 }
81
82 static void make(SkBitmap* bitmap, SkColorType colorType, SkAlphaType alphaType,
83                  sk_sp<SkColorSpace> colorSpace) {
84     if (kIndex_8_SkColorType == colorType) {
85         make_index8(bitmap, alphaType, colorSpace);
86         return;
87     }
88
89     const char* resource = (kOpaque_SkAlphaType == alphaType) ? "color_wheel.jpg"
90                                                               : "color_wheel.png";
91     if (kGray_8_SkColorType == colorType) {
92         resource = "grayscale.jpg";
93         alphaType = kOpaque_SkAlphaType;
94     }
95
96     sk_sp<SkData> data = GetResourceAsData(resource);
97     std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(data));
98     SkImageInfo dstInfo = codec->getInfo().makeColorType(colorType)
99                                           .makeAlphaType(alphaType)
100                                           .makeColorSpace(fix_for_colortype(colorSpace, colorType));
101     bitmap->allocPixels(dstInfo);
102     codec->getPixels(dstInfo, bitmap->getPixels(), bitmap->rowBytes());
103 }
104
105 static sk_sp<SkData> encode_data(const SkBitmap& bitmap, SkEncodedImageFormat format) {
106     SkAutoLockPixels autoLockPixels(bitmap);
107     SkPixmap src;
108     if (!bitmap.peekPixels(&src)) {
109         return nullptr;
110     }
111     SkDynamicMemoryWStream buf;
112
113     SkEncodeOptions options;
114     if (bitmap.colorSpace()) {
115         options.fPremulBehavior = SkEncodeOptions::PremulBehavior::kGammaCorrect;
116     }
117
118     switch (format) {
119         case SkEncodedImageFormat::kPNG:
120             SkEncodeImageAsPNG(&buf, src, options);
121             break;
122         case SkEncodedImageFormat::kWEBP:
123             SkEncodeImageAsWEBP(&buf, src, options);
124             break;
125         default:
126             break;
127     }
128     return buf.detachAsData();
129 }
130
131 class EncodeSRGBGM : public GM {
132 public:
133     EncodeSRGBGM(SkEncodedImageFormat format)
134         : fEncodedFormat(format)
135     {}
136
137 protected:
138     SkString onShortName() override {
139         const char* format = nullptr;
140         switch (fEncodedFormat) {
141             case SkEncodedImageFormat::kPNG:
142                 format = "-png";
143                 break;
144             case SkEncodedImageFormat::kWEBP:
145                 format = "-webp";
146                 break;
147             default:
148                 break;
149         }
150         return SkStringPrintf("encode-srgb%s", format);
151     }
152
153     SkISize onISize() override {
154         return SkISize::Make(imageWidth * 2, imageHeight * 12);
155     }
156
157     void onDraw(SkCanvas* canvas) override {
158         const SkColorType colorTypes[] = {
159                 kN32_SkColorType, kRGBA_F16_SkColorType, kIndex_8_SkColorType, kGray_8_SkColorType,
160         };
161         const SkAlphaType alphaTypes[] = {
162                 kUnpremul_SkAlphaType, kPremul_SkAlphaType, kOpaque_SkAlphaType,
163         };
164         const sk_sp<SkColorSpace> colorSpaces[] = {
165                 nullptr, SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named),
166         };
167
168         SkBitmap bitmap;
169         for (SkColorType colorType : colorTypes) {
170             for (SkAlphaType alphaType : alphaTypes) {
171                 canvas->save();
172                 for (sk_sp<SkColorSpace> colorSpace : colorSpaces) {
173                     make(&bitmap, colorType, alphaType, colorSpace);
174                     auto image = SkImage::MakeFromEncoded(encode_data(bitmap, fEncodedFormat));
175                     canvas->drawImage(image.get(), 0.0f, 0.0f);
176                     canvas->translate((float) imageWidth, 0.0f);
177                 }
178                 canvas->restore();
179                 canvas->translate(0.0f, (float) imageHeight);
180             }
181         }
182     }
183
184 private:
185     SkEncodedImageFormat fEncodedFormat;
186
187     typedef GM INHERITED;
188 };
189
190 DEF_GM( return new EncodeSRGBGM(SkEncodedImageFormat::kPNG); )
191 DEF_GM( return new EncodeSRGBGM(SkEncodedImageFormat::kWEBP); )
192 }