1 /*
2 * Copyright 2011 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 <functional>
9 #include "gm.h"
10 #include "sk_tool_utils.h"
11 #include "SkAutoPixmapStorage.h"
12 #include "SkColorPriv.h"
13 #include "SkData.h"
14 #include "SkCanvas.h"
15 #include "SkRandom.h"
16 #include "SkStream.h"
17 #include "SkSurface.h"
18
19 #if SK_SUPPORT_GPU
20 #include "GrContext.h"
21 #endif
22
drawContents(SkSurface * surface,SkColor fillC)23 static void drawContents(SkSurface* surface, SkColor fillC) {
24 SkSize size = SkSize::Make(SkIntToScalar(surface->width()),
25 SkIntToScalar(surface->height()));
26 SkCanvas* canvas = surface->getCanvas();
27
28 SkScalar stroke = size.fWidth / 10;
29 SkScalar radius = (size.fWidth - stroke) / 2;
30
31 SkPaint paint;
32
33 paint.setAntiAlias(true);
34 paint.setColor(fillC);
35 canvas->drawCircle(size.fWidth/2, size.fHeight/2, radius, paint);
36
37 paint.setStyle(SkPaint::kStroke_Style);
38 paint.setStrokeWidth(stroke);
39 paint.setColor(SK_ColorBLACK);
40 canvas->drawCircle(size.fWidth/2, size.fHeight/2, radius, paint);
41 }
42
test_surface(SkCanvas * canvas,SkSurface * surf,bool usePaint)43 static void test_surface(SkCanvas* canvas, SkSurface* surf, bool usePaint) {
44 drawContents(surf, SK_ColorRED);
45 sk_sp<SkImage> imgR = surf->makeImageSnapshot();
46
47 if (true) {
48 sk_sp<SkImage> imgR2 = surf->makeImageSnapshot();
49 SkASSERT(imgR == imgR2);
50 }
51
52 drawContents(surf, SK_ColorGREEN);
53 sk_sp<SkImage> imgG = surf->makeImageSnapshot();
54
55 // since we've drawn after we snapped imgR, imgG will be a different obj
56 SkASSERT(imgR != imgG);
57
58 drawContents(surf, SK_ColorBLUE);
59
60 SkPaint paint;
61 // paint.setFilterBitmap(true);
62 // paint.setAlpha(0x80);
63
64 canvas->drawImage(imgR, 0, 0, usePaint ? &paint : nullptr);
65 canvas->drawImage(imgG, 0, 80, usePaint ? &paint : nullptr);
66 surf->draw(canvas, 0, 160, usePaint ? &paint : nullptr);
67
68 SkRect src1, src2, src3;
69 src1.iset(0, 0, surf->width(), surf->height());
70 src2.iset(-surf->width() / 2, -surf->height() / 2,
71 surf->width(), surf->height());
72 src3.iset(0, 0, surf->width() / 2, surf->height() / 2);
73
74 SkRect dst1, dst2, dst3, dst4;
75 dst1.set(0, 240, 65, 305);
76 dst2.set(0, 320, 65, 385);
77 dst3.set(0, 400, 65, 465);
78 dst4.set(0, 480, 65, 545);
79
80 canvas->drawImageRect(imgR, src1, dst1, usePaint ? &paint : nullptr);
81 canvas->drawImageRect(imgG, src2, dst2, usePaint ? &paint : nullptr);
82 canvas->drawImageRect(imgR, src3, dst3, usePaint ? &paint : nullptr);
83 canvas->drawImageRect(imgG, dst4, usePaint ? &paint : nullptr);
84 }
85
86 class ImageGM : public skiagm::GM {
87 void* fBuffer;
88 size_t fBufferSize;
89 SkSize fSize;
90 enum {
91 W = 64,
92 H = 64,
93 RB = W * 4 + 8,
94 };
95 public:
ImageGM()96 ImageGM() {
97 fBufferSize = RB * H;
98 fBuffer = sk_malloc_throw(fBufferSize);
99 fSize.set(SkIntToScalar(W), SkIntToScalar(H));
100 }
101
~ImageGM()102 ~ImageGM() override {
103 sk_free(fBuffer);
104 }
105
106 protected:
onShortName()107 SkString onShortName() override {
108 return SkString("image-surface");
109 }
110
onISize()111 SkISize onISize() override {
112 return SkISize::Make(960, 1200);
113 }
114
onDraw(SkCanvas * canvas)115 void onDraw(SkCanvas* canvas) override {
116 canvas->scale(2, 2);
117
118 const char* kLabel1 = "Original Img";
119 const char* kLabel2 = "Modified Img";
120 const char* kLabel3 = "Cur Surface";
121 const char* kLabel4 = "Full Crop";
122 const char* kLabel5 = "Over-crop";
123 const char* kLabel6 = "Upper-left";
124 const char* kLabel7 = "No Crop";
125
126 const char* kLabel8 = "Pre-Alloc Img";
127 const char* kLabel9 = "New Alloc Img";
128 const char* kLabel10 = "GPU";
129
130 SkPaint textPaint;
131 textPaint.setAntiAlias(true);
132 sk_tool_utils::set_portable_typeface(&textPaint);
133 textPaint.setTextSize(8);
134
135 canvas->drawString(kLabel1, 10, 60, textPaint);
136 canvas->drawString(kLabel2, 10, 140, textPaint);
137 canvas->drawString(kLabel3, 10, 220, textPaint);
138 canvas->drawString(kLabel4, 10, 300, textPaint);
139 canvas->drawString(kLabel5, 10, 380, textPaint);
140 canvas->drawString(kLabel6, 10, 460, textPaint);
141 canvas->drawString(kLabel7, 10, 540, textPaint);
142
143 canvas->drawString(kLabel8, 80, 10, textPaint);
144 canvas->drawString(kLabel9, 160, 10, textPaint);
145 canvas->drawString(kLabel10, 265, 10, textPaint);
146
147 canvas->translate(80, 20);
148
149 // since we draw into this directly, we need to start fresh
150 sk_bzero(fBuffer, fBufferSize);
151
152 SkImageInfo info = SkImageInfo::MakeN32Premul(W, H);
153 sk_sp<SkSurface> surf0(SkSurface::MakeRasterDirect(info, fBuffer, RB));
154 sk_sp<SkSurface> surf1(SkSurface::MakeRaster(info));
155 sk_sp<SkSurface> surf2; // gpu
156
157 #if SK_SUPPORT_GPU
158 surf2 = SkSurface::MakeRenderTarget(canvas->getGrContext(), SkBudgeted::kNo, info);
159 #endif
160
161 test_surface(canvas, surf0.get(), true);
162 canvas->translate(80, 0);
163 test_surface(canvas, surf1.get(), true);
164 if (surf2) {
165 canvas->translate(80, 0);
166 test_surface(canvas, surf2.get(), true);
167 }
168 }
169
170 private:
171 typedef skiagm::GM INHERITED;
172 };
DEF_GM(return new ImageGM;)173 DEF_GM( return new ImageGM; )
174
175 ///////////////////////////////////////////////////////////////////////////////////////////////////
176
177 #include "SkPictureRecorder.h"
178
179 static void draw_pixmap(SkCanvas* canvas, const SkPixmap& pmap) {
180 SkBitmap bitmap;
181 bitmap.installPixels(pmap);
182 canvas->drawBitmap(bitmap, 0, 0, nullptr);
183 }
184
show_scaled_pixels(SkCanvas * canvas,SkImage * image)185 static void show_scaled_pixels(SkCanvas* canvas, SkImage* image) {
186 SkAutoCanvasRestore acr(canvas, true);
187
188 canvas->drawImage(image, 0, 0, nullptr);
189 canvas->translate(110, 10);
190
191 const SkImageInfo info = SkImageInfo::MakeN32Premul(40, 40);
192 SkAutoPixmapStorage storage;
193 storage.alloc(info);
194
195 const SkImage::CachingHint chints[] = {
196 SkImage::kAllow_CachingHint, SkImage::kDisallow_CachingHint,
197 };
198 const SkFilterQuality qualities[] = {
199 kNone_SkFilterQuality, kLow_SkFilterQuality, kMedium_SkFilterQuality, kHigh_SkFilterQuality,
200 };
201
202 for (auto ch : chints) {
203 canvas->save();
204 for (auto q : qualities) {
205 if (image->scalePixels(storage, q, ch)) {
206 draw_pixmap(canvas, storage);
207 }
208 canvas->translate(70, 0);
209 }
210 canvas->restore();
211 canvas->translate(0, 45);
212 }
213 }
214
draw_contents(SkCanvas * canvas)215 static void draw_contents(SkCanvas* canvas) {
216 SkPaint paint;
217 paint.setStyle(SkPaint::kStroke_Style);
218 paint.setStrokeWidth(20);
219 canvas->drawCircle(50, 50, 35, paint);
220 }
221
make_raster(const SkImageInfo & info,GrContext *,void (* draw)(SkCanvas *))222 static sk_sp<SkImage> make_raster(const SkImageInfo& info, GrContext*, void (*draw)(SkCanvas*)) {
223 auto surface(SkSurface::MakeRaster(info));
224 draw(surface->getCanvas());
225 return surface->makeImageSnapshot();
226 }
227
make_picture(const SkImageInfo & info,GrContext *,void (* draw)(SkCanvas *))228 static sk_sp<SkImage> make_picture(const SkImageInfo& info, GrContext*, void (*draw)(SkCanvas*)) {
229 SkPictureRecorder recorder;
230 draw(recorder.beginRecording(SkRect::MakeIWH(info.width(), info.height())));
231 return SkImage::MakeFromPicture(recorder.finishRecordingAsPicture(),
232 info.dimensions(), nullptr, nullptr, SkImage::BitDepth::kU8,
233 SkColorSpace::MakeSRGB());
234 }
235
make_codec(const SkImageInfo & info,GrContext *,void (* draw)(SkCanvas *))236 static sk_sp<SkImage> make_codec(const SkImageInfo& info, GrContext*, void (*draw)(SkCanvas*)) {
237 sk_sp<SkImage> image(make_raster(info, nullptr, draw));
238 return SkImage::MakeFromEncoded(image->encodeToData());
239 }
240
make_gpu(const SkImageInfo & info,GrContext * ctx,void (* draw)(SkCanvas *))241 static sk_sp<SkImage> make_gpu(const SkImageInfo& info, GrContext* ctx, void (*draw)(SkCanvas*)) {
242 if (!ctx) { return nullptr; }
243 auto surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info));
244 if (!surface) { return nullptr; }
245 draw(surface->getCanvas());
246 return surface->makeImageSnapshot();
247 }
248
249 typedef sk_sp<SkImage> (*ImageMakerProc)(const SkImageInfo&, GrContext*, void (*)(SkCanvas*));
250
251 class ScalePixelsGM : public skiagm::GM {
252 public:
ScalePixelsGM()253 ScalePixelsGM() {}
254
255 protected:
onShortName()256 SkString onShortName() override {
257 return SkString("scale-pixels");
258 }
259
onISize()260 SkISize onISize() override {
261 return SkISize::Make(960, 1200);
262 }
263
onDraw(SkCanvas * canvas)264 void onDraw(SkCanvas* canvas) override {
265 const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
266
267 const ImageMakerProc procs[] = {
268 make_codec, make_raster, make_picture, make_codec, make_gpu,
269 };
270 for (auto& proc : procs) {
271 sk_sp<SkImage> image(proc(info, canvas->getGrContext(), draw_contents));
272 if (image) {
273 show_scaled_pixels(canvas, image.get());
274 }
275 canvas->translate(0, 120);
276 }
277 }
278
279 private:
280 typedef skiagm::GM INHERITED;
281 };
282 DEF_GM( return new ScalePixelsGM; )
283
284 ///////////////////////////////////////////////////////////////////////////////////////////////////
285
286 DEF_SIMPLE_GM(new_texture_image, canvas, 280, 60) {
287 GrContext* context = canvas->getGrContext();
288 if (!context) {
289 skiagm::GM::DrawGpuOnlyMessage(canvas);
290 return;
291 }
292
__anonf69a3e7c0202(SkCanvas* canvas) 293 auto render_image = [](SkCanvas* canvas) {
294 canvas->clear(SK_ColorBLUE);
295 SkPaint paint;
296 paint.setColor(SK_ColorRED);
297 canvas->drawRect(SkRect::MakeXYWH(10.f,10.f,10.f,10.f), paint);
298 paint.setColor(SK_ColorGREEN);
299 canvas->drawRect(SkRect::MakeXYWH(30.f,10.f,10.f,10.f), paint);
300 paint.setColor(SK_ColorYELLOW);
301 canvas->drawRect(SkRect::MakeXYWH(10.f,30.f,10.f,10.f), paint);
302 paint.setColor(SK_ColorCYAN);
303 canvas->drawRect(SkRect::MakeXYWH(30.f,30.f,10.f,10.f), paint);
304 };
305
306 static constexpr int kSize = 50;
307 SkBitmap bmp;
308 bmp.allocPixels(SkImageInfo::MakeS32(kSize, kSize, kPremul_SkAlphaType));
309 SkCanvas bmpCanvas(bmp);
310 render_image(&bmpCanvas);
311
312 std::function<sk_sp<SkImage>()> imageFactories[] = {
313 // Create sw raster image.
__anonf69a3e7c0302null314 [bmp] {
315 return SkImage::MakeFromBitmap(bmp);
316 },
317 // Create encoded image.
__anonf69a3e7c0402null318 [bmp] {
319 sk_sp<SkData> src(
320 sk_tool_utils::EncodeImageToData(bmp, SkEncodedImageFormat::kPNG, 100));
321 return SkImage::MakeFromEncoded(std::move(src));
322 },
323 // Create YUV encoded image.
__anonf69a3e7c0502null324 [bmp] {
325 sk_sp<SkData> src(
326 sk_tool_utils::EncodeImageToData(bmp, SkEncodedImageFormat::kJPEG, 100));
327 return SkImage::MakeFromEncoded(std::move(src));
328 },
329 // Create a picture image.
__anonf69a3e7c0602null330 [render_image] {
331 SkPictureRecorder recorder;
332 SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kSize), SkIntToScalar(kSize));
333 render_image(canvas);
334 sk_sp<SkColorSpace> srgbColorSpace = SkColorSpace::MakeSRGB();
335 return SkImage::MakeFromPicture(recorder.finishRecordingAsPicture(),
336 SkISize::Make(kSize, kSize), nullptr, nullptr,
337 SkImage::BitDepth::kU8, srgbColorSpace);
338 },
339 // Create a texture image
__anonf69a3e7c0702() 340 [context, render_image]() -> sk_sp<SkImage> {
341 auto surface(SkSurface::MakeRenderTarget(context, SkBudgeted::kYes,
342 SkImageInfo::MakeS32(kSize, kSize,
343 kPremul_SkAlphaType)));
344 if (!surface) {
345 return nullptr;
346 }
347 render_image(surface->getCanvas());
348 return surface->makeImageSnapshot();
349 }
350 };
351
352 constexpr SkScalar kPad = 5.f;
353 canvas->translate(kPad, kPad);
354 for (auto factory : imageFactories) {
355 auto image(factory());
356 if (image) {
357 sk_sp<SkImage> texImage(image->makeTextureImage(context,
358 canvas->imageInfo().colorSpace()));
359 if (texImage) {
360 canvas->drawImage(texImage, 0, 0);
361 }
362 }
363 canvas->translate(kSize + kPad, 0);
364 }
365 }
366
draw_pixmap(SkCanvas * canvas,const SkPixmap & pm,SkScalar x,SkScalar y)367 static void draw_pixmap(SkCanvas* canvas, const SkPixmap& pm, SkScalar x, SkScalar y) {
368 canvas->drawImage(SkImage::MakeRasterCopy(pm), x, y, nullptr);
369 }
370
slam_ff(const SkPixmap & pm)371 static void slam_ff(const SkPixmap& pm) {
372 for (int y = 0; y < pm.height(); ++y) {
373 for (int x = 0; x < pm.width(); ++x) {
374 *pm.writable_addr32(x, y) = *pm.addr32(x, y) | SkPackARGB32(0xFF, 0, 0, 0);
375 }
376 }
377 }
378
379 DEF_SIMPLE_GM(scalepixels_unpremul, canvas, 1080, 280) {
380 SkImageInfo info = SkImageInfo::MakeN32(16, 16, kUnpremul_SkAlphaType);
381 SkAutoPixmapStorage pm;
382 pm.alloc(info);
383 for (int y = 0; y < 16; ++y) {
384 for (int x = 0; x < 16; ++x) {
385 *pm.writable_addr32(x, y) = SkPackARGB32NoCheck(0, (y << 4) | y, (x << 4) | x, 0xFF);
386 }
387 }
388 SkAutoPixmapStorage pm2;
389 pm2.alloc(SkImageInfo::MakeN32(256, 256, kUnpremul_SkAlphaType));
390
391 const SkFilterQuality qualities[] = {
392 kNone_SkFilterQuality, kLow_SkFilterQuality, kMedium_SkFilterQuality, kHigh_SkFilterQuality
393 };
394
395 for (auto fq : qualities) {
396 pm.scalePixels(pm2, fq);
397 slam_ff(pm2);
398 draw_pixmap(canvas, pm2, 10, 10);
399 canvas->translate(pm2.width() + 10.0f, 0);
400 }
401 }
402