blob: ef889c8f82cd7a6b316f1f360ec422395512566a [file] [log] [blame]
Matt Sarett84014f02017-01-10 11:28:54 -05001/*
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"
Matt Sarett1da27ef2017-01-19 17:14:07 -050013#include "SkColorSpace_Base.h"
Matt Sarett84014f02017-01-10 11:28:54 -050014#include "SkData.h"
15#include "SkImageEncoderPriv.h"
16#include "SkPM4f.h"
17#include "SkSRGB.h"
18
19namespace skiagm {
20
21static const int imageWidth = 128;
22static const int imageHeight = 128;
23
24static inline int div_round_up(int a, int b) {
25 return (a + b - 1) / b;
26}
27
Matt Sarett1da27ef2017-01-19 17:14:07 -050028sk_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
Matt Sarett84014f02017-01-10 11:28:54 -050040static 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) {
Matt Sarett62bb2802017-01-23 12:28:02 -050046 // In the opaque/unpremul case, just convert to SkPMColor ordering.
47 if (kPremul_SkAlphaType != alphaType) {
Matt Sarett84014f02017-01-10 11:28:54 -050048 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
82static void make(SkBitmap* bitmap, SkColorType colorType, SkAlphaType alphaType,
83 sk_sp<SkColorSpace> colorSpace) {
Matt Sarette95941f2017-01-27 18:16:40 -050084 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;
Matt Sarett62bb2802017-01-23 12:28:02 -0500101 }
102
Matt Sarett1da27ef2017-01-19 17:14:07 -0500103 sk_sp<SkData> data = GetResourceAsData(resource);
Matt Sarett84014f02017-01-10 11:28:54 -0500104 std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(data));
105 SkImageInfo dstInfo = codec->getInfo().makeColorType(colorType)
106 .makeAlphaType(alphaType)
Matt Sarett1da27ef2017-01-19 17:14:07 -0500107 .makeColorSpace(fix_for_colortype(colorSpace, colorType));
Matt Sarett84014f02017-01-10 11:28:54 -0500108 bitmap->allocPixels(dstInfo);
109 codec->getPixels(dstInfo, bitmap->getPixels(), bitmap->rowBytes());
110}
111
Matt Sarett62bb2802017-01-23 12:28:02 -0500112static sk_sp<SkData> encode_data(const SkBitmap& bitmap, SkEncodedImageFormat format) {
Matt Sarett84014f02017-01-10 11:28:54 -0500113 SkAutoLockPixels autoLockPixels(bitmap);
114 SkPixmap src;
115 if (!bitmap.peekPixels(&src)) {
116 return nullptr;
117 }
118 SkDynamicMemoryWStream buf;
Matt Sarett62bb2802017-01-23 12:28:02 -0500119
Matt Sarett84014f02017-01-10 11:28:54 -0500120 SkEncodeOptions options;
121 if (bitmap.colorSpace()) {
122 options.fPremulBehavior = SkEncodeOptions::PremulBehavior::kGammaCorrect;
123 }
Matt Sarett62bb2802017-01-23 12:28:02 -0500124
125 switch (format) {
126 case SkEncodedImageFormat::kPNG:
Matt Sarette95941f2017-01-27 18:16:40 -0500127 SkAssertResult(SkEncodeImageAsPNG(&buf, src, options));
Matt Sarett62bb2802017-01-23 12:28:02 -0500128 break;
129 case SkEncodedImageFormat::kWEBP:
Matt Sarette95941f2017-01-27 18:16:40 -0500130 SkAssertResult(SkEncodeImageAsWEBP(&buf, src, options));
131 break;
132 case SkEncodedImageFormat::kJPEG:
133 SkAssertResult(SkEncodeImageAsJPEG(&buf, src, options));
Matt Sarett62bb2802017-01-23 12:28:02 -0500134 break;
135 default:
136 break;
137 }
Matt Sarett84014f02017-01-10 11:28:54 -0500138 return buf.detachAsData();
139}
140
141class EncodeSRGBGM : public GM {
142public:
Matt Sarett62bb2802017-01-23 12:28:02 -0500143 EncodeSRGBGM(SkEncodedImageFormat format)
144 : fEncodedFormat(format)
145 {}
Matt Sarett84014f02017-01-10 11:28:54 -0500146
147protected:
148 SkString onShortName() override {
Matt Sarett62bb2802017-01-23 12:28:02 -0500149 const char* format = nullptr;
150 switch (fEncodedFormat) {
151 case SkEncodedImageFormat::kPNG:
Matt Sarette95941f2017-01-27 18:16:40 -0500152 format = "png";
Matt Sarett62bb2802017-01-23 12:28:02 -0500153 break;
154 case SkEncodedImageFormat::kWEBP:
Matt Sarette95941f2017-01-27 18:16:40 -0500155 format = "webp";
156 break;
157 case SkEncodedImageFormat::kJPEG:
158 format = "jpg";
Matt Sarett62bb2802017-01-23 12:28:02 -0500159 break;
160 default:
161 break;
162 }
Matt Sarette95941f2017-01-27 18:16:40 -0500163 return SkStringPrintf("encode-srgb-%s", format);
Matt Sarett84014f02017-01-10 11:28:54 -0500164 }
165
166 SkISize onISize() override {
Matt Sarette95941f2017-01-27 18:16:40 -0500167 return SkISize::Make(imageWidth * 2, imageHeight * 15);
Matt Sarett84014f02017-01-10 11:28:54 -0500168 }
169
170 void onDraw(SkCanvas* canvas) override {
Matt Sarett1da27ef2017-01-19 17:14:07 -0500171 const SkColorType colorTypes[] = {
Matt Sarett62bb2802017-01-23 12:28:02 -0500172 kN32_SkColorType, kRGBA_F16_SkColorType, kIndex_8_SkColorType, kGray_8_SkColorType,
Matt Sarette95941f2017-01-27 18:16:40 -0500173 kRGB_565_SkColorType,
Matt Sarett1da27ef2017-01-19 17:14:07 -0500174 };
175 const SkAlphaType alphaTypes[] = {
176 kUnpremul_SkAlphaType, kPremul_SkAlphaType, kOpaque_SkAlphaType,
177 };
Matt Sarett84014f02017-01-10 11:28:54 -0500178 const sk_sp<SkColorSpace> colorSpaces[] = {
179 nullptr, SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named),
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);
Matt Sarett62bb2802017-01-23 12:28:02 -0500188 auto image = SkImage::MakeFromEncoded(encode_data(bitmap, fEncodedFormat));
Matt Sarett84014f02017-01-10 11:28:54 -0500189 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
198private:
Matt Sarett62bb2802017-01-23 12:28:02 -0500199 SkEncodedImageFormat fEncodedFormat;
200
Matt Sarett84014f02017-01-10 11:28:54 -0500201 typedef GM INHERITED;
202};
203
Matt Sarett62bb2802017-01-23 12:28:02 -0500204DEF_GM( return new EncodeSRGBGM(SkEncodedImageFormat::kPNG); )
205DEF_GM( return new EncodeSRGBGM(SkEncodedImageFormat::kWEBP); )
Matt Sarette95941f2017-01-27 18:16:40 -0500206DEF_GM( return new EncodeSRGBGM(SkEncodedImageFormat::kJPEG); )
Matt Sarett84014f02017-01-10 11:28:54 -0500207}