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