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/gm.h"
9 #include "include/codec/SkCodec.h"
10 #include "include/core/SkBitmap.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkColorSpace.h"
13 #include "include/core/SkData.h"
14 #include "include/core/SkImage.h"
15 #include "include/core/SkImageInfo.h"
16 #include "include/core/SkPaint.h"
17 #include "include/core/SkPicture.h"
18 #include "include/core/SkPictureRecorder.h"
19 #include "include/core/SkRect.h"
20 #include "include/core/SkRefCnt.h"
21 #include "include/core/SkSize.h"
22 #include "include/core/SkStream.h"
23 #include "include/core/SkString.h"
24 #include "include/core/SkTypes.h"
25 #include "include/third_party/skcms/skcms.h"
26 #include "tools/Resources.h"
27
28 #include <string.h>
29 #include <memory>
30 #include <utility>
31
32 class GrContext;
33
34 static const int kWidth = 64;
35 static const int kHeight = 64;
36
make_raster_image(SkColorType colorType)37 static sk_sp<SkImage> make_raster_image(SkColorType colorType) {
38 std::unique_ptr<SkStream> stream(GetResourceAsStream("images/google_chrome.ico"));
39 std::unique_ptr<SkCodec> codec = SkCodec::MakeFromStream(std::move(stream));
40 if (!codec) {
41 return nullptr;
42 }
43
44 SkBitmap bitmap;
45 SkImageInfo info = codec->getInfo().makeWH(kWidth, kHeight)
46 .makeColorType(colorType)
47 .makeAlphaType(kPremul_SkAlphaType);
48 bitmap.allocPixels(info);
49 codec->getPixels(info, bitmap.getPixels(), bitmap.rowBytes());
50 bitmap.setImmutable();
51 return SkImage::MakeFromBitmap(bitmap);
52 }
53
make_codec_image()54 static sk_sp<SkImage> make_codec_image() {
55 sk_sp<SkData> encoded = GetResourceAsData("images/randPixels.png");
56 return SkImage::MakeFromEncoded(encoded);
57 }
58
draw_contents(SkCanvas * canvas)59 static void draw_contents(SkCanvas* canvas) {
60 SkPaint paint;
61 paint.setStyle(SkPaint::kStroke_Style);
62 paint.setStrokeWidth(20);
63 paint.setColor(0xFF800000);
64 canvas->drawCircle(40, 40, 35, paint);
65 paint.setColor(0xFF008000);
66 canvas->drawCircle(50, 50, 35, paint);
67 paint.setColor(0xFF000080);
68 canvas->drawCircle(60, 60, 35, paint);
69 }
70
make_picture_image()71 static sk_sp<SkImage> make_picture_image() {
72 SkPictureRecorder recorder;
73 draw_contents(recorder.beginRecording(SkRect::MakeIWH(kWidth, kHeight)));
74 return SkImage::MakeFromPicture(recorder.finishRecordingAsPicture(),
75 SkISize::Make(kWidth, kHeight), nullptr, nullptr,
76 SkImage::BitDepth::kU8,
77 SkColorSpace::MakeSRGB());
78 }
79
make_parametric_transfer_fn(const SkColorSpacePrimaries & primaries)80 static sk_sp<SkColorSpace> make_parametric_transfer_fn(const SkColorSpacePrimaries& primaries) {
81 skcms_Matrix3x3 toXYZD50;
82 SkAssertResult(primaries.toXYZD50(&toXYZD50));
83 skcms_TransferFunction fn = { 1.8f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f };
84 return SkColorSpace::MakeRGB(fn, toXYZD50);
85 }
86
make_wide_gamut()87 static sk_sp<SkColorSpace> make_wide_gamut() {
88 // ProPhoto
89 SkColorSpacePrimaries primaries;
90 primaries.fRX = 0.7347f;
91 primaries.fRY = 0.2653f;
92 primaries.fGX = 0.1596f;
93 primaries.fGY = 0.8404f;
94 primaries.fBX = 0.0366f;
95 primaries.fBY = 0.0001f;
96 primaries.fWX = 0.34567f;
97 primaries.fWY = 0.35850f;
98 return make_parametric_transfer_fn(primaries);
99 }
100
make_small_gamut()101 static sk_sp<SkColorSpace> make_small_gamut() {
102 SkColorSpacePrimaries primaries;
103 primaries.fRX = 0.50f;
104 primaries.fRY = 0.33f;
105 primaries.fGX = 0.30f;
106 primaries.fGY = 0.50f;
107 primaries.fBX = 0.25f;
108 primaries.fBY = 0.16f;
109 primaries.fWX = 0.3127f;
110 primaries.fWY = 0.3290f;
111 return make_parametric_transfer_fn(primaries);
112 }
113
draw_image(SkCanvas * canvas,SkImage * image,SkColorType dstColorType,SkAlphaType dstAlphaType,sk_sp<SkColorSpace> dstColorSpace,SkImage::CachingHint hint)114 static void draw_image(SkCanvas* canvas, SkImage* image, SkColorType dstColorType,
115 SkAlphaType dstAlphaType, sk_sp<SkColorSpace> dstColorSpace,
116 SkImage::CachingHint hint) {
117 size_t rowBytes = image->width() * SkColorTypeBytesPerPixel(dstColorType);
118 sk_sp<SkData> data = SkData::MakeUninitialized(rowBytes * image->height());
119 SkImageInfo dstInfo = SkImageInfo::Make(image->width(), image->height(), dstColorType,
120 dstAlphaType, dstColorSpace);
121 if (!image->readPixels(dstInfo, data->writable_data(), rowBytes, 0, 0, hint)) {
122 memset(data->writable_data(), 0, rowBytes * image->height());
123 }
124
125 // Now that we have called readPixels(), dump the raw pixels into an srgb image.
126 sk_sp<SkColorSpace> srgb = SkColorSpace::MakeSRGB();
127 sk_sp<SkImage> raw = SkImage::MakeRasterData(dstInfo.makeColorSpace(srgb), data, rowBytes);
128 canvas->drawImage(raw.get(), 0.0f, 0.0f, nullptr);
129 }
130
131 class ReadPixelsGM : public skiagm::GM {
132 public:
ReadPixelsGM()133 ReadPixelsGM() {}
134
135 protected:
onShortName()136 SkString onShortName() override {
137 return SkString("readpixels");
138 }
139
onISize()140 SkISize onISize() override {
141 return SkISize::Make(6 * kWidth, 9 * kHeight);
142 }
143
onDraw(SkCanvas * canvas)144 void onDraw(SkCanvas* canvas) override {
145 const SkAlphaType alphaTypes[] = {
146 kUnpremul_SkAlphaType,
147 kPremul_SkAlphaType,
148 };
149 const SkColorType colorTypes[] = {
150 kRGBA_8888_SkColorType,
151 kBGRA_8888_SkColorType,
152 kRGBA_F16_SkColorType,
153 };
154 const sk_sp<SkColorSpace> colorSpaces[] = {
155 make_wide_gamut(),
156 SkColorSpace::MakeSRGB(),
157 make_small_gamut(),
158 };
159
160 for (sk_sp<SkColorSpace> dstColorSpace : colorSpaces) {
161 for (SkColorType srcColorType : colorTypes) {
162 canvas->save();
163 sk_sp<SkImage> image = make_raster_image(srcColorType);
164 if (!image) {
165 continue;
166 }
167 if (GrContext* context = canvas->getGrContext()) {
168 image = image->makeTextureImage(context);
169 }
170 if (image) {
171 for (SkColorType dstColorType : colorTypes) {
172 for (SkAlphaType dstAlphaType : alphaTypes) {
173 draw_image(canvas, image.get(), dstColorType, dstAlphaType,
174 dstColorSpace, SkImage::kAllow_CachingHint);
175 canvas->translate((float)kWidth, 0.0f);
176 }
177 }
178 }
179 canvas->restore();
180 canvas->translate(0.0f, (float) kHeight);
181 }
182 }
183 }
184
185 private:
186 typedef skiagm::GM INHERITED;
187 };
188 DEF_GM( return new ReadPixelsGM; )
189
190 class ReadPixelsCodecGM : public skiagm::GM {
191 public:
ReadPixelsCodecGM()192 ReadPixelsCodecGM() {}
193
194 protected:
onShortName()195 SkString onShortName() override {
196 return SkString("readpixelscodec");
197 }
198
onISize()199 SkISize onISize() override {
200 return SkISize::Make(3 * (kEncodedWidth + 1), 12 * (kEncodedHeight + 1));
201 }
202
onDraw(SkCanvas * canvas,SkString * errorMsg)203 DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
204 if (!canvas->imageInfo().colorSpace()) {
205 *errorMsg = "This gm is only interesting in color correct modes.";
206 return DrawResult::kSkip;
207 }
208
209 const SkAlphaType alphaTypes[] = {
210 kUnpremul_SkAlphaType,
211 kPremul_SkAlphaType,
212 };
213 const SkColorType colorTypes[] = {
214 kRGBA_8888_SkColorType,
215 kBGRA_8888_SkColorType,
216 kRGBA_F16_SkColorType,
217 };
218 const sk_sp<SkColorSpace> colorSpaces[] = {
219 make_wide_gamut(),
220 SkColorSpace::MakeSRGB(),
221 make_small_gamut(),
222 };
223 const SkImage::CachingHint hints[] = {
224 SkImage::kAllow_CachingHint,
225 SkImage::kDisallow_CachingHint,
226 };
227
228 sk_sp<SkImage> image = make_codec_image();
229 for (sk_sp<SkColorSpace> dstColorSpace : colorSpaces) {
230 canvas->save();
231 for (SkColorType dstColorType : colorTypes) {
232 for (SkAlphaType dstAlphaType : alphaTypes) {
233 for (SkImage::CachingHint hint : hints) {
234 draw_image(canvas, image.get(), dstColorType, dstAlphaType, dstColorSpace,
235 hint);
236 canvas->translate(0.0f, (float) kEncodedHeight + 1);
237 }
238 }
239 }
240 canvas->restore();
241 canvas->translate((float) kEncodedWidth + 1, 0.0f);
242 }
243 return DrawResult::kOk;
244 }
245
246 private:
247 static const int kEncodedWidth = 8;
248 static const int kEncodedHeight = 8;
249
250 typedef skiagm::GM INHERITED;
251 };
252 DEF_GM( return new ReadPixelsCodecGM; )
253
254 class ReadPixelsPictureGM : public skiagm::GM {
255 public:
ReadPixelsPictureGM()256 ReadPixelsPictureGM() {}
257
258 protected:
onShortName()259 SkString onShortName() override {
260 return SkString("readpixelspicture");
261 }
262
onISize()263 SkISize onISize() override {
264 return SkISize::Make(3 * kWidth, 12 * kHeight);
265 }
266
onDraw(SkCanvas * canvas,SkString * errorMsg)267 DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
268 if (!canvas->imageInfo().colorSpace()) {
269 *errorMsg = "This gm is only interesting in color correct modes.";
270 return DrawResult::kSkip;
271 }
272
273 const sk_sp<SkImage> images[] = {
274 make_picture_image(),
275 };
276 const SkAlphaType alphaTypes[] = {
277 kUnpremul_SkAlphaType,
278 kPremul_SkAlphaType,
279 };
280 const SkColorType colorTypes[] = {
281 kRGBA_8888_SkColorType,
282 kBGRA_8888_SkColorType,
283 kRGBA_F16_SkColorType,
284 };
285 const sk_sp<SkColorSpace> colorSpaces[] = {
286 make_wide_gamut(),
287 SkColorSpace::MakeSRGB(),
288 make_small_gamut(),
289 };
290 const SkImage::CachingHint hints[] = {
291 SkImage::kAllow_CachingHint,
292 SkImage::kDisallow_CachingHint,
293 };
294
295 for (sk_sp<SkImage> image : images) {
296 for (sk_sp<SkColorSpace> dstColorSpace : colorSpaces) {
297 canvas->save();
298 for (SkColorType dstColorType : colorTypes) {
299 for (SkAlphaType dstAlphaType : alphaTypes) {
300 for (SkImage::CachingHint hint : hints) {
301 draw_image(canvas, image.get(), dstColorType, dstAlphaType,
302 dstColorSpace, hint);
303 canvas->translate(0.0f, (float) kHeight);
304 }
305 }
306 }
307 canvas->restore();
308 canvas->translate((float) kWidth, 0.0f);
309 }
310 }
311 return DrawResult::kOk;
312 }
313
314 private:
315
316 typedef skiagm::GM INHERITED;
317 };
318 DEF_GM( return new ReadPixelsPictureGM; )
319