• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
div_round_up(int a,int b)24 static inline int div_round_up(int a, int b) {
25     return (a + b - 1) / b;
26 }
27 
fix_for_colortype(sk_sp<SkColorSpace> colorSpace,SkColorType colorType)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::MakeSRGBLinear();
32         }
33 
34         return as_CSB(colorSpace)->makeLinearGamma();
35     }
36 
37     return colorSpace;
38 }
39 
make_index8(SkBitmap * bitmap,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace)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 
make(SkBitmap * bitmap,SkColorType colorType,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace)82 static void make(SkBitmap* bitmap, SkColorType colorType, SkAlphaType alphaType,
83                  sk_sp<SkColorSpace> colorSpace) {
84     const char* resource;
85     switch (colorType) {
86         case kIndex_8_SkColorType:
87             make_index8(bitmap, alphaType, colorSpace);
88             return;
89         case kGray_8_SkColorType:
90             resource = "grayscale.jpg";
91             alphaType = kOpaque_SkAlphaType;
92             break;
93         case kRGB_565_SkColorType:
94             resource = "color_wheel.jpg";
95             alphaType = kOpaque_SkAlphaType;
96             break;
97         default:
98             resource = (kOpaque_SkAlphaType == alphaType) ? "color_wheel.jpg"
99                                                           : "color_wheel.png";
100             break;
101     }
102 
103     sk_sp<SkData> data = GetResourceAsData(resource);
104     std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(data));
105     SkImageInfo dstInfo = codec->getInfo().makeColorType(colorType)
106                                           .makeAlphaType(alphaType)
107                                           .makeColorSpace(fix_for_colortype(colorSpace, colorType));
108     bitmap->allocPixels(dstInfo);
109     codec->getPixels(dstInfo, bitmap->getPixels(), bitmap->rowBytes());
110 }
111 
encode_data(const SkBitmap & bitmap,SkEncodedImageFormat format)112 static sk_sp<SkData> encode_data(const SkBitmap& bitmap, SkEncodedImageFormat format) {
113     SkAutoLockPixels autoLockPixels(bitmap);
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(SkEncodeImageAsJPEG(&buf, src, options));
134             break;
135         default:
136             break;
137     }
138     return buf.detachAsData();
139 }
140 
141 class EncodeSRGBGM : public GM {
142 public:
EncodeSRGBGM(SkEncodedImageFormat format)143     EncodeSRGBGM(SkEncodedImageFormat format)
144         : fEncodedFormat(format)
145     {}
146 
147 protected:
onShortName()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 
onISize()166     SkISize onISize() override {
167         return SkISize::Make(imageWidth * 2, imageHeight * 15);
168     }
169 
onDraw(SkCanvas * canvas)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 }
208