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