152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod/*
252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod * Copyright © 2012  Google, Inc.
352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod *
452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod *  This is part of HarfBuzz, a text shaping library.
552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod *
652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod * Permission is hereby granted, without written agreement and without
752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod * license or royalty fees, to use, copy, modify, and distribute this
852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod * software and its documentation for any purpose, provided that the
952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod * above copyright notice and the following two paragraphs appear in
1052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod * all copies of this software.
1152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod *
1252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
1352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
1452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
1552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
1652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod * DAMAGE.
1752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod *
1852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
1952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
2052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
2152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
2252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
2352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod *
2452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod * Google Author(s): Behdad Esfahbod
2552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod */
2652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
2752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod#ifdef HAVE_CONFIG_H
2852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod#include "config.h"
2952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod#endif
3052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
3152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod#include "ansi-print.hh"
3252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
3352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod#include <assert.h>
3452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod#include <stdlib.h>
3552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod#include <stddef.h>
3652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod#include <string.h>
3752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod#include <stdio.h>
3852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod#include <math.h>
3952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod#include <fcntl.h>
4052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod#ifdef HAVE_UNISTD_H
4152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod#include <unistd.h> /* for isatty() */
4252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod#endif
4352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
44b4c5c52944a44ba863a22a53035ff561af7318caChun-wei Fan#ifdef _MSC_VER
45b4c5c52944a44ba863a22a53035ff561af7318caChun-wei Fanstatic inline long int
46b4c5c52944a44ba863a22a53035ff561af7318caChun-wei Fanlround (double x)
47b4c5c52944a44ba863a22a53035ff561af7318caChun-wei Fan{
48b4c5c52944a44ba863a22a53035ff561af7318caChun-wei Fan  if (x >= 0)
49b4c5c52944a44ba863a22a53035ff561af7318caChun-wei Fan    return floor (x + 0.5);
50b4c5c52944a44ba863a22a53035ff561af7318caChun-wei Fan  else
51b4c5c52944a44ba863a22a53035ff561af7318caChun-wei Fan    return ceil (x - 0.5);
52b4c5c52944a44ba863a22a53035ff561af7318caChun-wei Fan}
53b4c5c52944a44ba863a22a53035ff561af7318caChun-wei Fan#endif
54b4c5c52944a44ba863a22a53035ff561af7318caChun-wei Fan
5552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod#define MIN(a,b) ((a) < (b) ? (a) : (b))
5652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
5752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod#define CELL_W 8
5852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod#define CELL_H (2 * CELL_W)
5952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
6052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbodstruct color_diff_t
6152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod{
6252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  int dot (const color_diff_t &o)
6352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  { return v[0]*o.v[0] + v[1]*o.v[1] + v[2]*o.v[2] + v[3]*o.v[3]; }
6452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
6552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  int v[4];
6652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod};
6752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
6852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbodstruct color_t
6952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod{
7052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  static color_t from_ansi (unsigned int x)
7152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  {
7252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    color_t c = {(0xFF<<24) | ((0xFF*(x&1))<<16) | ((0xFF*((x >> 1)&1))<<8) | (0xFF*((x >> 2)&1))};
7352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    return c;
7452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  }
7552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  unsigned int to_ansi (void)
7652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  {
7752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    return ((v >> 23) & 1) | ((v >> 14)&2) | ((v >> 5)&4);
7852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  }
7952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
8052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  color_diff_t diff (const color_t &o)
8152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  {
8252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    color_diff_t d;
8352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    for (unsigned int i = 0; i < 4; i++)
8452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      d.v[i] = (int) ((v >> (i*8))&0xFF) - (int) ((o.v >> (i*8))&0xFF);
8552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    return d;
8652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  }
8752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
8852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  uint32_t v;
8952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod};
9052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
9152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbodstruct image_t
9252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod{
9352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  public:
9452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
9552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  image_t (unsigned int width_,
9652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	   unsigned int height_,
9752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	   const uint32_t *data_,
9852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	   unsigned int stride_) :
9952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod		width (width_),
10052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod		height (height_),
10152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod		own_data (false),
10252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod		data ((color_t *) data_),
10352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod		stride (stride_) {}
10452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  image_t (unsigned int width_,
10552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	   unsigned int height_) :
10652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod		width (width_),
10752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod		height (height_),
10852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod		own_data (true),
10952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod		data ((color_t *) malloc (sizeof (data[0]) * width * height)),
11052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod		stride (width) {}
11152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  ~image_t (void)
11252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  { if (own_data) free (data); }
11352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
11452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  color_t &operator () (unsigned int x, unsigned int y)
11552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  { return data[x + y * stride]; }
11652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
11752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  color_t operator () (unsigned int x, unsigned int y) const
11852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  { return data[x + y * stride]; }
11952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
12052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  void
12152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  copy_sub_image (const image_t &s,
12252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod		  unsigned int x, unsigned int y,
12352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod		  unsigned int w, unsigned int h)
12452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  {
12552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    assert (x < width);
12652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    assert (y < height);
12752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    for (unsigned int row = 0; row < h; row++) {
12852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      color_t *p = data + x + MIN (y + row, height - 1) * stride;
12952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      color_t *q = s.data + row * s.stride;
13052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      if (x + w <= width)
13152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	for (unsigned int col = 0; col < w; col++)
13252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	  *q++ = *p++;
13352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      else {
13452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod        unsigned int limit = width - x;
13552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	for (unsigned int col = 0; col < limit; col++)
13652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	  *q++ = *p++;
13752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	p--;
13852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	for (unsigned int col = limit; col < w; col++)
13952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	  *q++ = *p;
14052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      }
14152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    }
14252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  }
14352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
14452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  const unsigned int width;
14552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  const unsigned int height;
14652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
14752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  private:
14852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  bool own_data;
14952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  color_t * const data;
15052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  const unsigned int stride;
15152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod};
15252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
15352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbodstruct biimage_t
15452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod{
15552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  public:
15652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
15752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  biimage_t (unsigned int width, unsigned int height) :
15852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod		width (width),
15952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod		height (height),
1607235f33f9e5e031622a00a84f4b2e98f16803579Behdad Esfahbod		bg (0), fg (0), unicolor (true),
16152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod		data ((uint8_t *) malloc (sizeof (data[0]) * width * height)) {}
16252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  ~biimage_t (void)
16352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  { free (data); }
16452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
16552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  void set (const image_t &image)
16652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  {
16752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    assert (image.width == width);
16852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    assert (image.height == height);
16952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    int freq[8] = {0};
17052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    for (unsigned int y = 0; y < height; y++)
17152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      for (unsigned int x = 0; x < width; x++) {
17252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod        color_t c = image (x, y);
17352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod        freq[c.to_ansi ()]++;
17452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      }
17552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    bg = 0;
17652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    for (unsigned int i = 1; i < 8; i++)
17752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      if (freq[bg] < freq[i])
17852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod        bg = i;
17952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    fg = 0;
18052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    for (unsigned int i = 1; i < 8; i++)
18152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      if (i != bg && freq[fg] < freq[i])
18252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod        fg = i;
18352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    if (fg == bg || freq[fg] == 0) {
18452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      fg = bg;
18552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      unicolor = true;
18652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    }
18752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    else
18852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      unicolor = false;
18952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
19052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    /* Set the data... */
19152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
19252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    if (unicolor) {
19352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      memset (data, 0, sizeof (data[0]) * width * height);
19452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      return;
19552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    }
19652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
19752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    color_t bgc = color_t::from_ansi (bg);
19852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    color_t fgc = color_t::from_ansi (fg);
19952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    color_diff_t diff = fgc.diff (bgc);
20052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    int dd = diff.dot (diff);
20152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    for (unsigned int y = 0; y < height; y++)
20252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      for (unsigned int x = 0; x < width; x++) {
20352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod        int d = diff.dot (image (x, y).diff (bgc));
20452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	(*this)(x, y) = d < 0 ? 0 : d > dd ? 255 : lround (d * 255. / dd);
20552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      }
20652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  }
20752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
20852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  uint8_t &operator () (unsigned int x, unsigned int y)
20952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  { return data[x + y * width]; }
21052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
21152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  uint8_t operator () (unsigned int x, unsigned int y) const
21252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  { return data[x + y * width]; }
21352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
21452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  const unsigned int width;
21552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  const unsigned int height;
21652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  unsigned int bg;
21752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  unsigned int fg;
21852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  bool unicolor;
21952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
22052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  private:
22152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  uint8_t * const data;
22252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod};
22352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
22452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbodconst char *
22552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbodblock_best (const biimage_t &bi, unsigned int *score, bool *inverse)
22652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod{
2277ec83051c05777c0e6e2eea6ef6c71effede9527Behdad Esfahbod  assert (bi.width  <= CELL_W);
2287ec83051c05777c0e6e2eea6ef6c71effede9527Behdad Esfahbod  assert (bi.height <= CELL_H);
22952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
2307ec83051c05777c0e6e2eea6ef6c71effede9527Behdad Esfahbod  unsigned int row_sum[CELL_H] = {0};
2317ec83051c05777c0e6e2eea6ef6c71effede9527Behdad Esfahbod  unsigned int col_sum[CELL_W] = {0};
2327ec83051c05777c0e6e2eea6ef6c71effede9527Behdad Esfahbod  unsigned int row_sum_i[CELL_H] = {0};
2337ec83051c05777c0e6e2eea6ef6c71effede9527Behdad Esfahbod  unsigned int col_sum_i[CELL_W] = {0};
23452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  unsigned int quad[2][2] = {{0}};
23552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  unsigned int quad_i[2][2] = {{0}};
2367ec83051c05777c0e6e2eea6ef6c71effede9527Behdad Esfahbod  unsigned int total = 0;
2377ec83051c05777c0e6e2eea6ef6c71effede9527Behdad Esfahbod  unsigned int total_i = 0;
23852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  for (unsigned int y = 0; y < bi.height; y++)
23952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    for (unsigned int x = 0; x < bi.width; x++) {
24052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      unsigned int c = bi (x, y);
2417ec83051c05777c0e6e2eea6ef6c71effede9527Behdad Esfahbod      unsigned int c_i = 255 - c;
24252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      row_sum[y] += c;
2437ec83051c05777c0e6e2eea6ef6c71effede9527Behdad Esfahbod      row_sum_i[y] += c_i;
24452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      col_sum[x] += c;
2457ec83051c05777c0e6e2eea6ef6c71effede9527Behdad Esfahbod      col_sum_i[x] += c_i;
24652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      quad[2 * y / bi.height][2 * x / bi.width] += c;
2477ec83051c05777c0e6e2eea6ef6c71effede9527Behdad Esfahbod      quad_i[2 * y / bi.height][2 * x / bi.width] += c_i;
24852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      total += c;
2497ec83051c05777c0e6e2eea6ef6c71effede9527Behdad Esfahbod      total_i += c_i;
25052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    }
25152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
25252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  /* Make the sums cummulative */
25352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  for (unsigned int i = 1; i < bi.height; i++) {
25452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    row_sum[i] += row_sum[i - 1];
25552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    row_sum_i[i] += row_sum_i[i - 1];
25652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  }
25752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  for (unsigned int i = 1; i < bi.width;  i++) {
25852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    col_sum[i] += col_sum[i - 1];
25952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    col_sum_i[i] += col_sum_i[i - 1];
26052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  }
26152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
26252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  const char *best_c = " ";
26352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
26452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  /* Maybe empty is better! */
26552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  if (total < *score) {
26652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    *score = total;
26752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    *inverse = false;
26852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    best_c = " ";
26952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  }
27052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  /* Maybe full is better! */
27152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  if (total_i < *score) {
27252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    *score = total_i;
27352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    *inverse = true;
27452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    best_c = " ";
27552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  }
27652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
27752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  /* Find best lower line */
27852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  if (1) {
27952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    unsigned int best_s = (unsigned int) -1;
28052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    bool best_inv = false;
28152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    int best_i = 0;
28252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    for (unsigned int i = 0; i < bi.height - 1; i++)
28352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    {
28452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      unsigned int s;
28552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      s = row_sum[i] + total_i - row_sum_i[i];
28652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      if (s < best_s) {
28752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod        best_s = s;
28852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	best_i = i;
28952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	best_inv = false;
29052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      }
29152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      s = row_sum_i[i] + total - row_sum[i];
29252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      if (s < best_s) {
29352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod        best_s = s;
29452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	best_i = i;
29552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	best_inv = true;
29652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      }
29752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    }
29852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    if (best_s < *score) {
29952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      static const char *lower[7] = {"▁", "▂", "▃", "▄", "▅", "▆", "▇"};
30052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      unsigned int which = lround (((best_i + 1) * 8) / bi.height);
30152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      if (1 <= which && which <= 7) {
30252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	*score = best_s;
30352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	*inverse = best_inv;
30452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	best_c = lower[7 - which];
30552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      }
30652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    }
30752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  }
30852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
30952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  /* Find best left line */
31052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  if (1) {
31152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    unsigned int best_s = (unsigned int) -1;
31252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    bool best_inv = false;
31352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    int best_i = 0;
31452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    for (unsigned int i = 0; i < bi.width - 1; i++)
31552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    {
31652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      unsigned int s;
31752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      s = col_sum[i] + total_i - col_sum_i[i];
31852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      if (s < best_s) {
31952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod        best_s = s;
32052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	best_i = i;
32152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	best_inv = true;
32252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      }
32352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      s = col_sum_i[i] + total - col_sum[i];
32452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      if (s < best_s) {
32552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod        best_s = s;
32652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	best_i = i;
32752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	best_inv = false;
32852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      }
32952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    }
33052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    if (best_s < *score) {
33152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      static const char *left [7] = {"▏", "▎", "▍", "▌", "▋", "▊", "▉"};
33252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      unsigned int which = lround (((best_i + 1) * 8) / bi.width);
33352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      if (1 <= which && which <= 7) {
33452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	*score = best_s;
33552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	*inverse = best_inv;
33652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod	best_c = left[which - 1];
33752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      }
33852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    }
33952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  }
34052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
3418caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod  /* Find best quadrant */
3428caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod  if (1) {
3438caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod    unsigned int q = 0;
3448caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod    unsigned int qs = 0;
3458caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod    for (unsigned int i = 0; i < 2; i++)
3468caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod      for (unsigned int j = 0; j < 2; j++)
3478caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod	if (quad[i][j] > quad_i[i][j]) {
3488caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod	  q += 1 << (2 * i + j);
3498caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod	  qs += quad_i[i][j];
3508caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod	} else
3518caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod	  qs += quad[i][j];
3528caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod    if (qs < *score) {
3538caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod      const char *c = NULL;
3548caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod      bool inv = false;
3558caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod      switch (q) {
3568caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod	case 1:  c = "▟"; inv = true;  break;
3578caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod	case 2:  c = "▙"; inv = true;  break;
3588caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod	case 4:  c = "▖"; inv = false; break;
3598caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod	case 8:  c = "▗"; inv = false; break;
3608caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod	case 9:  c = "▚"; inv = false; break;
3618caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod	case 6:  c = "▞"; inv = false; break;
3628caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod	case 7:  c = "▜"; inv = true;  break;
3638caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod	case 11: c = "▜"; inv = true;  break;
3648caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod	case 13: c = "▙"; inv = true;  break;
3658caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod	case 14: c = "▟"; inv = true;  break;
3668caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod      }
3678caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod      if (c) {
3688caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod	*score = qs;
3698caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod	*inverse = inv;
3708caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod	best_c = c;
3718caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod      }
37252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    }
37352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  }
37452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
37552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  return best_c;
37652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod}
37752e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
37852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbodvoid
37952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbodansi_print_image_rgb24 (const uint32_t *data,
38052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod			unsigned int width,
38152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod			unsigned int height,
38252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod			unsigned int stride)
38352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod{
38452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  image_t image (width, height, data, stride);
38552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod
38652e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  unsigned int rows = (height + CELL_H - 1) / CELL_H;
3878caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod  unsigned int cols = (width +  CELL_W - 1) / CELL_W;
38852e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  image_t cell (CELL_W, CELL_H);
38952e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  biimage_t bi (CELL_W, CELL_H);
390db0de7cd616e1e9d6fde6659e52a541477fb0148Behdad Esfahbod  unsigned int last_bg = -1, last_fg = -1;
39152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  for (unsigned int row = 0; row < rows; row++) {
39252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    for (unsigned int col = 0; col < cols; col++) {
39352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      image.copy_sub_image (cell, col * CELL_W, row * CELL_H, CELL_W, CELL_H);
39452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      bi.set (cell);
395db0de7cd616e1e9d6fde6659e52a541477fb0148Behdad Esfahbod      if (bi.unicolor) {
396db0de7cd616e1e9d6fde6659e52a541477fb0148Behdad Esfahbod        if (last_bg != bi.bg) {
397db0de7cd616e1e9d6fde6659e52a541477fb0148Behdad Esfahbod	  printf ("\e[%dm", 40 + bi.bg);
398db0de7cd616e1e9d6fde6659e52a541477fb0148Behdad Esfahbod	  last_bg = bi.bg;
399db0de7cd616e1e9d6fde6659e52a541477fb0148Behdad Esfahbod	}
400db0de7cd616e1e9d6fde6659e52a541477fb0148Behdad Esfahbod	printf (" ");
401db0de7cd616e1e9d6fde6659e52a541477fb0148Behdad Esfahbod      } else {
40252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod        /* Figure out the closest character to the biimage */
40352e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod        unsigned int score = (unsigned int) -1;
4048caf5dcd66550351c6038b9ae7ecc5254eed64ffBehdad Esfahbod	bool inverse = false;
40552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod        const char *c = block_best (bi, &score, &inverse);
406db0de7cd616e1e9d6fde6659e52a541477fb0148Behdad Esfahbod	if (inverse) {
407db0de7cd616e1e9d6fde6659e52a541477fb0148Behdad Esfahbod	  if (last_bg != bi.fg || last_fg != bi.bg) {
408db0de7cd616e1e9d6fde6659e52a541477fb0148Behdad Esfahbod	    printf ("\e[%d;%dm", 30 + bi.bg, 40 + bi.fg);
409db0de7cd616e1e9d6fde6659e52a541477fb0148Behdad Esfahbod	    last_bg = bi.fg;
410db0de7cd616e1e9d6fde6659e52a541477fb0148Behdad Esfahbod	    last_fg = bi.bg;
411db0de7cd616e1e9d6fde6659e52a541477fb0148Behdad Esfahbod	  }
412db0de7cd616e1e9d6fde6659e52a541477fb0148Behdad Esfahbod	} else {
413db0de7cd616e1e9d6fde6659e52a541477fb0148Behdad Esfahbod	  if (last_bg != bi.bg || last_fg != bi.fg) {
414db0de7cd616e1e9d6fde6659e52a541477fb0148Behdad Esfahbod	    printf ("\e[%d;%dm", 40 + bi.bg, 30 + bi.fg);
415db0de7cd616e1e9d6fde6659e52a541477fb0148Behdad Esfahbod	    last_bg = bi.bg;
416db0de7cd616e1e9d6fde6659e52a541477fb0148Behdad Esfahbod	    last_fg = bi.fg;
417db0de7cd616e1e9d6fde6659e52a541477fb0148Behdad Esfahbod	  }
418db0de7cd616e1e9d6fde6659e52a541477fb0148Behdad Esfahbod	}
419db0de7cd616e1e9d6fde6659e52a541477fb0148Behdad Esfahbod	printf ("%s", c);
42052e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod      }
42152e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    }
42252e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod    printf ("\e[0m\n"); /* Reset */
423db0de7cd616e1e9d6fde6659e52a541477fb0148Behdad Esfahbod    last_bg = last_fg = -1;
42452e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod  }
42552e7b1424a3613122e9ca30879298df42733acdaBehdad Esfahbod}
426