Home | History | Annotate | Download | only in gm
      1 /*
      2  * Copyright 2012 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.h"
      9 #include "sk_tool_utils.h"
     10 #include "SkColor.h"
     11 #include "SkGradientShader.h"
     12 #include "SkMatrixConvolutionImageFilter.h"
     13 #include "SkPixelRef.h"
     14 
     15 namespace skiagm {
     16 
     17 class MatrixConvolutionGM : public GM {
     18 public:
     19     MatrixConvolutionGM(SkColor colorOne, SkColor colorTwo, const char* nameSuffix)
     20             : fNameSuffix(nameSuffix) {
     21         this->setBGColor(0x00000000);
     22         fColors[0] = colorOne;
     23         fColors[1] = colorTwo;
     24     }
     25 
     26 protected:
     27 
     28     SkString onShortName() override {
     29         return SkStringPrintf("matrixconvolution%s", fNameSuffix);
     30     }
     31 
     32     void makeBitmap() {
     33         // Draw our bitmap in N32, so legacy devices get "premul" values they understand
     34         SkBitmap n32Bitmap;
     35         n32Bitmap.allocN32Pixels(80, 80);
     36         SkCanvas canvas(n32Bitmap);
     37         canvas.clear(0x00000000);
     38         SkPaint paint;
     39         paint.setAntiAlias(true);
     40         sk_tool_utils::set_portable_typeface(&paint);
     41         paint.setColor(0xFFFFFFFF);
     42         paint.setTextSize(SkIntToScalar(180));
     43         SkPoint pts[2] = { SkPoint::Make(0, 0),
     44                            SkPoint::Make(0, SkIntToScalar(80)) };
     45         SkScalar pos[2] = { 0, SkIntToScalar(80) };
     46         paint.setShader(SkGradientShader::MakeLinear(
     47             pts, fColors, pos, 2, SkShader::kClamp_TileMode));
     48         const char* str = "e";
     49         canvas.drawString(str, SkIntToScalar(-10), SkIntToScalar(80), paint);
     50 
     51         // ... tag the data as sRGB, so color-aware devices do gamut adjustment, etc...
     52         fBitmap.setInfo(SkImageInfo::MakeS32(80, 80, kPremul_SkAlphaType));
     53         fBitmap.setPixelRef(sk_ref_sp(n32Bitmap.pixelRef()), 0, 0);
     54     }
     55 
     56     SkISize onISize() override {
     57         return SkISize::Make(500, 300);
     58     }
     59 
     60     void draw(SkCanvas* canvas, int x, int y, const SkIPoint& kernelOffset,
     61               SkMatrixConvolutionImageFilter::TileMode tileMode, bool convolveAlpha,
     62               const SkImageFilter::CropRect* cropRect = nullptr) {
     63         SkScalar kernel[9] = {
     64             SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
     65             SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1),
     66             SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
     67         };
     68         SkISize kernelSize = SkISize::Make(3, 3);
     69         SkScalar gain = 0.3f, bias = SkIntToScalar(100);
     70         if (canvas->imageInfo().colorSpace()) {
     71             // TODO: Gain and bias are poorly specified (in the feConvolveMatrix SVG documentation,
     72             // there is obviously no mention of gamma or color spaces). Eventually, we need to
     73             // decide what to do with these (they generally have an extreme brightening effect).
     74             // For now, I'm modifying this GM to use values tuned to preserve luminance across the
     75             // range of input values (compared to the legacy math and values).
     76             //
     77             // It's impossible to match the results exactly, because legacy math produces a flat
     78             // response (when looking at sRGB encoded results), while gamma-correct math produces
     79             // a curve.
     80             gain = 0.25f;
     81             bias = 16.5f;
     82         }
     83         SkPaint paint;
     84         paint.setImageFilter(SkMatrixConvolutionImageFilter::Make(kernelSize,
     85                                                                   kernel,
     86                                                                   gain,
     87                                                                   bias,
     88                                                                   kernelOffset,
     89                                                                   tileMode,
     90                                                                   convolveAlpha,
     91                                                                   nullptr,
     92                                                                   cropRect));
     93         canvas->save();
     94         canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
     95         canvas->clipRect(SkRect::MakeWH(SkIntToScalar(fBitmap.width()),
     96                                         SkIntToScalar(fBitmap.height())));
     97         canvas->drawBitmap(fBitmap, 0, 0, &paint);
     98         canvas->restore();
     99     }
    100 
    101     typedef SkMatrixConvolutionImageFilter MCIF;
    102 
    103     void onOnceBeforeDraw() override {
    104         this->makeBitmap();
    105     }
    106 
    107     void onDraw(SkCanvas* canvas) override {
    108         canvas->clear(SK_ColorBLACK);
    109         SkIPoint kernelOffset = SkIPoint::Make(1, 0);
    110         SkImageFilter::CropRect rect(SkRect::Make(fBitmap.bounds()));
    111         for (int x = 10; x < 310; x += 100) {
    112             this->draw(canvas, x, 10, kernelOffset, MCIF::kClamp_TileMode, true, &rect);
    113             this->draw(canvas, x, 110, kernelOffset, MCIF::kClampToBlack_TileMode, true, &rect);
    114             this->draw(canvas, x, 210, kernelOffset, MCIF::kRepeat_TileMode, true, &rect);
    115             kernelOffset.fY++;
    116         }
    117         kernelOffset.fY = 1;
    118         SkImageFilter::CropRect smallRect(SkRect::MakeXYWH(10, 5, 60, 60));
    119         this->draw(canvas, 310, 10, kernelOffset, MCIF::kClamp_TileMode, true, &smallRect);
    120         this->draw(canvas, 310, 110, kernelOffset, MCIF::kClampToBlack_TileMode, true, &smallRect);
    121         this->draw(canvas, 310, 210, kernelOffset, MCIF::kRepeat_TileMode, true, &smallRect);
    122 
    123         this->draw(canvas, 410, 10, kernelOffset, MCIF::kClamp_TileMode, false, &rect);
    124         this->draw(canvas, 410, 110, kernelOffset, MCIF::kClampToBlack_TileMode, false, &rect);
    125         this->draw(canvas, 410, 210, kernelOffset, MCIF::kRepeat_TileMode, false, &rect);
    126     }
    127 
    128 private:
    129     SkBitmap fBitmap;
    130     SkColor fColors[2];
    131     const char* fNameSuffix;
    132 
    133     typedef GM INHERITED;
    134 };
    135 
    136 //////////////////////////////////////////////////////////////////////////////
    137 
    138 DEF_GM(return new MatrixConvolutionGM(0xFFFFFFFF, 0x40404040, "");)
    139 DEF_GM(return new MatrixConvolutionGM(0xFFFF0000, 0xFF00FF00, "_color");)
    140 
    141 }
    142