1/* 2 * Copyright 2015 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/SkColorSpace.h" 13#include "include/core/SkData.h" 14#include "include/core/SkEncodedImageFormat.h" 15#include "include/core/SkImage.h" 16#include "include/core/SkImageInfo.h" 17#include "include/core/SkMatrix.h" 18#include "include/core/SkPaint.h" 19#include "include/core/SkPicture.h" 20#include "include/core/SkPictureRecorder.h" 21#include "include/core/SkRect.h" 22#include "include/core/SkRefCnt.h" 23#include "include/core/SkShader.h" 24#include "include/core/SkSize.h" 25#include "include/core/SkString.h" 26#include "include/core/SkSurface.h" 27#include "include/core/SkTileMode.h" 28#include "include/core/SkTypes.h" 29 30#include <utility> 31 32static void draw_something(SkCanvas* canvas, const SkRect& bounds) { 33 SkPaint paint; 34 paint.setAntiAlias(true); 35 paint.setColor(SK_ColorRED); 36 paint.setStyle(SkPaint::kStroke_Style); 37 paint.setStrokeWidth(10); 38 canvas->drawRect(bounds, paint); 39 paint.setStyle(SkPaint::kFill_Style); 40 paint.setColor(SK_ColorBLUE); 41 canvas->drawOval(bounds, paint); 42} 43 44typedef sk_sp<SkImage> (*ImageMakerProc)(GrRecordingContext*, SkPicture*, const SkImageInfo&); 45 46static sk_sp<SkImage> make_raster(GrRecordingContext*, 47 SkPicture* pic, 48 const SkImageInfo& info) { 49 auto surface(SkSurface::MakeRaster(info)); 50 surface->getCanvas()->clear(0); 51 surface->getCanvas()->drawPicture(pic); 52 return surface->makeImageSnapshot(); 53} 54 55static sk_sp<SkImage> make_texture(GrRecordingContext* ctx, 56 SkPicture* pic, 57 const SkImageInfo& info) { 58 if (!ctx) { 59 return nullptr; 60 } 61 auto surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info)); 62 if (!surface) { 63 return nullptr; 64 } 65 surface->getCanvas()->clear(0); 66 surface->getCanvas()->drawPicture(pic); 67 return surface->makeImageSnapshot(); 68} 69 70static sk_sp<SkImage> make_pict_gen(GrRecordingContext*, 71 SkPicture* pic, 72 const SkImageInfo& info) { 73 return SkImage::MakeFromPicture(sk_ref_sp(pic), info.dimensions(), nullptr, nullptr, 74 SkImage::BitDepth::kU8, 75 SkColorSpace::MakeSRGB()); 76} 77 78static sk_sp<SkImage> make_encode_gen(GrRecordingContext* ctx, 79 SkPicture* pic, 80 const SkImageInfo& info) { 81 sk_sp<SkImage> src(make_raster(ctx, pic, info)); 82 if (!src) { 83 return nullptr; 84 } 85 sk_sp<SkData> encoded = src->encodeToData(SkEncodedImageFormat::kPNG, 100); 86 if (!encoded) { 87 return nullptr; 88 } 89 return SkImage::MakeFromEncoded(std::move(encoded)); 90} 91 92const ImageMakerProc gProcs[] = { 93 make_raster, 94 make_texture, 95 make_pict_gen, 96 make_encode_gen, 97}; 98 99/* 100 * Exercise drawing pictures inside an image, showing that the image version is pixelated 101 * (correctly) when it is inside an image. 102 */ 103class ImageShaderGM : public skiagm::GM { 104 sk_sp<SkPicture> fPicture; 105 106public: 107 ImageShaderGM() {} 108 109protected: 110 SkString onShortName() override { 111 return SkString("image-shader"); 112 } 113 114 SkISize onISize() override { 115 return SkISize::Make(850, 450); 116 } 117 118 void onOnceBeforeDraw() override { 119 const SkRect bounds = SkRect::MakeWH(100, 100); 120 SkPictureRecorder recorder; 121 draw_something(recorder.beginRecording(bounds), bounds); 122 fPicture = recorder.finishRecordingAsPicture(); 123 } 124 125 void testImage(SkCanvas* canvas, SkImage* image) { 126 SkAutoCanvasRestore acr(canvas, true); 127 128 canvas->drawImage(image, 0, 0); 129 canvas->translate(0, 120); 130 131 const SkTileMode tile = SkTileMode::kRepeat; 132 const SkMatrix localM = SkMatrix::Translate(-50, -50); 133 SkPaint paint; 134 paint.setShader(image->makeShader(tile, tile, SkSamplingOptions(), &localM)); 135 paint.setAntiAlias(true); 136 canvas->drawCircle(50, 50, 50, paint); 137 } 138 139 void onDraw(SkCanvas* canvas) override { 140 canvas->translate(20, 20); 141 142 const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100); 143 144 for (size_t i = 0; i < SK_ARRAY_COUNT(gProcs); ++i) { 145 sk_sp<SkImage> image(gProcs[i](canvas->recordingContext(), fPicture.get(), info)); 146 if (image) { 147 this->testImage(canvas, image.get()); 148 } 149 canvas->translate(120, 0); 150 } 151 } 152 153private: 154 using INHERITED = skiagm::GM; 155}; 156DEF_GM( return new ImageShaderGM; ) 157 158////////////////////////////////////////////////////////////////////////////////////////////// 159 160#include "tools/ToolUtils.h" 161 162static sk_sp<SkImage> make_checker_img(int w, int h, SkColor c0, SkColor c1, int size) { 163 SkBitmap bm = ToolUtils::create_checkerboard_bitmap(w, h, c0, c1, size); 164 bm.setImmutable(); 165 return bm.asImage(); 166} 167 168DEF_SIMPLE_GM(drawimage_sampling, canvas, 500, 500) { 169 constexpr int N = 256; 170 constexpr float kScale = 1.0f/6; 171 const SkRect dst = {0, 0, kScale*N, kScale*N}; 172 173 auto img = make_checker_img(N, N, SK_ColorBLACK, SK_ColorWHITE, 7)->withDefaultMipmaps(); 174 const SkRect src = SkRect::MakeIWH(img->width(), img->height()); 175 176 SkMatrix mx = SkMatrix::RectToRect(src, dst); 177 178 SkPaint paint; 179 180 for (auto mm : {SkMipmapMode::kNone, SkMipmapMode::kNearest, SkMipmapMode::kLinear}) { 181 for (auto fm : {SkFilterMode::kNearest, SkFilterMode::kLinear}) { 182 SkSamplingOptions sampling(fm, mm); 183 184 canvas->save(); 185 186 canvas->save(); 187 canvas->concat(mx); 188 canvas->drawImage(img.get(), 0, 0, sampling); 189 canvas->restore(); 190 191 canvas->translate(dst.width() + 4, 0); 192 193 paint.setShader(img->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, sampling, &mx)); 194 canvas->drawRect(dst, paint); 195 196 canvas->translate(dst.width() + 4, 0); 197 198 canvas->drawImageRect(img.get(), src, dst, sampling, nullptr, 199 SkCanvas::kFast_SrcRectConstraint); 200 canvas->restore(); 201 202 canvas->translate(0, dst.height() + 8); 203 } 204 } 205 206} 207