Home | History | Annotate | Download | only in samplecode
      1 /*
      2  * Copyright 2013 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.h"
      9 
     10 #include "sk_tool_utils.h"
     11 #include "DecodeFile.h"
     12 #include "Resources.h"
     13 #include "SampleCode.h"
     14 #include "SkBlurMask.h"
     15 #include "SkBlurDrawLooper.h"
     16 #include "SkCanvas.h"
     17 #include "SkColorPriv.h"
     18 #include "SkOSFile.h"
     19 #include "SkOSPath.h"
     20 #include "SkStream.h"
     21 #include "SkString.h"
     22 #include "SkTypes.h"
     23 #include "SkUtils.h"
     24 #include "SkView.h"
     25 
     26 /**
     27  *  Interprets c as an unpremultiplied color, and returns the
     28  *  premultiplied equivalent.
     29  */
     30 static SkPMColor premultiply_unpmcolor(SkPMColor c) {
     31     U8CPU a = SkGetPackedA32(c);
     32     U8CPU r = SkGetPackedR32(c);
     33     U8CPU g = SkGetPackedG32(c);
     34     U8CPU b = SkGetPackedB32(c);
     35     return SkPreMultiplyARGB(a, r, g, b);
     36 }
     37 
     38 class UnpremulView : public SampleView {
     39 public:
     40     UnpremulView(SkString res)
     41     : fResPath(res)
     42     , fPremul(true)
     43     , fDecodeSucceeded(false) {
     44         this->nextImage();
     45     }
     46 
     47 protected:
     48     // overrides from SkEventSink
     49     bool onQuery(SkEvent* evt) override {
     50         if (SampleCode::TitleQ(*evt)) {
     51             SampleCode::TitleR(evt, "unpremul");
     52             return true;
     53         }
     54         SkUnichar uni;
     55         if (SampleCode::CharQ(*evt, &uni)) {
     56             char utf8[kMaxBytesInUTF8Sequence];
     57             size_t size = SkUTF8_FromUnichar(uni, utf8);
     58             // Only consider events for single char keys
     59             if (1 == size) {
     60                 switch (utf8[0]) {
     61                     case fNextImageChar:
     62                         this->nextImage();
     63                         return true;
     64                     case fTogglePremulChar:
     65                         this->togglePremul();
     66                         return true;
     67                     default:
     68                         break;
     69                 }
     70             }
     71         }
     72         return this->INHERITED::onQuery(evt);
     73     }
     74 
     75     void onDrawBackground(SkCanvas* canvas) override {
     76         sk_tool_utils::draw_checkerboard(canvas, 0xFFCCCCCC, 0xFFFFFFFF, 12);
     77     }
     78 
     79     void onDrawContent(SkCanvas* canvas) override {
     80         SkPaint paint;
     81         paint.setAntiAlias(true);
     82         paint.setTextSize(SkIntToScalar(24));
     83         auto looper(
     84             SkBlurDrawLooper::Make(SK_ColorBLUE, SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(2)),
     85                                    0, 0));
     86         paint.setLooper(looper);
     87         SkScalar height = paint.getFontMetrics(nullptr);
     88         if (!fDecodeSucceeded) {
     89             SkString failure;
     90             if (fResPath.size() == 0) {
     91                 failure.printf("resource path is required!");
     92             } else {
     93                 failure.printf("Failed to decode %s", fCurrFile.c_str());
     94             }
     95             canvas->drawString(failure, 0, height, paint);
     96             return;
     97         }
     98 
     99         // Name, size of the file, and whether or not it is premultiplied.
    100         SkString header(SkOSPath::Basename(fCurrFile.c_str()));
    101         header.appendf("     [%dx%d]     %s", fBitmap.width(), fBitmap.height(),
    102                        (fPremul ? "premultiplied" : "unpremultiplied"));
    103         canvas->drawString(header, 0, height, paint);
    104         canvas->translate(0, height);
    105 
    106         // Help messages
    107         header.printf("Press '%c' to move to the next image.'", fNextImageChar);
    108         canvas->drawString(header, 0, height, paint);
    109         canvas->translate(0, height);
    110 
    111         header.printf("Press '%c' to toggle premultiplied decode.", fTogglePremulChar);
    112         canvas->drawString(header, 0, height, paint);
    113 
    114         // Now draw the image itself.
    115         canvas->translate(height * 2, height * 2);
    116         if (!fPremul) {
    117             // A premultiplied bitmap cannot currently be drawn.
    118             // Copy it to a bitmap which can be drawn, converting
    119             // to premultiplied:
    120             SkBitmap bm;
    121             bm.allocN32Pixels(fBitmap.width(), fBitmap.height());
    122             for (int i = 0; i < fBitmap.width(); ++i) {
    123                 for (int j = 0; j < fBitmap.height(); ++j) {
    124                     *bm.getAddr32(i, j) = premultiply_unpmcolor(*fBitmap.getAddr32(i, j));
    125                 }
    126             }
    127             canvas->drawBitmap(bm, 0, 0);
    128         } else {
    129             canvas->drawBitmap(fBitmap, 0, 0);
    130         }
    131     }
    132 
    133 private:
    134     const SkString  fResPath;
    135     SkString        fCurrFile;
    136     bool            fPremul;
    137     bool            fDecodeSucceeded;
    138     SkBitmap        fBitmap;
    139     SkOSFile::Iter  fFileIter;
    140 
    141     static const char   fNextImageChar      = 'j';
    142     static const char   fTogglePremulChar   = 'h';
    143 
    144     void nextImage() {
    145         if (fResPath.size() == 0) {
    146             return;
    147         }
    148         SkString basename;
    149         if (!fFileIter.next(&basename)) {
    150             fFileIter.reset(fResPath.c_str());
    151             if (!fFileIter.next(&basename)) {
    152                 // Perhaps this should draw some error message?
    153                 return;
    154             }
    155         }
    156         fCurrFile = SkOSPath::Join(fResPath.c_str(), basename.c_str());
    157         this->decodeCurrFile();
    158     }
    159 
    160     void decodeCurrFile() {
    161         if (fCurrFile.size() == 0) {
    162             fDecodeSucceeded = false;
    163             return;
    164         }
    165         fDecodeSucceeded = decode_file(fCurrFile.c_str(), &fBitmap, kN32_SkColorType, !fPremul);
    166     }
    167 
    168     void togglePremul() {
    169         fPremul = !fPremul;
    170         this->decodeCurrFile();
    171     }
    172 
    173     typedef SampleView INHERITED;
    174 };
    175 
    176 //////////////////////////////////////////////////////////////////////////////
    177 
    178 static SkView* MyFactory() {
    179     return new UnpremulView(GetResourcePath("images"));
    180 }
    181 static SkViewRegister reg(MyFactory);
    182