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