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