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