• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 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/gm.h"
9 #include "include/codec/SkEncodedOrigin.h"
10 #include "include/core/SkBlurTypes.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkFont.h"
13 #include "include/core/SkImage.h"
14 #include "include/core/SkMaskFilter.h"
15 #include "include/core/SkRefCnt.h"
16 #include "include/core/SkSize.h"
17 #include "include/core/SkString.h"
18 #include "include/core/SkSurface.h"
19 #include "tools/Resources.h"
20 #include "tools/ToolUtils.h"
21 
22 
23 static constexpr int kImgW = 100;
24 static constexpr int kImgH =  80;
25 
26 /**
27   This function was used to create the images used by these test. It saves them as PNGs (so they
28   are lossless). Then the following bash script was used to create the oriented JPGs with
29   imagemagick and exiftool:
30 #!/bin/bash
31 
32 for s in 444 422 420 440 411 410; do
33   for i in {1..8}; do
34     magick convert $i.png -sampling-factor ${s:0:1}:${s:1:1}:${s:2:1} $i\_$s.jpg;
35     exiftool -orientation=$i -n -m -overwrite_original $i\_$s.jpg;
36   done
37 done
38 
39  */
make_images()40 static void make_images() {
41     for (int i = 1; i <= 8; ++i) {
42         SkISize size{kImgW, kImgH};
43         SkEncodedOrigin origin = static_cast<SkEncodedOrigin>(i);
44         // We apply the inverse transformation to the PNG we generate, convert the PNG to a
45         // a JPEG using magick, then modify the JPEG's tag using exiftool (without modifying the
46         // stored JPEG data).
47         if (origin >= kLeftTop_SkEncodedOrigin) {
48             // The last four SkEncodedOrigin values involve 90 degree rotations
49             using std::swap;
50             swap(size.fWidth, size.fHeight);
51         }
52         using std::swap;
53         auto surf = SkSurface::MakeRaster(SkImageInfo::Make(size,
54                                                             kRGBA_8888_SkColorType,
55                                                             kPremul_SkAlphaType));
56         auto* canvas = surf->getCanvas();
57         SkMatrix m = SkEncodedOriginToMatrix(origin, kImgW, kImgH);
58         SkAssertResult(m.invert(&m));
59         canvas->concat(m);
60         canvas->clear(SK_ColorBLACK);
61         SkPaint paint;
62         paint.setColor(SK_ColorRED);
63         SkScalar midX = kImgW / 2.f;
64         SkScalar midY = kImgH / 2.f;
65         SkScalar w = midX - 1;
66         SkScalar h = midY - 1;
67         canvas->drawRect(SkRect::MakeXYWH(1, 1, w, h), paint);
68         paint.setColor(SK_ColorBLUE);
69         canvas->drawRect(SkRect::MakeXYWH(midX, 1, w, h), paint);
70         paint.setColor(SK_ColorGREEN);
71         canvas->drawRect(SkRect::MakeXYWH(1, midY, w, h), paint);
72         paint.setColor(SK_ColorYELLOW);
73         canvas->drawRect(SkRect::MakeXYWH(midX, midY, w, h), paint);
74         SkFont font(ToolUtils::create_portable_typeface(), kImgH / 4.f);
75 
76         SkPaint blurPaint;
77         blurPaint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, .75f));
78         blurPaint.setColor(SK_ColorBLACK);
79         paint.setColor(SK_ColorWHITE);
80 
81         auto drawLabel = [&](const char* string, SkScalar x, SkScalar y) {
82             canvas->save();
83             canvas->translate(1, 1);
84             canvas->drawString(string, x, y, font, blurPaint);
85             canvas->restore();
86             canvas->drawString(string, x, y, font, paint);
87         };
88 
89         auto measure = [&font](const char* text) {
90             SkRect bounds;
91             font.measureText(text, strlen(text), SkTextEncoding::kUTF8, &bounds);
92             return bounds;
93         };
94 
95         static constexpr SkScalar kPad = 3.f;
96         SkRect bounds;
97 
98         bounds = measure("top");
99         drawLabel("top", midX - bounds.centerX(), -bounds.top() + kPad);
100 
101         bounds = measure("bottom");
102         drawLabel("bottom", midX - bounds.centerX(), kImgH - kPad - bounds.bottom());
103 
104         // It looks weird if "left" and "right" and the number at the center aren't vertically
105         // aligned.
106         SkScalar baseY = midY - measure("leftright").centerY();
107         bounds = measure("left");
108         drawLabel("left", kPad - bounds.left(), baseY);
109 
110         bounds = measure("right");
111         drawLabel("right", kImgW - kPad - bounds.right(), baseY);
112 
113         SkString num = SkStringPrintf("%d", i);
114         bounds = measure(num.c_str());
115         drawLabel(num.c_str(), midX - bounds.centerX(), baseY);
116         num.append(".png");
117         SkPixmap pm;
118         surf->makeImageSnapshot()->peekPixels(&pm);
119         ToolUtils::EncodeImageToFile(num.c_str(), pm, SkEncodedImageFormat::kPNG, 100);
120     }
121 }
122 
123 // This gm draws 8 images that are mostly the same when respecting the
124 // EXIF orientation tag. Each one has four quadrants (red, blue, green,
125 // yellow), and labels on the left, top, right and bottom. The only
126 // visual difference is a number in the middle corresponding to the
127 // EXIF tag for that image's jpg file.
draw(SkCanvas * canvas,const char * suffix)128 static void draw(SkCanvas* canvas, const char* suffix) {
129     // Avoid unused function warning.
130     if ((false)) {
131         make_images();
132     }
133     canvas->save();
134     for (char i = '1'; i <= '8'; i++) {
135         SkString path = SkStringPrintf("images/orientation/%c%s.jpg", i, suffix);
136         auto image = GetResourceAsImage(path.c_str());
137         if (!image) {
138             continue;
139         }
140         canvas->drawImage(image, 0, 0);
141         if ('4' == i) {
142             canvas->restore();
143             canvas->translate(0, image->height());
144         } else {
145             canvas->translate(image->width(), 0);
146         }
147     }
148 }
149 
150 #define MAKE_GM(subsample) DEF_SIMPLE_GM(orientation_##subsample, canvas, 4*kImgW, 2*kImgH) { \
151         draw(canvas, "_" #subsample);                                                         \
152 }
153 
154 MAKE_GM(410)
155 MAKE_GM(411)
156 MAKE_GM(420)
157 MAKE_GM(422)
158 MAKE_GM(440)
159 MAKE_GM(444)
160