imagefilters.cpp revision 5f500920e719b215d5e0e36a6679995ed3c9b4ad
17e4186accea094276c9f3c65c64e63ffc59aa644reed/* 27e4186accea094276c9f3c65c64e63ffc59aa644reed * Copyright 2015 Google Inc. 37e4186accea094276c9f3c65c64e63ffc59aa644reed * 47e4186accea094276c9f3c65c64e63ffc59aa644reed * Use of this source code is governed by a BSD-style license that can be 57e4186accea094276c9f3c65c64e63ffc59aa644reed * found in the LICENSE file. 67e4186accea094276c9f3c65c64e63ffc59aa644reed */ 77e4186accea094276c9f3c65c64e63ffc59aa644reed 87e4186accea094276c9f3c65c64e63ffc59aa644reed#include "gm.h" 9f65fb658147da97b5010276fe99f15952e6333e3reed#include "SkBlurImageFilter.h" 107e4186accea094276c9f3c65c64e63ffc59aa644reed#include "SkColorMatrixFilter.h" 11f65fb658147da97b5010276fe99f15952e6333e3reed#include "SkImage.h" 12f65fb658147da97b5010276fe99f15952e6333e3reed#include "SkImageFilter.h" 13f65fb658147da97b5010276fe99f15952e6333e3reed#include "SkSurface.h" 147e4186accea094276c9f3c65c64e63ffc59aa644reed 157e4186accea094276c9f3c65c64e63ffc59aa644reed/** 167e4186accea094276c9f3c65c64e63ffc59aa644reed * Test drawing a primitive w/ an imagefilter (in this case, just matrix w/ identity) to see 177e4186accea094276c9f3c65c64e63ffc59aa644reed * that we apply the xfermode *after* the image has been created and filtered, and not during 187e4186accea094276c9f3c65c64e63ffc59aa644reed * the creation step (i.e. before it is filtered). 197e4186accea094276c9f3c65c64e63ffc59aa644reed * 206950de6c4166fabb35e6c756fc009e0cf1c47819halcanary * see https://bug.skia.org/3741 217e4186accea094276c9f3c65c64e63ffc59aa644reed */ 22374772bd61951f01bf84fe17bf53d8867681c9aereedstatic void do_draw(SkCanvas* canvas, SkBlendMode mode, sk_sp<SkImageFilter> imf) { 2349124378913f3467eb67e653b3b48f80899a3f37reed SkAutoCanvasRestore acr(canvas, true); 2449124378913f3467eb67e653b3b48f80899a3f37reed canvas->clipRect(SkRect::MakeWH(220, 220)); 25467ddc0b24a63ee1525fa18d1dcf62e47975588axidachen 2649124378913f3467eb67e653b3b48f80899a3f37reed // want to force a layer, so modes like DstIn can combine meaningfully, but the final 2749124378913f3467eb67e653b3b48f80899a3f37reed // image can still be shown against our default (opaque) background. non-opaque GMs 2849124378913f3467eb67e653b3b48f80899a3f37reed // are a lot more trouble to compare/triage. 2996fcdcc219d2a0d3579719b84b28bede76efba64halcanary canvas->saveLayer(nullptr, nullptr); 3049124378913f3467eb67e653b3b48f80899a3f37reed canvas->drawColor(SK_ColorGREEN); 3149124378913f3467eb67e653b3b48f80899a3f37reed 327e4186accea094276c9f3c65c64e63ffc59aa644reed SkPaint paint; 337e4186accea094276c9f3c65c64e63ffc59aa644reed paint.setAntiAlias(true); 34467ddc0b24a63ee1525fa18d1dcf62e47975588axidachen 357e4186accea094276c9f3c65c64e63ffc59aa644reed SkRect r0 = SkRect::MakeXYWH(10, 60, 200, 100); 367e4186accea094276c9f3c65c64e63ffc59aa644reed SkRect r1 = SkRect::MakeXYWH(60, 10, 100, 200); 37467ddc0b24a63ee1525fa18d1dcf62e47975588axidachen 387e4186accea094276c9f3c65c64e63ffc59aa644reed paint.setColor(SK_ColorRED); 397e4186accea094276c9f3c65c64e63ffc59aa644reed canvas->drawOval(r0, paint); 407e4186accea094276c9f3c65c64e63ffc59aa644reed 4149124378913f3467eb67e653b3b48f80899a3f37reed paint.setColor(0x660000FF); 42ae8c933ca89315c1256bcf23749b5ee5cbc0d53crobertphillips paint.setImageFilter(std::move(imf)); 43374772bd61951f01bf84fe17bf53d8867681c9aereed paint.setBlendMode(mode); 447e4186accea094276c9f3c65c64e63ffc59aa644reed canvas->drawOval(r1, paint); 452a24338c777462e04a2b26295f9c034155ee8f3ehalcanary} 467e4186accea094276c9f3c65c64e63ffc59aa644reed 472a24338c777462e04a2b26295f9c034155ee8f3ehalcanaryDEF_SIMPLE_GM(imagefilters_xfermodes, canvas, 480, 480) { 4849124378913f3467eb67e653b3b48f80899a3f37reed canvas->translate(10, 10); 4949124378913f3467eb67e653b3b48f80899a3f37reed 507e4186accea094276c9f3c65c64e63ffc59aa644reed // just need an imagefilter to trigger the code-path (which creates a tmp layer) 51ae8c933ca89315c1256bcf23749b5ee5cbc0d53crobertphillips sk_sp<SkImageFilter> imf(SkImageFilter::MakeMatrixFilter(SkMatrix::I(), 52ae8c933ca89315c1256bcf23749b5ee5cbc0d53crobertphillips kNone_SkFilterQuality, 53ae8c933ca89315c1256bcf23749b5ee5cbc0d53crobertphillips nullptr)); 547e4186accea094276c9f3c65c64e63ffc59aa644reed 55374772bd61951f01bf84fe17bf53d8867681c9aereed const SkBlendMode modes[] = { 56374772bd61951f01bf84fe17bf53d8867681c9aereed SkBlendMode::kSrcATop, SkBlendMode::kDstIn 577e4186accea094276c9f3c65c64e63ffc59aa644reed }; 58467ddc0b24a63ee1525fa18d1dcf62e47975588axidachen 597e4186accea094276c9f3c65c64e63ffc59aa644reed for (size_t i = 0; i < SK_ARRAY_COUNT(modes); ++i) { 607e4186accea094276c9f3c65c64e63ffc59aa644reed canvas->save(); 612a24338c777462e04a2b26295f9c034155ee8f3ehalcanary do_draw(canvas, modes[i], nullptr); 6249124378913f3467eb67e653b3b48f80899a3f37reed canvas->translate(240, 0); 632a24338c777462e04a2b26295f9c034155ee8f3ehalcanary do_draw(canvas, modes[i], imf); 647e4186accea094276c9f3c65c64e63ffc59aa644reed canvas->restore(); 65467ddc0b24a63ee1525fa18d1dcf62e47975588axidachen 6649124378913f3467eb67e653b3b48f80899a3f37reed canvas->translate(0, 240); 677e4186accea094276c9f3c65c64e63ffc59aa644reed } 682a24338c777462e04a2b26295f9c034155ee8f3ehalcanary} 69f65fb658147da97b5010276fe99f15952e6333e3reed 709ce9d6772df650ceb0511f275e1a83dffa78ff72reedstatic sk_sp<SkImage> make_image(SkCanvas* canvas) { 715f500920e719b215d5e0e36a6679995ed3c9b4adBrian Osman const SkImageInfo info = SkImageInfo::MakeS32(100, 100, kPremul_SkAlphaType); 72e8f3062a36d3682f4019309a32b5b84dc9eddf8creed auto surface(canvas->makeSurface(info)); 73f65fb658147da97b5010276fe99f15952e6333e3reed if (!surface) { 74e8f3062a36d3682f4019309a32b5b84dc9eddf8creed surface = SkSurface::MakeRaster(info); 75f65fb658147da97b5010276fe99f15952e6333e3reed } 76f65fb658147da97b5010276fe99f15952e6333e3reed surface->getCanvas()->drawRect(SkRect::MakeXYWH(25, 25, 50, 50), SkPaint()); 779ce9d6772df650ceb0511f275e1a83dffa78ff72reed return surface->makeImageSnapshot(); 78f65fb658147da97b5010276fe99f15952e6333e3reed} 79f65fb658147da97b5010276fe99f15952e6333e3reed 80f65fb658147da97b5010276fe99f15952e6333e3reed// Compare blurs when we're tightly clipped (fast) and not as tightly (slower) 81f65fb658147da97b5010276fe99f15952e6333e3reed// 82f65fb658147da97b5010276fe99f15952e6333e3reed// Expect the two to draw the same (modulo the extra border of pixels when the clip is larger) 83f65fb658147da97b5010276fe99f15952e6333e3reed// 84f65fb658147da97b5010276fe99f15952e6333e3reedDEF_SIMPLE_GM(fast_slow_blurimagefilter, canvas, 620, 260) { 859ce9d6772df650ceb0511f275e1a83dffa78ff72reed sk_sp<SkImage> image(make_image(canvas)); 86f65fb658147da97b5010276fe99f15952e6333e3reed const SkRect r = SkRect::MakeIWH(image->width(), image->height()); 87f65fb658147da97b5010276fe99f15952e6333e3reed 88f65fb658147da97b5010276fe99f15952e6333e3reed canvas->translate(10, 10); 89f65fb658147da97b5010276fe99f15952e6333e3reed for (SkScalar sigma = 8; sigma <= 128; sigma *= 2) { 90f65fb658147da97b5010276fe99f15952e6333e3reed SkPaint paint; 916e7025ab13dfc4f0037233e67b4b8e18d6dfd1e1robertphillips paint.setImageFilter(SkBlurImageFilter::Make(sigma, sigma, nullptr)); 92f65fb658147da97b5010276fe99f15952e6333e3reed 93f65fb658147da97b5010276fe99f15952e6333e3reed canvas->save(); 94f65fb658147da97b5010276fe99f15952e6333e3reed // we outset the clip by 1, to fall out of the fast-case in drawImage 95f65fb658147da97b5010276fe99f15952e6333e3reed // i.e. the clip is larger than the image 96f65fb658147da97b5010276fe99f15952e6333e3reed for (SkScalar outset = 0; outset <= 1; ++outset) { 97f65fb658147da97b5010276fe99f15952e6333e3reed canvas->save(); 98f65fb658147da97b5010276fe99f15952e6333e3reed canvas->clipRect(r.makeOutset(outset, outset)); 99f65fb658147da97b5010276fe99f15952e6333e3reed canvas->drawImage(image, 0, 0, &paint); 100f65fb658147da97b5010276fe99f15952e6333e3reed canvas->restore(); 101f65fb658147da97b5010276fe99f15952e6333e3reed canvas->translate(0, r.height() + 20); 102f65fb658147da97b5010276fe99f15952e6333e3reed } 103f65fb658147da97b5010276fe99f15952e6333e3reed canvas->restore(); 104f65fb658147da97b5010276fe99f15952e6333e3reed canvas->translate(r.width() + 20, 0); 105f65fb658147da97b5010276fe99f15952e6333e3reed } 106f65fb658147da97b5010276fe99f15952e6333e3reed} 107bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed 108bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed/////////////////////////////////////////////////////////////////////////////////////////////////// 109bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed#include "Resources.h" 110bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed#include "SkBlurImageFilter.h" 111bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed#include "SkMatrixConvolutionImageFilter.h" 112bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed#include "SkMorphologyImageFilter.h" 113bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed#include "SkColorMatrixFilter.h" 114bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed#include "SkColorFilterImageFilter.h" 115bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed#include "SkRRect.h" 116bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed 117ef6a47b4af1ebf621682b3398916fefb90fc912erobertphillipsstatic void draw_set(SkCanvas* canvas, sk_sp<SkImageFilter> filters[], int count) { 118bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed const SkRect r = SkRect::MakeXYWH(30, 30, 200, 200); 119bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed const SkScalar offset = 250; 120bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed SkScalar dx = 0, dy = 0; 121bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed 122bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed for (int i = 0; i < count; ++i) { 123bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed canvas->save(); 124bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed SkRRect rr = SkRRect::MakeRectXY(r.makeOffset(dx, dy), 20, 20); 125669983856d99b9312be3166b7dd1f8483a90c315reed canvas->clipRRect(rr, true); 126ef6a47b4af1ebf621682b3398916fefb90fc912erobertphillips canvas->saveLayer({ &rr.getBounds(), nullptr, filters[i].get(), 0 }); 127bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed canvas->drawColor(0x40FFFFFF); 128bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed canvas->restore(); 129bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed canvas->restore(); 130bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed 131bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed if (0 == dx) { 132bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed dx = offset; 133bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed } else { 134bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed dx = 0; 135bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed dy = offset; 136bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed } 137bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed } 138bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed} 139bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed 140bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areedDEF_SIMPLE_GM(savelayer_with_backdrop, canvas, 830, 550) { 141bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed SkColorMatrix cm; 142bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed cm.setSaturation(10); 143fc11b0afe0ca922a42767d4a656ed640008da1bbrobertphillips sk_sp<SkColorFilter> cf(SkColorFilter::MakeMatrixFilterRowMajor255(cm.fMat)); 144bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed const SkScalar kernel[] = { 4, 0, 4, 0, -15, 0, 4, 0, 4 }; 145ef6a47b4af1ebf621682b3398916fefb90fc912erobertphillips sk_sp<SkImageFilter> filters[] = { 146ef6a47b4af1ebf621682b3398916fefb90fc912erobertphillips SkBlurImageFilter::Make(10, 10, nullptr), 147ef6a47b4af1ebf621682b3398916fefb90fc912erobertphillips SkDilateImageFilter::Make(8, 8, nullptr), 148ef6a47b4af1ebf621682b3398916fefb90fc912erobertphillips SkMatrixConvolutionImageFilter::Make( 149ef6a47b4af1ebf621682b3398916fefb90fc912erobertphillips { 3, 3 }, kernel, 1, 0, { 0, 0 }, 150bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed SkMatrixConvolutionImageFilter::kClampToBlack_TileMode, 151ef6a47b4af1ebf621682b3398916fefb90fc912erobertphillips true, nullptr), 152ef6a47b4af1ebf621682b3398916fefb90fc912erobertphillips SkColorFilterImageFilter::Make(std::move(cf), nullptr), 153bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed }; 154bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed 155bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed const struct { 156bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed SkScalar fSx, fSy, fTx, fTy; 157bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed } xforms[] = { 158bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed { 1, 1, 0, 0 }, 159bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed { 0.5f, 0.5f, 530, 0 }, 160bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed { 0.25f, 0.25f, 530, 275 }, 161bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed { 0.125f, 0.125f, 530, 420 }, 162bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed }; 163bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed 164bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed SkPaint paint; 165bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed paint.setFilterQuality(kMedium_SkFilterQuality); 1669ce9d6772df650ceb0511f275e1a83dffa78ff72reed sk_sp<SkImage> image(GetResourceAsImage("mandrill_512.png")); 167bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed 168bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed canvas->translate(20, 20); 169bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed for (const auto& xform : xforms) { 170bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed canvas->save(); 171bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed canvas->translate(xform.fTx, xform.fTy); 172bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed canvas->scale(xform.fSx, xform.fSy); 173bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed canvas->drawImage(image, 0, 0, &paint); 174bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed draw_set(canvas, filters, SK_ARRAY_COUNT(filters)); 175bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed canvas->restore(); 176bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed } 177bfd5f171e6a3eccd7c4bede652a85fd76bcbce2areed} 178