Home | History | Annotate | Download | only in gm
      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