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