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 <functional> 9 #include "gm.h" 10 #include "sk_tool_utils.h" 11 #include "SkAutoPixmapStorage.h" 12 #include "SkData.h" 13 #include "SkCanvas.h" 14 #include "SkRandom.h" 15 #include "SkStream.h" 16 #include "SkSurface.h" 17 18 #if SK_SUPPORT_GPU 19 #include "GrContext.h" 20 #endif 21 22 static void drawJpeg(SkCanvas* canvas, const SkISize& size) { 23 // TODO: Make this draw a file that is checked in, so it can 24 // be exercised on machines other than mike's. Will require a 25 // rebaseline. 26 sk_sp<SkData> data(SkData::MakeFromFileName("/Users/mike/Downloads/skia.google.jpeg")); 27 if (nullptr == data) { 28 return; 29 } 30 sk_sp<SkImage> image = SkImage::MakeFromEncoded(std::move(data)); 31 if (image) { 32 SkAutoCanvasRestore acr(canvas, true); 33 canvas->scale(size.width() * 1.0f / image->width(), 34 size.height() * 1.0f / image->height()); 35 canvas->drawImage(image, 0, 0, nullptr); 36 } 37 } 38 39 static void drawContents(SkSurface* surface, SkColor fillC) { 40 SkSize size = SkSize::Make(SkIntToScalar(surface->width()), 41 SkIntToScalar(surface->height())); 42 SkCanvas* canvas = surface->getCanvas(); 43 44 SkScalar stroke = size.fWidth / 10; 45 SkScalar radius = (size.fWidth - stroke) / 2; 46 47 SkPaint paint; 48 49 paint.setAntiAlias(true); 50 paint.setColor(fillC); 51 canvas->drawCircle(size.fWidth/2, size.fHeight/2, radius, paint); 52 53 paint.setStyle(SkPaint::kStroke_Style); 54 paint.setStrokeWidth(stroke); 55 paint.setColor(SK_ColorBLACK); 56 canvas->drawCircle(size.fWidth/2, size.fHeight/2, radius, paint); 57 } 58 59 static void test_surface(SkCanvas* canvas, SkSurface* surf, bool usePaint) { 60 drawContents(surf, SK_ColorRED); 61 sk_sp<SkImage> imgR = surf->makeImageSnapshot(); 62 63 if (true) { 64 sk_sp<SkImage> imgR2 = surf->makeImageSnapshot(); 65 SkASSERT(imgR == imgR2); 66 } 67 68 drawContents(surf, SK_ColorGREEN); 69 sk_sp<SkImage> imgG = surf->makeImageSnapshot(); 70 71 // since we've drawn after we snapped imgR, imgG will be a different obj 72 SkASSERT(imgR != imgG); 73 74 drawContents(surf, SK_ColorBLUE); 75 76 SkPaint paint; 77 // paint.setFilterBitmap(true); 78 // paint.setAlpha(0x80); 79 80 canvas->drawImage(imgR, 0, 0, usePaint ? &paint : nullptr); 81 canvas->drawImage(imgG, 0, 80, usePaint ? &paint : nullptr); 82 surf->draw(canvas, 0, 160, usePaint ? &paint : nullptr); 83 84 SkRect src1, src2, src3; 85 src1.iset(0, 0, surf->width(), surf->height()); 86 src2.iset(-surf->width() / 2, -surf->height() / 2, 87 surf->width(), surf->height()); 88 src3.iset(0, 0, surf->width() / 2, surf->height() / 2); 89 90 SkRect dst1, dst2, dst3, dst4; 91 dst1.set(0, 240, 65, 305); 92 dst2.set(0, 320, 65, 385); 93 dst3.set(0, 400, 65, 465); 94 dst4.set(0, 480, 65, 545); 95 96 canvas->drawImageRect(imgR, src1, dst1, usePaint ? &paint : nullptr); 97 canvas->drawImageRect(imgG, src2, dst2, usePaint ? &paint : nullptr); 98 canvas->drawImageRect(imgR, src3, dst3, usePaint ? &paint : nullptr); 99 canvas->drawImageRect(imgG, dst4, usePaint ? &paint : nullptr); 100 } 101 102 class ImageGM : public skiagm::GM { 103 void* fBuffer; 104 size_t fBufferSize; 105 SkSize fSize; 106 enum { 107 W = 64, 108 H = 64, 109 RB = W * 4 + 8, 110 }; 111 public: 112 ImageGM() { 113 fBufferSize = RB * H; 114 fBuffer = sk_malloc_throw(fBufferSize); 115 fSize.set(SkIntToScalar(W), SkIntToScalar(H)); 116 } 117 118 ~ImageGM() override { 119 sk_free(fBuffer); 120 } 121 122 protected: 123 SkString onShortName() override { 124 return SkString("image-surface"); 125 } 126 127 SkISize onISize() override { 128 return SkISize::Make(960, 1200); 129 } 130 131 void onDraw(SkCanvas* canvas) override { 132 drawJpeg(canvas, this->getISize()); 133 134 canvas->scale(2, 2); 135 136 const char* kLabel1 = "Original Img"; 137 const char* kLabel2 = "Modified Img"; 138 const char* kLabel3 = "Cur Surface"; 139 const char* kLabel4 = "Full Crop"; 140 const char* kLabel5 = "Over-crop"; 141 const char* kLabel6 = "Upper-left"; 142 const char* kLabel7 = "No Crop"; 143 144 const char* kLabel8 = "Pre-Alloc Img"; 145 const char* kLabel9 = "New Alloc Img"; 146 const char* kLabel10 = "GPU"; 147 148 SkPaint textPaint; 149 textPaint.setAntiAlias(true); 150 sk_tool_utils::set_portable_typeface(&textPaint); 151 textPaint.setTextSize(8); 152 153 canvas->drawString(kLabel1, 10, 60, textPaint); 154 canvas->drawString(kLabel2, 10, 140, textPaint); 155 canvas->drawString(kLabel3, 10, 220, textPaint); 156 canvas->drawString(kLabel4, 10, 300, textPaint); 157 canvas->drawString(kLabel5, 10, 380, textPaint); 158 canvas->drawString(kLabel6, 10, 460, textPaint); 159 canvas->drawString(kLabel7, 10, 540, textPaint); 160 161 canvas->drawString(kLabel8, 80, 10, textPaint); 162 canvas->drawString(kLabel9, 160, 10, textPaint); 163 canvas->drawString(kLabel10, 265, 10, textPaint); 164 165 canvas->translate(80, 20); 166 167 // since we draw into this directly, we need to start fresh 168 sk_bzero(fBuffer, fBufferSize); 169 170 SkImageInfo info = SkImageInfo::MakeN32Premul(W, H); 171 sk_sp<SkSurface> surf0(SkSurface::MakeRasterDirect(info, fBuffer, RB)); 172 sk_sp<SkSurface> surf1(SkSurface::MakeRaster(info)); 173 sk_sp<SkSurface> surf2; // gpu 174 175 #if SK_SUPPORT_GPU 176 surf2 = SkSurface::MakeRenderTarget(canvas->getGrContext(), SkBudgeted::kNo, info); 177 #endif 178 179 test_surface(canvas, surf0.get(), true); 180 canvas->translate(80, 0); 181 test_surface(canvas, surf1.get(), true); 182 if (surf2) { 183 canvas->translate(80, 0); 184 test_surface(canvas, surf2.get(), true); 185 } 186 } 187 188 private: 189 typedef skiagm::GM INHERITED; 190 }; 191 DEF_GM( return new ImageGM; ) 192 193 /////////////////////////////////////////////////////////////////////////////////////////////////// 194 195 #include "SkPictureRecorder.h" 196 197 static void draw_pixmap(SkCanvas* canvas, const SkPixmap& pmap) { 198 SkBitmap bitmap; 199 bitmap.installPixels(pmap); 200 canvas->drawBitmap(bitmap, 0, 0, nullptr); 201 } 202 203 static void show_scaled_pixels(SkCanvas* canvas, SkImage* image) { 204 SkAutoCanvasRestore acr(canvas, true); 205 206 canvas->drawImage(image, 0, 0, nullptr); 207 canvas->translate(110, 10); 208 209 const SkImageInfo info = SkImageInfo::MakeN32Premul(40, 40); 210 SkAutoPixmapStorage storage; 211 storage.alloc(info); 212 213 const SkImage::CachingHint chints[] = { 214 SkImage::kAllow_CachingHint, SkImage::kDisallow_CachingHint, 215 }; 216 const SkFilterQuality qualities[] = { 217 kNone_SkFilterQuality, kLow_SkFilterQuality, kMedium_SkFilterQuality, kHigh_SkFilterQuality, 218 }; 219 220 for (auto ch : chints) { 221 canvas->save(); 222 for (auto q : qualities) { 223 if (image->scalePixels(storage, q, ch)) { 224 draw_pixmap(canvas, storage); 225 } 226 canvas->translate(70, 0); 227 } 228 canvas->restore(); 229 canvas->translate(0, 45); 230 } 231 } 232 233 static void draw_contents(SkCanvas* canvas) { 234 SkPaint paint; 235 paint.setStyle(SkPaint::kStroke_Style); 236 paint.setStrokeWidth(20); 237 canvas->drawCircle(50, 50, 35, paint); 238 } 239 240 static sk_sp<SkImage> make_raster(const SkImageInfo& info, GrContext*, void (*draw)(SkCanvas*)) { 241 auto surface(SkSurface::MakeRaster(info)); 242 draw(surface->getCanvas()); 243 return surface->makeImageSnapshot(); 244 } 245 246 static sk_sp<SkImage> make_picture(const SkImageInfo& info, GrContext*, void (*draw)(SkCanvas*)) { 247 SkPictureRecorder recorder; 248 draw(recorder.beginRecording(SkRect::MakeIWH(info.width(), info.height()))); 249 return SkImage::MakeFromPicture(recorder.finishRecordingAsPicture(), 250 info.dimensions(), nullptr, nullptr, SkImage::BitDepth::kU8, 251 SkColorSpace::MakeSRGB()); 252 } 253 254 static sk_sp<SkImage> make_codec(const SkImageInfo& info, GrContext*, void (*draw)(SkCanvas*)) { 255 sk_sp<SkImage> image(make_raster(info, nullptr, draw)); 256 return SkImage::MakeFromEncoded(image->encodeToData()); 257 } 258 259 static sk_sp<SkImage> make_gpu(const SkImageInfo& info, GrContext* ctx, void (*draw)(SkCanvas*)) { 260 if (!ctx) { return nullptr; } 261 auto surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info)); 262 if (!surface) { return nullptr; } 263 draw(surface->getCanvas()); 264 return surface->makeImageSnapshot(); 265 } 266 267 typedef sk_sp<SkImage> (*ImageMakerProc)(const SkImageInfo&, GrContext*, void (*)(SkCanvas*)); 268 269 class ScalePixelsGM : public skiagm::GM { 270 public: 271 ScalePixelsGM() {} 272 273 protected: 274 SkString onShortName() override { 275 return SkString("scale-pixels"); 276 } 277 278 SkISize onISize() override { 279 return SkISize::Make(960, 1200); 280 } 281 282 void onDraw(SkCanvas* canvas) override { 283 const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100); 284 285 const ImageMakerProc procs[] = { 286 make_codec, make_raster, make_picture, make_codec, make_gpu, 287 }; 288 for (auto& proc : procs) { 289 sk_sp<SkImage> image(proc(info, canvas->getGrContext(), draw_contents)); 290 if (image) { 291 show_scaled_pixels(canvas, image.get()); 292 } 293 canvas->translate(0, 120); 294 } 295 } 296 297 private: 298 typedef skiagm::GM INHERITED; 299 }; 300 DEF_GM( return new ScalePixelsGM; ) 301 302 /////////////////////////////////////////////////////////////////////////////////////////////////// 303 304 DEF_SIMPLE_GM(new_texture_image, canvas, 280, 60) { 305 GrContext* context = canvas->getGrContext(); 306 if (!context) { 307 skiagm::GM::DrawGpuOnlyMessage(canvas); 308 return; 309 } 310 311 auto render_image = [](SkCanvas* canvas) { 312 canvas->clear(SK_ColorBLUE); 313 SkPaint paint; 314 paint.setColor(SK_ColorRED); 315 canvas->drawRect(SkRect::MakeXYWH(10.f,10.f,10.f,10.f), paint); 316 paint.setColor(SK_ColorGREEN); 317 canvas->drawRect(SkRect::MakeXYWH(30.f,10.f,10.f,10.f), paint); 318 paint.setColor(SK_ColorYELLOW); 319 canvas->drawRect(SkRect::MakeXYWH(10.f,30.f,10.f,10.f), paint); 320 paint.setColor(SK_ColorCYAN); 321 canvas->drawRect(SkRect::MakeXYWH(30.f,30.f,10.f,10.f), paint); 322 }; 323 324 static constexpr int kSize = 50; 325 SkBitmap bmp; 326 bmp.allocPixels(SkImageInfo::MakeS32(kSize, kSize, kPremul_SkAlphaType)); 327 SkCanvas bmpCanvas(bmp); 328 render_image(&bmpCanvas); 329 330 std::function<sk_sp<SkImage>()> imageFactories[] = { 331 // Create sw raster image. 332 [bmp] { 333 return SkImage::MakeFromBitmap(bmp); 334 }, 335 // Create encoded image. 336 [bmp] { 337 sk_sp<SkData> src( 338 sk_tool_utils::EncodeImageToData(bmp, SkEncodedImageFormat::kPNG, 100)); 339 return SkImage::MakeFromEncoded(std::move(src)); 340 }, 341 // Create YUV encoded image. 342 [bmp] { 343 sk_sp<SkData> src( 344 sk_tool_utils::EncodeImageToData(bmp, SkEncodedImageFormat::kJPEG, 100)); 345 return SkImage::MakeFromEncoded(std::move(src)); 346 }, 347 // Create a picture image. 348 [render_image] { 349 SkPictureRecorder recorder; 350 SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kSize), SkIntToScalar(kSize)); 351 render_image(canvas); 352 sk_sp<SkColorSpace> srgbColorSpace = SkColorSpace::MakeSRGB(); 353 return SkImage::MakeFromPicture(recorder.finishRecordingAsPicture(), 354 SkISize::Make(kSize, kSize), nullptr, nullptr, 355 SkImage::BitDepth::kU8, srgbColorSpace); 356 }, 357 // Create a texture image 358 [context, render_image]() -> sk_sp<SkImage> { 359 auto surface(SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, 360 SkImageInfo::MakeS32(kSize, kSize, 361 kPremul_SkAlphaType))); 362 if (!surface) { 363 return nullptr; 364 } 365 render_image(surface->getCanvas()); 366 return surface->makeImageSnapshot(); 367 } 368 }; 369 370 constexpr SkScalar kPad = 5.f; 371 canvas->translate(kPad, kPad); 372 for (auto factory : imageFactories) { 373 auto image(factory()); 374 if (image) { 375 sk_sp<SkImage> texImage(image->makeTextureImage(context, 376 canvas->imageInfo().colorSpace())); 377 if (texImage) { 378 canvas->drawImage(texImage, 0, 0); 379 } 380 } 381 canvas->translate(kSize + kPad, 0); 382 } 383 } 384