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