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