• 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 <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