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