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