ARB
AW_rgb.cxx
Go to the documentation of this file.
1 // ============================================================ //
2 // //
3 // File : AW_rgb.cxx //
4 // Purpose : //
5 // //
6 // Coded by Ralf Westram (coder@reallysoft.de) in June 2016 //
7 // http://www.arb-home.de/ //
8 // //
9 // ============================================================ //
10 
11 #include "aw_rgb.hxx"
12 
13 static AW_rgb16 CRAZY_PINK("#C0C");
14 static AW_rgb16 convert_xcolorname(const char *xcolorname, bool& failed);
15 
16 void AW_rgb16::rescale(uint16_t my_max) {
17  float scale = MAX/my_max;
18 
19  R = R*scale + 0.5;
20  G = G*scale + 0.5;
21  B = B*scale + 0.5;
22 }
23 
24 AW_rgb16::AW_rgb16(const char *colorname) {
29  bool failed = (colorname[0] != '#');
30  if (!failed) {
31  const char *end;
32  unsigned long num = strtoul(colorname+1, const_cast<char**>(&end), 16);
33  int length = end-colorname-1;
34 
35  switch (length) {
36  case 3: R = num >> 8; G = (num >> 4) & 0xf; B = num & 0xf; rescale(0xf); break;
37  case 6: R = num >> 16; G = (num >> 8) & 0xff; B = num & 0xff; rescale(0xff); break;
38  case 9: R = num >> 24; G = (num >> 12) & 0xfff; B = num & 0xfff; rescale(0xfff); break;
39  case 12: R = num >> 32; G = (num >> 16) & 0xffff; B = num & 0xffff; break;
40 
41  default:
42  aw_assert(0); // hex color spec has invalid length
43  failed = true;
44  break;
45  }
46  }
47 
48  if (failed) *this = convert_xcolorname(colorname, failed);
49 
50  if (failed) {
51  fprintf(stderr, "Warning: Failed to interpret color '%s' - fallback to crazy pink\n", colorname);
52  *this = CRAZY_PINK;
53  }
54 }
55 
56 const char *AW_rgb16::ascii() const {
57  const int FIXEDLEN = 1+3*4;
58  static char buffer[FIXEDLEN+1];
59 
60 #if defined(ASSERTION_USED)
61  int printed =
62 #endif
63  sprintf(buffer, "#%04x%04x%04x", R, G, B);
64 
65  aw_assert(printed == FIXEDLEN);
66 
67  return buffer;
68 }
69 
70 // --------------------------------------------------------------------------------
71 
72 #ifdef UNIT_TESTS
73 #ifndef TEST_UNIT_H
74 #include <test_unit.h>
75 #endif
76 
77 #include <arb_msg.h>
78 
79 #define TEST_ASCII_COLOR_CONVERT(i,o) TEST_EXPECT_EQUAL(AW_rgb16(i).ascii(),o)
80 #define TEST_ASCII_COLOR_IDENT(c) TEST_ASCII_COLOR_CONVERT(c,c);
81 
82 #define TEST_NORMALIZED_CONVERSION(c) TEST_EXPECT_EQUAL(AW_rgb16(AW_rgb_normalized(AW_rgb16(c))).ascii(), c);
83 
84 #define TEST_NORMALIZED_CONTAINS(col,expected) TEST_EXPECT_EQUAL(GBS_global_string("(%.2f,%.2f,%.2f)", \
85  (col).r(), (col).g(), (col).b()), \
86  expected)
87 
88 #define TEST_DIFF_CONTAINS(diff,expected) TEST_NORMALIZED_CONTAINS(diff,expected)
89 
90 void TEST_rgb() {
91  // Note: more related tests in AW_preset.cxx@RGB_TESTS
92 
93  // check construction from diff.-length color specifications
94  AW_rgb16 orange4("#f80");
95  AW_rgb16 orange8("#ff8800");
96  AW_rgb16 orange12("#fff888000");
97  AW_rgb16 orange16("#ffff88880000");
98 
99  TEST_EXPECT(orange16 == AW_rgb16(65535, 34952, 0));
100  TEST_EXPECT(orange12 == orange16);
101  TEST_EXPECT(orange8 == orange12);
102  TEST_EXPECT(orange4 == orange8);
103 
104  AW_rgb16 lblue4("#004");
105  AW_rgb16 lblue8("#000044");
106  AW_rgb16 lblue12("#000000444");
107  AW_rgb16 lblue16("#000000004444");
108 
109  TEST_EXPECT(lblue16 == AW_rgb16(0, 0, 17476));
110  TEST_EXPECT(lblue12 == lblue16);
111  TEST_EXPECT(lblue8 == lblue12);
112  TEST_EXPECT(lblue4 == lblue8);
113 
114  TEST_EXPECT_EQUAL(lblue8.ascii(), "#000000004444");
115 
116  TEST_ASCII_COLOR_CONVERT("#1" "2" "3", "#1111" "2222" "3333");
117  TEST_ASCII_COLOR_CONVERT("#45" "67" "89", "#4545" "6767" "8989");
118  TEST_ASCII_COLOR_CONVERT("#678" "9ab" "cde", "#6786" "9ab9" "cdec");
119  TEST_ASCII_COLOR_CONVERT("#001" "010" "100", "#0010" "0100" "1001");
120 
121  TEST_ASCII_COLOR_IDENT("#0123456789ab");
122  TEST_ASCII_COLOR_IDENT("#fedcba987654");
123 
124  // conversion normalized -> 16bit for special values
125  TEST_EXPECT_EQUAL(AW_rgb16(AW_rgb_normalized(0.25, 0.5, 0.75 )).ascii(), "#3fff" "7fff" "bfff");
126  TEST_EXPECT_EQUAL(AW_rgb16(AW_rgb_normalized(1./3, 1./5, 1./7 )).ascii(), "#5555" "3333" "2492");
127  TEST_EXPECT_EQUAL(AW_rgb16(AW_rgb_normalized(.1, .01, .001 )).ascii(), "#1999" "028f" "0041");
128  TEST_EXPECT_EQUAL(AW_rgb16(AW_rgb_normalized(.0001, .00005, .00002)).ascii(), "#0006" "0003" "0001");
129 
130  // test conversion 16bit -> normalized -> 16bit is stable
131  TEST_NORMALIZED_CONVERSION("#000000000000");
132  TEST_NORMALIZED_CONVERSION("#0123456789ab");
133  TEST_NORMALIZED_CONVERSION("#ffffffffffff");
134 
135  // invalid colors
136  TEST_EXPECT(AW_rgb16("kashdkjasdh") == CRAZY_PINK);
138 }
139 
140 void TEST_rgb_diff() {
141  AW_rgb16 orange("#f80");
142  AW_rgb16 blue("#004");
143 
144  AW_rgb_diff blue2orange = orange - blue;
145  AW_rgb16 calc_orange = blue + blue2orange;
146  TEST_EXPECT(calc_orange == orange);
147 
148  AW_rgb_diff orange2blue = -blue2orange;
149  AW_rgb16 calc_blue = orange + orange2blue;
150  TEST_EXPECT(calc_blue == blue);
151 
152  for (float part = 0.1; part<1.0; part += 0.1) {
153  AW_rgb16 mix1 = orange + part * orange2blue;
154  AW_rgb16 mix2 = blue + (1-part) * blue2orange;
155  TEST_EXPECT(mix1 == mix2);
156  }
157 
158  // check that color calculation does not overflow:
159  AW_rgb16 black("#000");
160  AW_rgb16 white("#fff");
161  AW_rgb_diff black2white = white-black;
162 
163  AW_rgb16 whiter = white + black2white;
164  TEST_EXPECT_EQUAL(whiter.ascii(), "#ffffffffffff");
165  TEST_EXPECT(whiter == white);
166 
167  AW_rgb16 blacker = black - black2white;
168  TEST_EXPECT_EQUAL(blacker.ascii(), "#000000000000");
169  TEST_EXPECT(blacker == black);
170 
171  // summarized diff:
172  AW_rgb16 red("#f00");
173  AW_rgb16 green("#0f0");
174 
175  AW_rgb_diff blue2red = red-blue;
176  AW_rgb_diff blue2green = green-blue;
177 
178  TEST_DIFF_CONTAINS(blue2red, "(1.00,0.00,-0.27)");
179  TEST_DIFF_CONTAINS(blue2green, "(0.00,1.00,-0.27)");
180  TEST_DIFF_CONTAINS(blue2green.abs(), "(0.00,1.00,0.27)");
181 
182  {
183  AW_rgb_diff sum = blue2red + blue2green;
184  AW_rgb_diff abssum = blue2red.abs() + blue2green.abs();
185  AW_rgb_diff maxabsdiff = max(blue2red.abs(), blue2green.abs());
186 
187  TEST_DIFF_CONTAINS(sum, "(1.00,1.00,-0.53)");
188  TEST_DIFF_CONTAINS(abssum, "(1.00,1.00,0.53)");
189  TEST_DIFF_CONTAINS(maxabsdiff, "(1.00,1.00,0.27)");
190  }
191 
192  AW_rgb16 magenta("#f0f");
193  AW_rgb16 cyan("#0ff");
194 
195  AW_rgb_diff orange2magenta = magenta-orange;
196  AW_rgb_diff orange2cyan = cyan-orange;
197 
198  TEST_DIFF_CONTAINS(orange2magenta, "(0.00,-0.53,1.00)");
199  TEST_DIFF_CONTAINS(orange2cyan, "(-1.00,0.47,1.00)");
200 
201  {
202  AW_rgb_diff sum = orange2magenta + orange2cyan;
203  AW_rgb_diff abssum = orange2magenta.abs() + orange2cyan.abs();
204  AW_rgb_diff maxabsdiff = max(orange2magenta.abs(), orange2cyan.abs());
205 
206  TEST_DIFF_CONTAINS(sum, "(-1.00,-0.07,2.00)");
207  TEST_DIFF_CONTAINS(abssum, "(1.00,1.00,2.00)");
208  TEST_DIFF_CONTAINS(maxabsdiff, "(1.00,0.53,1.00)");
209  }
210 
211 }
212 
213 #endif // UNIT_TESTS
214 
215 // --------------------------------------------------------------------------------
216 
217 #include "aw_root.hxx"
218 #include "aw_window.hxx"
219 #include "aw_window_Xm.hxx"
220 
221 static AW_rgb16 convert_xcolorname(const char *xcolorname, bool& failed) {
222  XColor col, unused;
223  if (AW_root::SINGLETON) { // only works if window was set (by caller)
225  failed = !XLookupColor(mroot->display,
226  mroot->colormap,
227  xcolorname,
228  &col, // exact color
229  &unused); // screen-color
230  }
231  else {
232  failed = true;
233  }
234 
235  return
236  failed
237  ? AW_rgb16()
238  : AW_rgb16(col.red, col.green, col.blue);
239 }
240 
AW_root_Motif * prvt
Definition: aw_root.hxx:104
AW_rgb_diff abs() const
Definition: aw_rgb.hxx:114
static CONSTEXPR float MAX
Definition: aw_rgb.hxx:43
Colormap colormap
char buffer[MESSAGE_BUFFERSIZE]
Definition: seq_search.cxx:34
static AW_rgb16 convert_xcolorname(const char *xcolorname, bool &failed)
Definition: AW_rgb.cxx:221
const char * ascii() const
Definition: AW_rgb.cxx:56
AW_rgb16()
Definition: aw_rgb.hxx:45
static AW_root * SINGLETON
Definition: aw_root.hxx:102
#define TEST_EXPECT(cond)
Definition: test_unit.h:1328
static AW_rgb16 CRAZY_PINK("#C0C")
Display * display
#define aw_assert(bed)
Definition: aw_position.hxx:29
bool white(int ch)
size_t length
#define TEST_EXPECT_EQUAL(expr, want)
Definition: test_unit.h:1294
#define max(a, b)
Definition: f2c.h:154