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 "gm/gm.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkData.h"
11 #include "include/core/SkEncodedImageFormat.h"
12 #include "include/core/SkImage.h"
13 #include "include/core/SkImageInfo.h"
14 #include "include/core/SkSize.h"
15 #include "include/core/SkString.h"
16 #include "include/core/SkSurface.h"
17 #include "tools/Resources.h"
18 
19 namespace skiagm {
20 
21 static const int imageWidth = 128;
22 static const int imageHeight = 128;
23 
make_image(SkColorType colorType,SkAlphaType alphaType)24 static sk_sp<SkImage> make_image(SkColorType colorType, SkAlphaType alphaType) {
25     const char* resource;
26     switch (colorType) {
27         case kGray_8_SkColorType:
28             if (alphaType != kOpaque_SkAlphaType) {
29                 return nullptr;
30             }
31             resource = "images/grayscale.jpg";
32             break;
33         case kRGB_565_SkColorType:
34         case kRGB_888x_SkColorType:
35         case kRGB_101010x_SkColorType:
36         case kBGR_101010x_SkColorType:
37             if (alphaType != kOpaque_SkAlphaType) {
38                 return nullptr;
39             }
40             resource = "images/color_wheel.jpg";
41             break;
42         default:
43             resource = (kOpaque_SkAlphaType == alphaType) ? "images/color_wheel.jpg"
44                                                           : "images/rainbow-gradient.png";
45             break;
46     }
47 
48     auto image = GetResourceAsImage(resource);
49     if (!image) {
50         return nullptr;
51     }
52 
53     auto surface = SkSurface::MakeRaster(SkImageInfo::Make(image->width(), image->height(),
54             colorType, alphaType, image->refColorSpace()));
55     surface->getCanvas()->drawImage(image, 0, 0);
56     return surface->makeImageSnapshot();
57 }
58 
59 // This GM looks different depending on the colortype used, so we use different
60 // names to treat them as different GMs.
61 // All Variants draw images in pairs:
62 // - First as an image of the SkColorType of the destination
63 // - Next as the result of encoding and decoding the first image
64 enum class Variant {
65     // One pair, using an opaque image.
66     kOpaque,
67     // One pair, using a grayscale image.
68     kGray,
69     // An opaque pair followed by two more for premul and unpremul.
70     kNormal,
71 };
72 
73 class EncodeColorTypesGM : public GM {
74 public:
EncodeColorTypesGM(SkEncodedImageFormat format,int quality,Variant variant,const char * name)75     EncodeColorTypesGM(SkEncodedImageFormat format, int quality, Variant variant, const char* name)
76         : fFormat(format)
77         , fQuality(quality)
78         , fVariant(variant)
79         , fName(name)
80     {}
81 
82 protected:
onShortName()83     SkString onShortName() override {
84         const char* variant = fVariant == Variant::kOpaque ? "opaque-":
85                               fVariant == Variant::kGray   ? "gray-"  :
86                                                              ""       ;
87         return SkStringPrintf("encode-%scolor-types-%s", variant, fName);
88     }
89 
onISize()90     SkISize onISize() override {
91         const int width = fVariant == Variant::kNormal ? imageWidth * 7 : imageWidth * 2;
92         return SkISize::Make(width, imageHeight);
93     }
94 
onDraw(SkCanvas * canvas,SkString * errorMsg)95     DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
96         const auto colorType = canvas->imageInfo().colorType();
97         switch (fVariant) {
98             case Variant::kGray:
99                 if (colorType != kGray_8_SkColorType) {
100                     return DrawResult::kSkip;
101                 }
102                 break;
103             case Variant::kOpaque:
104                 if (colorType != kRGB_565_SkColorType     &&
105                     colorType != kRGB_888x_SkColorType    &&
106                     colorType != kRGB_101010x_SkColorType &&
107                     colorType != kBGR_101010x_SkColorType)
108                 {
109                     return DrawResult::kSkip;
110                 }
111                 break;
112             case Variant::kNormal:
113                 if (colorType != kARGB_4444_SkColorType    &&
114                     colorType != kRGBA_8888_SkColorType    &&
115                     colorType != kBGRA_8888_SkColorType    &&
116                     colorType != kRGBA_1010102_SkColorType &&
117                     colorType != kBGRA_1010102_SkColorType &&
118                     colorType != kRGBA_F16Norm_SkColorType &&
119                     colorType != kRGBA_F16_SkColorType     &&
120                     colorType != kRGBA_F32_SkColorType)
121                 {
122                     return DrawResult::kSkip;
123                 }
124             break;
125         }
126         const SkAlphaType alphaTypes[] = {
127             kOpaque_SkAlphaType, kPremul_SkAlphaType, kUnpremul_SkAlphaType,
128         };
129 
130         for (SkAlphaType alphaType : alphaTypes) {
131             auto src = make_image(colorType, alphaType);
132             auto decoded = src ? SkImage::MakeFromEncoded(src->encodeToData(fFormat, fQuality))
133                                : nullptr;
134             if (!src || !decoded) {
135                 break;
136             }
137 
138             canvas->drawImage(src, 0.0f, 0.0f);
139             canvas->translate((float) imageWidth, 0.0f);
140 
141             canvas->drawImage(decoded, 0.0f, 0.0f);
142             canvas->translate((float) imageWidth * 1.5, 0.0f);
143         }
144         return DrawResult::kOk;
145     }
146 
147 private:
148     const SkEncodedImageFormat fFormat;
149     const int                  fQuality;
150     const Variant              fVariant;
151     const char*                fName;
152 
153     using INHERITED = GM;
154 };
155 
156 
157 #define DEF_ENCODE_GM(format, quality, variant, name) \
158     static skiagm::GMRegistry SK_MACRO_CONCAT(SK_MACRO_APPEND_LINE(REG_), variant)(\
159             [](){return std::unique_ptr<skiagm::GM>([](){\
160                     return new EncodeColorTypesGM(format, quality, Variant::variant, name);\
161                 }());});
162 
163 #define DEF_VARIANTS(format, quality, name)         \
164     DEF_ENCODE_GM(format, quality, kNormal, name);  \
165     DEF_ENCODE_GM(format, quality, kOpaque, name);  \
166     DEF_ENCODE_GM(format, quality, kGray, name);
167 
168 DEF_VARIANTS(SkEncodedImageFormat::kWEBP, 100, "webp-lossless")
169 DEF_VARIANTS(SkEncodedImageFormat::kWEBP,  80, "webp-lossy")
170 }  // namespace skiagm
171