xref: /aosp_15_r20/external/harfbuzz_ng/util/ansi-print.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1*2d1272b8SAndroid Build Coastguard Worker /*
2*2d1272b8SAndroid Build Coastguard Worker  * Copyright © 2012  Google, Inc.
3*2d1272b8SAndroid Build Coastguard Worker  *
4*2d1272b8SAndroid Build Coastguard Worker  *  This is part of HarfBuzz, a text shaping library.
5*2d1272b8SAndroid Build Coastguard Worker  *
6*2d1272b8SAndroid Build Coastguard Worker  * Permission is hereby granted, without written agreement and without
7*2d1272b8SAndroid Build Coastguard Worker  * license or royalty fees, to use, copy, modify, and distribute this
8*2d1272b8SAndroid Build Coastguard Worker  * software and its documentation for any purpose, provided that the
9*2d1272b8SAndroid Build Coastguard Worker  * above copyright notice and the following two paragraphs appear in
10*2d1272b8SAndroid Build Coastguard Worker  * all copies of this software.
11*2d1272b8SAndroid Build Coastguard Worker  *
12*2d1272b8SAndroid Build Coastguard Worker  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13*2d1272b8SAndroid Build Coastguard Worker  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14*2d1272b8SAndroid Build Coastguard Worker  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15*2d1272b8SAndroid Build Coastguard Worker  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16*2d1272b8SAndroid Build Coastguard Worker  * DAMAGE.
17*2d1272b8SAndroid Build Coastguard Worker  *
18*2d1272b8SAndroid Build Coastguard Worker  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19*2d1272b8SAndroid Build Coastguard Worker  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20*2d1272b8SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21*2d1272b8SAndroid Build Coastguard Worker  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22*2d1272b8SAndroid Build Coastguard Worker  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23*2d1272b8SAndroid Build Coastguard Worker  *
24*2d1272b8SAndroid Build Coastguard Worker  * Google Author(s): Behdad Esfahbod
25*2d1272b8SAndroid Build Coastguard Worker  */
26*2d1272b8SAndroid Build Coastguard Worker 
27*2d1272b8SAndroid Build Coastguard Worker #ifndef ANSI_PRINT_HH
28*2d1272b8SAndroid Build Coastguard Worker #define ANSI_PRINT_HH
29*2d1272b8SAndroid Build Coastguard Worker 
30*2d1272b8SAndroid Build Coastguard Worker #include "hb.hh"
31*2d1272b8SAndroid Build Coastguard Worker 
32*2d1272b8SAndroid Build Coastguard Worker #include <cairo.h>
33*2d1272b8SAndroid Build Coastguard Worker 
34*2d1272b8SAndroid Build Coastguard Worker #include <assert.h>
35*2d1272b8SAndroid Build Coastguard Worker #include <stdlib.h>
36*2d1272b8SAndroid Build Coastguard Worker #include <stddef.h>
37*2d1272b8SAndroid Build Coastguard Worker #include <string.h>
38*2d1272b8SAndroid Build Coastguard Worker #include <math.h>
39*2d1272b8SAndroid Build Coastguard Worker 
40*2d1272b8SAndroid Build Coastguard Worker #if defined (_MSC_VER) && (_MSC_VER < 1800)
41*2d1272b8SAndroid Build Coastguard Worker static inline long int
lround(double x)42*2d1272b8SAndroid Build Coastguard Worker lround (double x)
43*2d1272b8SAndroid Build Coastguard Worker {
44*2d1272b8SAndroid Build Coastguard Worker   if (x >= 0)
45*2d1272b8SAndroid Build Coastguard Worker     return floor (x + 0.5);
46*2d1272b8SAndroid Build Coastguard Worker   else
47*2d1272b8SAndroid Build Coastguard Worker     return ceil (x - 0.5);
48*2d1272b8SAndroid Build Coastguard Worker }
49*2d1272b8SAndroid Build Coastguard Worker #endif
50*2d1272b8SAndroid Build Coastguard Worker 
51*2d1272b8SAndroid Build Coastguard Worker #define CELL_W 8
52*2d1272b8SAndroid Build Coastguard Worker #define CELL_H (2 * CELL_W)
53*2d1272b8SAndroid Build Coastguard Worker 
54*2d1272b8SAndroid Build Coastguard Worker struct color_diff_t
55*2d1272b8SAndroid Build Coastguard Worker {
dotcolor_diff_t56*2d1272b8SAndroid Build Coastguard Worker   int dot (const color_diff_t &o)
57*2d1272b8SAndroid Build Coastguard Worker   { return v[0]*o.v[0] + v[1]*o.v[1] + v[2]*o.v[2] + v[3]*o.v[3]; }
58*2d1272b8SAndroid Build Coastguard Worker 
59*2d1272b8SAndroid Build Coastguard Worker   int v[4];
60*2d1272b8SAndroid Build Coastguard Worker };
61*2d1272b8SAndroid Build Coastguard Worker 
62*2d1272b8SAndroid Build Coastguard Worker struct color_t
63*2d1272b8SAndroid Build Coastguard Worker {
from_ansicolor_t64*2d1272b8SAndroid Build Coastguard Worker   static color_t from_ansi (unsigned int x)
65*2d1272b8SAndroid Build Coastguard Worker   {
66*2d1272b8SAndroid Build Coastguard Worker     color_t c = {(0xFFu<<24) | ((0xFFu*(x&1))<<16) | ((0xFFu*((x >> 1)&1))<<8) | (0xFFu*((x >> 2)&1))};
67*2d1272b8SAndroid Build Coastguard Worker     return c;
68*2d1272b8SAndroid Build Coastguard Worker   }
to_ansicolor_t69*2d1272b8SAndroid Build Coastguard Worker   unsigned int to_ansi ()
70*2d1272b8SAndroid Build Coastguard Worker   {
71*2d1272b8SAndroid Build Coastguard Worker     return ((v >> 23) & 1) | ((v >> 14)&2) | ((v >> 5)&4);
72*2d1272b8SAndroid Build Coastguard Worker   }
73*2d1272b8SAndroid Build Coastguard Worker 
diffcolor_t74*2d1272b8SAndroid Build Coastguard Worker   color_diff_t diff (const color_t &o)
75*2d1272b8SAndroid Build Coastguard Worker   {
76*2d1272b8SAndroid Build Coastguard Worker     color_diff_t d;
77*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < 4; i++)
78*2d1272b8SAndroid Build Coastguard Worker       d.v[i] = (int) ((v >> (i*8))&0xFF) - (int) ((o.v >> (i*8))&0xFF);
79*2d1272b8SAndroid Build Coastguard Worker     return d;
80*2d1272b8SAndroid Build Coastguard Worker   }
81*2d1272b8SAndroid Build Coastguard Worker 
82*2d1272b8SAndroid Build Coastguard Worker   uint32_t v;
83*2d1272b8SAndroid Build Coastguard Worker };
84*2d1272b8SAndroid Build Coastguard Worker 
85*2d1272b8SAndroid Build Coastguard Worker struct image_t
86*2d1272b8SAndroid Build Coastguard Worker {
87*2d1272b8SAndroid Build Coastguard Worker   public:
88*2d1272b8SAndroid Build Coastguard Worker 
image_timage_t89*2d1272b8SAndroid Build Coastguard Worker   image_t (unsigned int width_,
90*2d1272b8SAndroid Build Coastguard Worker 	   unsigned int height_,
91*2d1272b8SAndroid Build Coastguard Worker 	   const uint32_t *data_,
92*2d1272b8SAndroid Build Coastguard Worker 	   unsigned int stride_) :
93*2d1272b8SAndroid Build Coastguard Worker 		width (width_),
94*2d1272b8SAndroid Build Coastguard Worker 		height (height_),
95*2d1272b8SAndroid Build Coastguard Worker 		own_data (false),
96*2d1272b8SAndroid Build Coastguard Worker 		data ((color_t *) data_),
97*2d1272b8SAndroid Build Coastguard Worker 		stride (stride_) {}
image_timage_t98*2d1272b8SAndroid Build Coastguard Worker   image_t (unsigned int width_,
99*2d1272b8SAndroid Build Coastguard Worker 	   unsigned int height_) :
100*2d1272b8SAndroid Build Coastguard Worker 		width (width_),
101*2d1272b8SAndroid Build Coastguard Worker 		height (height_),
102*2d1272b8SAndroid Build Coastguard Worker 		own_data (true),
103*2d1272b8SAndroid Build Coastguard Worker 		data ((color_t *) malloc (sizeof (data[0]) * width * height)),
104*2d1272b8SAndroid Build Coastguard Worker 		stride (width) {}
~image_timage_t105*2d1272b8SAndroid Build Coastguard Worker   ~image_t ()
106*2d1272b8SAndroid Build Coastguard Worker   { if (own_data) free (data); }
107*2d1272b8SAndroid Build Coastguard Worker 
operator ()image_t108*2d1272b8SAndroid Build Coastguard Worker   color_t &operator () (unsigned int x, unsigned int y)
109*2d1272b8SAndroid Build Coastguard Worker   { return data[x + y * stride]; }
110*2d1272b8SAndroid Build Coastguard Worker 
operator ()image_t111*2d1272b8SAndroid Build Coastguard Worker   color_t operator () (unsigned int x, unsigned int y) const
112*2d1272b8SAndroid Build Coastguard Worker   { return data[x + y * stride]; }
113*2d1272b8SAndroid Build Coastguard Worker 
114*2d1272b8SAndroid Build Coastguard Worker   void
copy_sub_imageimage_t115*2d1272b8SAndroid Build Coastguard Worker   copy_sub_image (const image_t &s,
116*2d1272b8SAndroid Build Coastguard Worker 		  unsigned int x, unsigned int y,
117*2d1272b8SAndroid Build Coastguard Worker 		  unsigned int w, unsigned int h)
118*2d1272b8SAndroid Build Coastguard Worker   {
119*2d1272b8SAndroid Build Coastguard Worker     assert (x < width);
120*2d1272b8SAndroid Build Coastguard Worker     assert (y < height);
121*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int row = 0; row < h; row++) {
122*2d1272b8SAndroid Build Coastguard Worker       color_t *p = data + x + hb_min (y + row, height - 1) * stride;
123*2d1272b8SAndroid Build Coastguard Worker       color_t *q = s.data + row * s.stride;
124*2d1272b8SAndroid Build Coastguard Worker       if (x + w <= width)
125*2d1272b8SAndroid Build Coastguard Worker 	for (unsigned int col = 0; col < w; col++)
126*2d1272b8SAndroid Build Coastguard Worker 	  *q++ = *p++;
127*2d1272b8SAndroid Build Coastguard Worker       else {
128*2d1272b8SAndroid Build Coastguard Worker 	unsigned int limit = width - x;
129*2d1272b8SAndroid Build Coastguard Worker 	for (unsigned int col = 0; col < limit; col++)
130*2d1272b8SAndroid Build Coastguard Worker 	  *q++ = *p++;
131*2d1272b8SAndroid Build Coastguard Worker 	p--;
132*2d1272b8SAndroid Build Coastguard Worker 	for (unsigned int col = limit; col < w; col++)
133*2d1272b8SAndroid Build Coastguard Worker 	  *q++ = *p;
134*2d1272b8SAndroid Build Coastguard Worker       }
135*2d1272b8SAndroid Build Coastguard Worker     }
136*2d1272b8SAndroid Build Coastguard Worker   }
137*2d1272b8SAndroid Build Coastguard Worker 
138*2d1272b8SAndroid Build Coastguard Worker   const unsigned int width;
139*2d1272b8SAndroid Build Coastguard Worker   const unsigned int height;
140*2d1272b8SAndroid Build Coastguard Worker 
141*2d1272b8SAndroid Build Coastguard Worker   private:
142*2d1272b8SAndroid Build Coastguard Worker   bool own_data;
143*2d1272b8SAndroid Build Coastguard Worker   color_t * const data;
144*2d1272b8SAndroid Build Coastguard Worker   const unsigned int stride;
145*2d1272b8SAndroid Build Coastguard Worker };
146*2d1272b8SAndroid Build Coastguard Worker 
147*2d1272b8SAndroid Build Coastguard Worker struct biimage_t
148*2d1272b8SAndroid Build Coastguard Worker {
149*2d1272b8SAndroid Build Coastguard Worker   public:
150*2d1272b8SAndroid Build Coastguard Worker 
biimage_tbiimage_t151*2d1272b8SAndroid Build Coastguard Worker   biimage_t (unsigned int width, unsigned int height) :
152*2d1272b8SAndroid Build Coastguard Worker 		width (width),
153*2d1272b8SAndroid Build Coastguard Worker 		height (height),
154*2d1272b8SAndroid Build Coastguard Worker 		bg (0), fg (0), unicolor (true),
155*2d1272b8SAndroid Build Coastguard Worker 		data ((uint8_t *) malloc (sizeof (data[0]) * width * height)) {}
~biimage_tbiimage_t156*2d1272b8SAndroid Build Coastguard Worker   ~biimage_t ()
157*2d1272b8SAndroid Build Coastguard Worker   { free (data); }
158*2d1272b8SAndroid Build Coastguard Worker 
setbiimage_t159*2d1272b8SAndroid Build Coastguard Worker   void set (const image_t &image)
160*2d1272b8SAndroid Build Coastguard Worker   {
161*2d1272b8SAndroid Build Coastguard Worker     assert (image.width == width);
162*2d1272b8SAndroid Build Coastguard Worker     assert (image.height == height);
163*2d1272b8SAndroid Build Coastguard Worker     int freq[8] = {0};
164*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int y = 0; y < height; y++)
165*2d1272b8SAndroid Build Coastguard Worker       for (unsigned int x = 0; x < width; x++) {
166*2d1272b8SAndroid Build Coastguard Worker 	color_t c = image (x, y);
167*2d1272b8SAndroid Build Coastguard Worker 	freq[c.to_ansi ()]++;
168*2d1272b8SAndroid Build Coastguard Worker       }
169*2d1272b8SAndroid Build Coastguard Worker     bg = 0;
170*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 1; i < 8; i++)
171*2d1272b8SAndroid Build Coastguard Worker       if (freq[bg] < freq[i])
172*2d1272b8SAndroid Build Coastguard Worker 	bg = i;
173*2d1272b8SAndroid Build Coastguard Worker     fg = 8;
174*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < 8; i++)
175*2d1272b8SAndroid Build Coastguard Worker       if (i != bg && (fg == 8 || freq[fg] < freq[i]))
176*2d1272b8SAndroid Build Coastguard Worker 	fg = i;
177*2d1272b8SAndroid Build Coastguard Worker     if (freq[fg] == 0) {
178*2d1272b8SAndroid Build Coastguard Worker       fg = bg;
179*2d1272b8SAndroid Build Coastguard Worker       unicolor = true;
180*2d1272b8SAndroid Build Coastguard Worker     }
181*2d1272b8SAndroid Build Coastguard Worker     else
182*2d1272b8SAndroid Build Coastguard Worker       unicolor = false;
183*2d1272b8SAndroid Build Coastguard Worker 
184*2d1272b8SAndroid Build Coastguard Worker     /* Set the data... */
185*2d1272b8SAndroid Build Coastguard Worker 
186*2d1272b8SAndroid Build Coastguard Worker     if (unicolor) {
187*2d1272b8SAndroid Build Coastguard Worker       memset (data, 0, sizeof (data[0]) * width * height);
188*2d1272b8SAndroid Build Coastguard Worker       return;
189*2d1272b8SAndroid Build Coastguard Worker     }
190*2d1272b8SAndroid Build Coastguard Worker 
191*2d1272b8SAndroid Build Coastguard Worker     color_t bgc = color_t::from_ansi (bg);
192*2d1272b8SAndroid Build Coastguard Worker     color_t fgc = color_t::from_ansi (fg);
193*2d1272b8SAndroid Build Coastguard Worker     color_diff_t diff = fgc.diff (bgc);
194*2d1272b8SAndroid Build Coastguard Worker     double dd = sqrt (diff.dot (diff));
195*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int y = 0; y < height; y++)
196*2d1272b8SAndroid Build Coastguard Worker       for (unsigned int x = 0; x < width; x++) {
197*2d1272b8SAndroid Build Coastguard Worker 	double d = sqrt (diff.dot (image (x, y).diff (bgc)));
198*2d1272b8SAndroid Build Coastguard Worker 	(*this)(x, y) = d <= 0 ? 0 : d >= dd ? 255 : lround (d / dd * 255.);
199*2d1272b8SAndroid Build Coastguard Worker       }
200*2d1272b8SAndroid Build Coastguard Worker   }
201*2d1272b8SAndroid Build Coastguard Worker 
operator ()biimage_t202*2d1272b8SAndroid Build Coastguard Worker   uint8_t &operator () (unsigned int x, unsigned int y)
203*2d1272b8SAndroid Build Coastguard Worker   { return data[x + y * width]; }
204*2d1272b8SAndroid Build Coastguard Worker 
operator ()biimage_t205*2d1272b8SAndroid Build Coastguard Worker   uint8_t operator () (unsigned int x, unsigned int y) const
206*2d1272b8SAndroid Build Coastguard Worker   { return data[x + y * width]; }
207*2d1272b8SAndroid Build Coastguard Worker 
208*2d1272b8SAndroid Build Coastguard Worker   const unsigned int width;
209*2d1272b8SAndroid Build Coastguard Worker   const unsigned int height;
210*2d1272b8SAndroid Build Coastguard Worker   unsigned int bg;
211*2d1272b8SAndroid Build Coastguard Worker   unsigned int fg;
212*2d1272b8SAndroid Build Coastguard Worker   bool unicolor;
213*2d1272b8SAndroid Build Coastguard Worker 
214*2d1272b8SAndroid Build Coastguard Worker   private:
215*2d1272b8SAndroid Build Coastguard Worker   uint8_t * const data;
216*2d1272b8SAndroid Build Coastguard Worker };
217*2d1272b8SAndroid Build Coastguard Worker 
218*2d1272b8SAndroid Build Coastguard Worker static const char *
block_best(const biimage_t & bi,bool * inverse)219*2d1272b8SAndroid Build Coastguard Worker block_best (const biimage_t &bi, bool *inverse)
220*2d1272b8SAndroid Build Coastguard Worker {
221*2d1272b8SAndroid Build Coastguard Worker   assert (bi.width  <= CELL_W);
222*2d1272b8SAndroid Build Coastguard Worker   assert (bi.height <= CELL_H);
223*2d1272b8SAndroid Build Coastguard Worker 
224*2d1272b8SAndroid Build Coastguard Worker   unsigned int score = UINT_MAX;
225*2d1272b8SAndroid Build Coastguard Worker   unsigned int row_sum[CELL_H] = {0};
226*2d1272b8SAndroid Build Coastguard Worker   unsigned int col_sum[CELL_W] = {0};
227*2d1272b8SAndroid Build Coastguard Worker   unsigned int row_sum_i[CELL_H] = {0};
228*2d1272b8SAndroid Build Coastguard Worker   unsigned int col_sum_i[CELL_W] = {0};
229*2d1272b8SAndroid Build Coastguard Worker   unsigned int quad[2][2] = {{0}};
230*2d1272b8SAndroid Build Coastguard Worker   unsigned int quad_i[2][2] = {{0}};
231*2d1272b8SAndroid Build Coastguard Worker   unsigned int total = 0;
232*2d1272b8SAndroid Build Coastguard Worker   unsigned int total_i = 0;
233*2d1272b8SAndroid Build Coastguard Worker   for (unsigned int y = 0; y < bi.height; y++)
234*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int x = 0; x < bi.width; x++) {
235*2d1272b8SAndroid Build Coastguard Worker       unsigned int c = bi (x, y);
236*2d1272b8SAndroid Build Coastguard Worker       unsigned int c_i = 255 - c;
237*2d1272b8SAndroid Build Coastguard Worker       row_sum[y] += c;
238*2d1272b8SAndroid Build Coastguard Worker       row_sum_i[y] += c_i;
239*2d1272b8SAndroid Build Coastguard Worker       col_sum[x] += c;
240*2d1272b8SAndroid Build Coastguard Worker       col_sum_i[x] += c_i;
241*2d1272b8SAndroid Build Coastguard Worker       quad[2 * y / bi.height][2 * x / bi.width] += c;
242*2d1272b8SAndroid Build Coastguard Worker       quad_i[2 * y / bi.height][2 * x / bi.width] += c_i;
243*2d1272b8SAndroid Build Coastguard Worker       total += c;
244*2d1272b8SAndroid Build Coastguard Worker       total_i += c_i;
245*2d1272b8SAndroid Build Coastguard Worker     }
246*2d1272b8SAndroid Build Coastguard Worker 
247*2d1272b8SAndroid Build Coastguard Worker   /* Make the sums cumulative */
248*2d1272b8SAndroid Build Coastguard Worker   for (unsigned int i = 1; i < bi.height; i++) {
249*2d1272b8SAndroid Build Coastguard Worker     row_sum[i] += row_sum[i - 1];
250*2d1272b8SAndroid Build Coastguard Worker     row_sum_i[i] += row_sum_i[i - 1];
251*2d1272b8SAndroid Build Coastguard Worker   }
252*2d1272b8SAndroid Build Coastguard Worker   for (unsigned int i = 1; i < bi.width;  i++) {
253*2d1272b8SAndroid Build Coastguard Worker     col_sum[i] += col_sum[i - 1];
254*2d1272b8SAndroid Build Coastguard Worker     col_sum_i[i] += col_sum_i[i - 1];
255*2d1272b8SAndroid Build Coastguard Worker   }
256*2d1272b8SAndroid Build Coastguard Worker 
257*2d1272b8SAndroid Build Coastguard Worker   const char *best_c = " ";
258*2d1272b8SAndroid Build Coastguard Worker 
259*2d1272b8SAndroid Build Coastguard Worker   /* Maybe empty is better! */
260*2d1272b8SAndroid Build Coastguard Worker   if (total < score) {
261*2d1272b8SAndroid Build Coastguard Worker     score = total;
262*2d1272b8SAndroid Build Coastguard Worker     *inverse = false;
263*2d1272b8SAndroid Build Coastguard Worker     best_c = " ";
264*2d1272b8SAndroid Build Coastguard Worker   }
265*2d1272b8SAndroid Build Coastguard Worker   /* Maybe full is better! */
266*2d1272b8SAndroid Build Coastguard Worker   if (total_i < score) {
267*2d1272b8SAndroid Build Coastguard Worker     score = total_i;
268*2d1272b8SAndroid Build Coastguard Worker     *inverse = true;
269*2d1272b8SAndroid Build Coastguard Worker     best_c = " ";
270*2d1272b8SAndroid Build Coastguard Worker   }
271*2d1272b8SAndroid Build Coastguard Worker 
272*2d1272b8SAndroid Build Coastguard Worker   /* Find best lower line */
273*2d1272b8SAndroid Build Coastguard Worker   if (1) {
274*2d1272b8SAndroid Build Coastguard Worker     unsigned int best_s = UINT_MAX;
275*2d1272b8SAndroid Build Coastguard Worker     bool best_inv = false;
276*2d1272b8SAndroid Build Coastguard Worker     int best_i = 0;
277*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < bi.height - 1; i++)
278*2d1272b8SAndroid Build Coastguard Worker     {
279*2d1272b8SAndroid Build Coastguard Worker       unsigned int s;
280*2d1272b8SAndroid Build Coastguard Worker       s = row_sum[i] + total_i - row_sum_i[i];
281*2d1272b8SAndroid Build Coastguard Worker       if (s < best_s) {
282*2d1272b8SAndroid Build Coastguard Worker 	best_s = s;
283*2d1272b8SAndroid Build Coastguard Worker 	best_i = i;
284*2d1272b8SAndroid Build Coastguard Worker 	best_inv = false;
285*2d1272b8SAndroid Build Coastguard Worker       }
286*2d1272b8SAndroid Build Coastguard Worker       s = row_sum_i[i] + total - row_sum[i];
287*2d1272b8SAndroid Build Coastguard Worker       if (s < best_s) {
288*2d1272b8SAndroid Build Coastguard Worker 	best_s = s;
289*2d1272b8SAndroid Build Coastguard Worker 	best_i = i;
290*2d1272b8SAndroid Build Coastguard Worker 	best_inv = true;
291*2d1272b8SAndroid Build Coastguard Worker       }
292*2d1272b8SAndroid Build Coastguard Worker     }
293*2d1272b8SAndroid Build Coastguard Worker     if (best_s < score) {
294*2d1272b8SAndroid Build Coastguard Worker       static const char *lower[7] = {"▁", "▂", "▃", "▄", "▅", "▆", "▇"};
295*2d1272b8SAndroid Build Coastguard Worker       unsigned int which = lround ((double) ((best_i + 1) * 8) / bi.height);
296*2d1272b8SAndroid Build Coastguard Worker       if (1 <= which && which <= 7) {
297*2d1272b8SAndroid Build Coastguard Worker 	score = best_s;
298*2d1272b8SAndroid Build Coastguard Worker 	*inverse = best_inv;
299*2d1272b8SAndroid Build Coastguard Worker 	best_c = lower[7 - which];
300*2d1272b8SAndroid Build Coastguard Worker       }
301*2d1272b8SAndroid Build Coastguard Worker     }
302*2d1272b8SAndroid Build Coastguard Worker   }
303*2d1272b8SAndroid Build Coastguard Worker 
304*2d1272b8SAndroid Build Coastguard Worker   /* Find best left line */
305*2d1272b8SAndroid Build Coastguard Worker   if (1) {
306*2d1272b8SAndroid Build Coastguard Worker     unsigned int best_s = UINT_MAX;
307*2d1272b8SAndroid Build Coastguard Worker     bool best_inv = false;
308*2d1272b8SAndroid Build Coastguard Worker     int best_i = 0;
309*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < bi.width - 1; i++)
310*2d1272b8SAndroid Build Coastguard Worker     {
311*2d1272b8SAndroid Build Coastguard Worker       unsigned int s;
312*2d1272b8SAndroid Build Coastguard Worker       s = col_sum[i] + total_i - col_sum_i[i];
313*2d1272b8SAndroid Build Coastguard Worker       if (s < best_s) {
314*2d1272b8SAndroid Build Coastguard Worker 	best_s = s;
315*2d1272b8SAndroid Build Coastguard Worker 	best_i = i;
316*2d1272b8SAndroid Build Coastguard Worker 	best_inv = true;
317*2d1272b8SAndroid Build Coastguard Worker       }
318*2d1272b8SAndroid Build Coastguard Worker       s = col_sum_i[i] + total - col_sum[i];
319*2d1272b8SAndroid Build Coastguard Worker       if (s < best_s) {
320*2d1272b8SAndroid Build Coastguard Worker 	best_s = s;
321*2d1272b8SAndroid Build Coastguard Worker 	best_i = i;
322*2d1272b8SAndroid Build Coastguard Worker 	best_inv = false;
323*2d1272b8SAndroid Build Coastguard Worker       }
324*2d1272b8SAndroid Build Coastguard Worker     }
325*2d1272b8SAndroid Build Coastguard Worker     if (best_s < score) {
326*2d1272b8SAndroid Build Coastguard Worker       static const char *left [7] = {"▏", "▎", "▍", "▌", "▋", "▊", "▉"};
327*2d1272b8SAndroid Build Coastguard Worker       unsigned int which = lround ((double) ((best_i + 1) * 8) / bi.width);
328*2d1272b8SAndroid Build Coastguard Worker       if (1 <= which && which <= 7) {
329*2d1272b8SAndroid Build Coastguard Worker 	score = best_s;
330*2d1272b8SAndroid Build Coastguard Worker 	*inverse = best_inv;
331*2d1272b8SAndroid Build Coastguard Worker 	best_c = left[which - 1];
332*2d1272b8SAndroid Build Coastguard Worker       }
333*2d1272b8SAndroid Build Coastguard Worker     }
334*2d1272b8SAndroid Build Coastguard Worker   }
335*2d1272b8SAndroid Build Coastguard Worker 
336*2d1272b8SAndroid Build Coastguard Worker   /* Find best quadrant */
337*2d1272b8SAndroid Build Coastguard Worker   if (1) {
338*2d1272b8SAndroid Build Coastguard Worker     unsigned int q = 0;
339*2d1272b8SAndroid Build Coastguard Worker     unsigned int qs = 0;
340*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int i = 0; i < 2; i++)
341*2d1272b8SAndroid Build Coastguard Worker       for (unsigned int j = 0; j < 2; j++)
342*2d1272b8SAndroid Build Coastguard Worker 	if (quad[i][j] > quad_i[i][j]) {
343*2d1272b8SAndroid Build Coastguard Worker 	  q += 1 << (2 * i + j);
344*2d1272b8SAndroid Build Coastguard Worker 	  qs += quad_i[i][j];
345*2d1272b8SAndroid Build Coastguard Worker 	} else
346*2d1272b8SAndroid Build Coastguard Worker 	  qs += quad[i][j];
347*2d1272b8SAndroid Build Coastguard Worker     if (qs < score) {
348*2d1272b8SAndroid Build Coastguard Worker       const char *c = nullptr;
349*2d1272b8SAndroid Build Coastguard Worker       bool inv = false;
350*2d1272b8SAndroid Build Coastguard Worker       switch (q) {
351*2d1272b8SAndroid Build Coastguard Worker 	case 1:  c = "▟"; inv = true;  break;
352*2d1272b8SAndroid Build Coastguard Worker 	case 2:  c = "▙"; inv = true;  break;
353*2d1272b8SAndroid Build Coastguard Worker 	case 4:  c = "▖"; inv = false; break;
354*2d1272b8SAndroid Build Coastguard Worker 	case 6:  c = "▞"; inv = false; break;
355*2d1272b8SAndroid Build Coastguard Worker 	case 7:  c = "▛"; inv = false; break;
356*2d1272b8SAndroid Build Coastguard Worker 	case 8:  c = "▗"; inv = false; break;
357*2d1272b8SAndroid Build Coastguard Worker 	case 9:  c = "▚"; inv = false; break;
358*2d1272b8SAndroid Build Coastguard Worker 	case 11: c = "▜"; inv = false; break;
359*2d1272b8SAndroid Build Coastguard Worker 	case 13: c = "▙"; inv = false; break;
360*2d1272b8SAndroid Build Coastguard Worker 	case 14: c = "▟"; inv = false; break;
361*2d1272b8SAndroid Build Coastguard Worker       }
362*2d1272b8SAndroid Build Coastguard Worker       if (c) {
363*2d1272b8SAndroid Build Coastguard Worker 	score = qs;
364*2d1272b8SAndroid Build Coastguard Worker 	*inverse = inv;
365*2d1272b8SAndroid Build Coastguard Worker 	best_c = c;
366*2d1272b8SAndroid Build Coastguard Worker       }
367*2d1272b8SAndroid Build Coastguard Worker     }
368*2d1272b8SAndroid Build Coastguard Worker   }
369*2d1272b8SAndroid Build Coastguard Worker 
370*2d1272b8SAndroid Build Coastguard Worker   return best_c;
371*2d1272b8SAndroid Build Coastguard Worker }
372*2d1272b8SAndroid Build Coastguard Worker 
373*2d1272b8SAndroid Build Coastguard Worker static inline void
ansi_print_image_rgb24(const uint32_t * data,unsigned int width,unsigned int height,unsigned int stride,cairo_write_func_t write_func,void * closure)374*2d1272b8SAndroid Build Coastguard Worker ansi_print_image_rgb24 (const uint32_t *data,
375*2d1272b8SAndroid Build Coastguard Worker 			unsigned int width,
376*2d1272b8SAndroid Build Coastguard Worker 			unsigned int height,
377*2d1272b8SAndroid Build Coastguard Worker 			unsigned int stride,
378*2d1272b8SAndroid Build Coastguard Worker 		        cairo_write_func_t	write_func,
379*2d1272b8SAndroid Build Coastguard Worker 		        void			*closure)
380*2d1272b8SAndroid Build Coastguard Worker {
381*2d1272b8SAndroid Build Coastguard Worker   image_t image (width, height, data, stride);
382*2d1272b8SAndroid Build Coastguard Worker 
383*2d1272b8SAndroid Build Coastguard Worker   unsigned int rows = (height + CELL_H - 1) / CELL_H;
384*2d1272b8SAndroid Build Coastguard Worker   unsigned int cols = (width +  CELL_W - 1) / CELL_W;
385*2d1272b8SAndroid Build Coastguard Worker   image_t cell (CELL_W, CELL_H);
386*2d1272b8SAndroid Build Coastguard Worker   biimage_t bi (CELL_W, CELL_H);
387*2d1272b8SAndroid Build Coastguard Worker   unsigned int last_bg = -1, last_fg = -1;
388*2d1272b8SAndroid Build Coastguard Worker   for (unsigned int row = 0; row < rows; row++)
389*2d1272b8SAndroid Build Coastguard Worker   {
390*2d1272b8SAndroid Build Coastguard Worker     for (unsigned int col = 0; col < cols; col++)
391*2d1272b8SAndroid Build Coastguard Worker     {
392*2d1272b8SAndroid Build Coastguard Worker       image.copy_sub_image (cell, col * CELL_W, row * CELL_H, CELL_W, CELL_H);
393*2d1272b8SAndroid Build Coastguard Worker       bi.set (cell);
394*2d1272b8SAndroid Build Coastguard Worker       if (bi.unicolor)
395*2d1272b8SAndroid Build Coastguard Worker       {
396*2d1272b8SAndroid Build Coastguard Worker 	if (last_bg != bi.bg)
397*2d1272b8SAndroid Build Coastguard Worker 	{
398*2d1272b8SAndroid Build Coastguard Worker 	  char buf[] = "\033[40m";
399*2d1272b8SAndroid Build Coastguard Worker 	  buf[3] += bi.bg;
400*2d1272b8SAndroid Build Coastguard Worker 	  write_func (closure, (unsigned char *) buf, 5);
401*2d1272b8SAndroid Build Coastguard Worker 	  last_bg = bi.bg;
402*2d1272b8SAndroid Build Coastguard Worker 	}
403*2d1272b8SAndroid Build Coastguard Worker 	write_func (closure, (unsigned char *) " ", 1);
404*2d1272b8SAndroid Build Coastguard Worker       }
405*2d1272b8SAndroid Build Coastguard Worker       else
406*2d1272b8SAndroid Build Coastguard Worker       {
407*2d1272b8SAndroid Build Coastguard Worker 	/* Figure out the closest character to the biimage */
408*2d1272b8SAndroid Build Coastguard Worker 	bool inverse = false;
409*2d1272b8SAndroid Build Coastguard Worker 	const char *c = block_best (bi, &inverse);
410*2d1272b8SAndroid Build Coastguard Worker 	if (inverse)
411*2d1272b8SAndroid Build Coastguard Worker 	{
412*2d1272b8SAndroid Build Coastguard Worker 	  if (last_bg != bi.fg || last_fg != bi.bg)
413*2d1272b8SAndroid Build Coastguard Worker 	  {
414*2d1272b8SAndroid Build Coastguard Worker 	    char buf[] = "\033[30;40m";
415*2d1272b8SAndroid Build Coastguard Worker 	    buf[3] += bi.bg;
416*2d1272b8SAndroid Build Coastguard Worker 	    buf[6] += bi.fg;
417*2d1272b8SAndroid Build Coastguard Worker 	    write_func (closure, (unsigned char *) buf, 8);
418*2d1272b8SAndroid Build Coastguard Worker 	    last_bg = bi.fg;
419*2d1272b8SAndroid Build Coastguard Worker 	    last_fg = bi.bg;
420*2d1272b8SAndroid Build Coastguard Worker 	  }
421*2d1272b8SAndroid Build Coastguard Worker 	}
422*2d1272b8SAndroid Build Coastguard Worker 	else
423*2d1272b8SAndroid Build Coastguard Worker 	{
424*2d1272b8SAndroid Build Coastguard Worker 	  if (last_bg != bi.bg || last_fg != bi.fg)
425*2d1272b8SAndroid Build Coastguard Worker 	  {
426*2d1272b8SAndroid Build Coastguard Worker 	    char buf[] = "\033[40;30m";
427*2d1272b8SAndroid Build Coastguard Worker 	    buf[3] += bi.bg;
428*2d1272b8SAndroid Build Coastguard Worker 	    buf[6] += bi.fg;
429*2d1272b8SAndroid Build Coastguard Worker 	    write_func (closure, (unsigned char *) buf, 8);
430*2d1272b8SAndroid Build Coastguard Worker 	    last_bg = bi.bg;
431*2d1272b8SAndroid Build Coastguard Worker 	    last_fg = bi.fg;
432*2d1272b8SAndroid Build Coastguard Worker 	  }
433*2d1272b8SAndroid Build Coastguard Worker 	}
434*2d1272b8SAndroid Build Coastguard Worker 	write_func (closure, (unsigned char *) c, strlen (c));
435*2d1272b8SAndroid Build Coastguard Worker       }
436*2d1272b8SAndroid Build Coastguard Worker     }
437*2d1272b8SAndroid Build Coastguard Worker     write_func (closure, (unsigned char *) "\033[0m\n", 5); /* Reset */
438*2d1272b8SAndroid Build Coastguard Worker     last_bg = last_fg = -1;
439*2d1272b8SAndroid Build Coastguard Worker   }
440*2d1272b8SAndroid Build Coastguard Worker }
441*2d1272b8SAndroid Build Coastguard Worker 
442*2d1272b8SAndroid Build Coastguard Worker #endif
443