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