• 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::Basename(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             bm.allocN32Pixels(fBitmap.width(), fBitmap.height());
132             for (int i = 0; i < fBitmap.width(); ++i) {
133                 for (int j = 0; j < fBitmap.height(); ++j) {
134                     *bm.getAddr32(i, j) = premultiply_unpmcolor(*fBitmap.getAddr32(i, j));
135                 }
136             }
137             canvas->drawBitmap(bm, 0, 0);
138         } else {
139             canvas->drawBitmap(fBitmap, 0, 0);
140         }
141     }
142 
143 private:
144     const SkString  fResPath;
145     SkString        fCurrFile;
146     bool            fPremul;
147     bool            fDecodeSucceeded;
148     SkBitmap        fBitmap;
149     SkOSFile::Iter  fFileIter;
150 
151     static const char   fNextImageChar      = 'j';
152     static const char   fTogglePremulChar   = 'h';
153 
nextImage()154     void nextImage() {
155         if (fResPath.size() == 0) {
156             return;
157         }
158         SkString basename;
159         if (!fFileIter.next(&basename)) {
160             fFileIter.reset(fResPath.c_str());
161             if (!fFileIter.next(&basename)) {
162                 // Perhaps this should draw some error message?
163                 return;
164             }
165         }
166         fCurrFile = SkOSPath::Join(fResPath.c_str(), basename.c_str());
167         this->decodeCurrFile();
168     }
169 
decodeCurrFile()170     void decodeCurrFile() {
171         if (fCurrFile.size() == 0) {
172             fDecodeSucceeded = false;
173             return;
174         }
175         SkFILEStream stream(fCurrFile.c_str());
176         SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream));
177         if (NULL == decoder.get()) {
178             fDecodeSucceeded = false;
179             return;
180         }
181         if (!fPremul) {
182             decoder->setRequireUnpremultipliedColors(true);
183         }
184         fDecodeSucceeded = decoder->decode(&stream, &fBitmap, kN32_SkColorType,
185                                            SkImageDecoder::kDecodePixels_Mode);
186         this->inval(NULL);
187     }
188 
togglePremul()189     void togglePremul() {
190         fPremul = !fPremul;
191         this->decodeCurrFile();
192     }
193 
194     typedef SampleView INHERITED;
195 };
196 
197 //////////////////////////////////////////////////////////////////////////////
198 
MyFactory()199 static SkView* MyFactory() {
200     return new UnpremulView(GetResourcePath());
201 }
202 static SkViewRegister reg(MyFactory);
203