/* * Copyright 2015 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "gm/gm.h" #include "include/core/SkBitmap.h" #include "include/core/SkCanvas.h" #include "include/core/SkColor.h" #include "include/core/SkColorSpace.h" #include "include/core/SkData.h" #include "include/core/SkEncodedImageFormat.h" #include "include/core/SkImage.h" #include "include/core/SkImageInfo.h" #include "include/core/SkMatrix.h" #include "include/core/SkPaint.h" #include "include/core/SkPicture.h" #include "include/core/SkPictureRecorder.h" #include "include/core/SkRect.h" #include "include/core/SkRefCnt.h" #include "include/core/SkShader.h" #include "include/core/SkSize.h" #include "include/core/SkString.h" #include "include/core/SkSurface.h" #include "include/core/SkTileMode.h" #include "include/core/SkTypes.h" #include static void draw_something(SkCanvas* canvas, const SkRect& bounds) { SkPaint paint; paint.setAntiAlias(true); paint.setColor(SK_ColorRED); paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(10); canvas->drawRect(bounds, paint); paint.setStyle(SkPaint::kFill_Style); paint.setColor(SK_ColorBLUE); canvas->drawOval(bounds, paint); } typedef sk_sp (*ImageMakerProc)(GrRecordingContext*, SkPicture*, const SkImageInfo&); static sk_sp make_raster(GrRecordingContext*, SkPicture* pic, const SkImageInfo& info) { auto surface(SkSurface::MakeRaster(info)); surface->getCanvas()->clear(0); surface->getCanvas()->drawPicture(pic); return surface->makeImageSnapshot(); } static sk_sp make_texture(GrRecordingContext* ctx, SkPicture* pic, const SkImageInfo& info) { if (!ctx) { return nullptr; } auto surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info)); if (!surface) { return nullptr; } surface->getCanvas()->clear(0); surface->getCanvas()->drawPicture(pic); return surface->makeImageSnapshot(); } static sk_sp make_pict_gen(GrRecordingContext*, SkPicture* pic, const SkImageInfo& info) { return SkImage::MakeFromPicture(sk_ref_sp(pic), info.dimensions(), nullptr, nullptr, SkImage::BitDepth::kU8, SkColorSpace::MakeSRGB()); } static sk_sp make_encode_gen(GrRecordingContext* ctx, SkPicture* pic, const SkImageInfo& info) { sk_sp src(make_raster(ctx, pic, info)); if (!src) { return nullptr; } sk_sp encoded = src->encodeToData(SkEncodedImageFormat::kPNG, 100); if (!encoded) { return nullptr; } return SkImage::MakeFromEncoded(std::move(encoded)); } const ImageMakerProc gProcs[] = { make_raster, make_texture, make_pict_gen, make_encode_gen, }; /* * Exercise drawing pictures inside an image, showing that the image version is pixelated * (correctly) when it is inside an image. */ class ImageShaderGM : public skiagm::GM { sk_sp fPicture; public: ImageShaderGM() {} protected: SkString onShortName() override { return SkString("image-shader"); } SkISize onISize() override { return SkISize::Make(850, 450); } void onOnceBeforeDraw() override { const SkRect bounds = SkRect::MakeWH(100, 100); SkPictureRecorder recorder; draw_something(recorder.beginRecording(bounds), bounds); fPicture = recorder.finishRecordingAsPicture(); } void testImage(SkCanvas* canvas, SkImage* image) { SkAutoCanvasRestore acr(canvas, true); canvas->drawImage(image, 0, 0); canvas->translate(0, 120); const SkTileMode tile = SkTileMode::kRepeat; const SkMatrix localM = SkMatrix::Translate(-50, -50); SkPaint paint; paint.setShader(image->makeShader(tile, tile, SkSamplingOptions(), &localM)); paint.setAntiAlias(true); canvas->drawCircle(50, 50, 50, paint); } void onDraw(SkCanvas* canvas) override { canvas->translate(20, 20); const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100); for (size_t i = 0; i < SK_ARRAY_COUNT(gProcs); ++i) { sk_sp image(gProcs[i](canvas->recordingContext(), fPicture.get(), info)); if (image) { this->testImage(canvas, image.get()); } canvas->translate(120, 0); } } private: using INHERITED = skiagm::GM; }; DEF_GM( return new ImageShaderGM; ) ////////////////////////////////////////////////////////////////////////////////////////////// #include "tools/ToolUtils.h" static sk_sp make_checker_img(int w, int h, SkColor c0, SkColor c1, int size) { SkBitmap bm = ToolUtils::create_checkerboard_bitmap(w, h, c0, c1, size); bm.setImmutable(); return bm.asImage(); } DEF_SIMPLE_GM(drawimage_sampling, canvas, 500, 500) { constexpr int N = 256; constexpr float kScale = 1.0f/6; const SkRect dst = {0, 0, kScale*N, kScale*N}; auto img = make_checker_img(N, N, SK_ColorBLACK, SK_ColorWHITE, 7)->withDefaultMipmaps(); const SkRect src = SkRect::MakeIWH(img->width(), img->height()); SkMatrix mx = SkMatrix::RectToRect(src, dst); SkPaint paint; for (auto mm : {SkMipmapMode::kNone, SkMipmapMode::kNearest, SkMipmapMode::kLinear}) { for (auto fm : {SkFilterMode::kNearest, SkFilterMode::kLinear}) { SkSamplingOptions sampling(fm, mm); canvas->save(); canvas->save(); canvas->concat(mx); canvas->drawImage(img.get(), 0, 0, sampling); canvas->restore(); canvas->translate(dst.width() + 4, 0); paint.setShader(img->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, sampling, &mx)); canvas->drawRect(dst, paint); canvas->translate(dst.width() + 4, 0); canvas->drawImageRect(img.get(), src, dst, sampling, nullptr, SkCanvas::kFast_SrcRectConstraint); canvas->restore(); canvas->translate(0, dst.height() + 8); } } } // Test case for skbug.com/12685 (texture-backed image shaders silently fail drawing to CPU canvas) DEF_SIMPLE_GM(textureimage_and_shader, canvas, 100, 50) { canvas->clear(SK_ColorGREEN); sk_sp image; if (canvas->getSurface()) { image = canvas->getSurface()->makeImageSnapshot(); canvas->clear(SK_ColorRED); } else { auto greenSurface = SkSurface::MakeRasterN32Premul(50, 50); greenSurface->getCanvas()->clear(SK_ColorGREEN); image = greenSurface->makeImageSnapshot(); } // At this point, 'image' contains a green image. If our original canvas is GPU-backed, then // the snapped image will be a (GPU) texture. We will try to draw that image to a non-GPU // surface, to ensure that we get automatic read-back. If all goes well, we will get a pure // green result. If either draw fails, we'll get red (most likely). auto surface = SkSurface::MakeRasterN32Premul(50, 50); // First, use drawImage: surface->getCanvas()->clear(SK_ColorRED); surface->getCanvas()->drawImage(image, 0, 0); canvas->drawImage(surface->makeImageSnapshot(), 0, 0); // Now, use an image shader: SkPaint paint; paint.setShader(image->makeShader(SkSamplingOptions())); surface->getCanvas()->clear(SK_ColorRED); surface->getCanvas()->drawPaint(paint); canvas->drawImage(surface->makeImageSnapshot(), 50, 0); }