1 /*
2  * Copyright (c) 1997, 1999, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 #include "awt.h"
27 #include "awt_image.h"
28 
29 extern "C" {
30 #include "img_colors.h"
31 } // extern "C"
32 
33 char *programname = "awt_makecube";
34 
35 unsigned char cube[LOOKUPSIZE * LOOKUPSIZE * LOOKUPSIZE];
36 
37 unsigned char reds[256], greens[256], blues[256], indices[256];
38 int num_colors;
39 
40 PALETTEENTRY sysPal[256];
41 
42 int sys2cmap[256];
43 int cmap2sys[256];
44 int error[256];
45 
46 int cmapsize = 0;
47 int virtcubesize = 0;
48 int makecube_verbose = 0;
49 
50 void printPalette(char *label, HPALETTE hPal);
51 
usage(char * errmsg)52 void usage(char *errmsg)
53 {
54     fprintf(stderr, "%s\n", errmsg);
55     fprintf(stderr, "usage: %s [-cmapsize N] [-cubesize N]\n", programname);
56     fprintf(stderr, "\t-cmapsize N   set the number of colors to allocate\n");
57     fprintf(stderr, "\t              in the colormap (2 <= N <= 256)\n");
58     fprintf(stderr, "\t-cubesize N   set the size of the cube of colors to\n");
59     fprintf(stderr, "                scan as potential entries in the cmap\n");
60     fprintf(stderr, "                (N must be a power of 2 and <= 32)\n");
61     exit(1);
62 }
63 
setsyscolor(int index,int red,int green,int blue)64 void setsyscolor(int index, int red, int green, int blue)
65 {
66     if (index >= 0) {
67         if (sysPal[index].peFlags != 0) {
68             usage("Internal error: system palette conflict");
69         }
70     } else {
71         for (int i = 0; i < 256; i++) {
72             if (sysPal[i].peFlags != 0) {
73                 if (sysPal[i].peRed   == red &&
74                     sysPal[i].peGreen == green &&
75                     sysPal[i].peBlue  == blue)
76                 {
77                     // Already there.  Ignore it.
78                     return;
79                 }
80             } else if (index < 0) {
81                 index = i;
82             }
83         }
84         if (index < 0) {
85             usage("Internal error: ran out of system palette entries");
86         }
87     }
88     sysPal[index].peRed   = red;
89     sysPal[index].peGreen = green;
90     sysPal[index].peBlue  = blue;
91     sysPal[index].peFlags = 1;
92 }
93 
addcmapcolor(int red,int green,int blue)94 void addcmapcolor(int red, int green, int blue)
95 {
96     for (int i = 0; i < num_colors; i++) {
97         if (red == reds[i] && green == greens[i] && blue == blues[i]) {
98             return;
99         }
100     }
101     if (num_colors >= cmapsize) {
102         usage("Internal error: more than cmapsize static colors defined");
103     }
104     reds[num_colors]   = red;
105     greens[num_colors] = green;
106     blues[num_colors]  = blue;
107     num_colors++;
108 }
109 
main(int argc,char ** argv)110 int main(int argc, char **argv)
111 {
112     int i;
113 
114     programname = argv[0];
115 
116     for (i = 1; i < argc; i++) {
117         if (strcmp(argv[i], "-cmapsize") == 0) {
118             if (i++ >= argc) {
119                 usage("no argument to -cmapsize");
120             }
121             cmapsize = atoi(argv[i]);
122             if (cmapsize <= 2 || cmapsize > 256) {
123                 usage("colormap size must be between 2 and 256");
124             }
125         } else if (strcmp(argv[1], "-cubesize") == 0) {
126             if (i++ >= argc) {
127                 usage("no argument to -cubesize");
128             }
129             virtcubesize = atoi(argv[i]);
130             if (virtcubesize == 0 ||
131                 (virtcubesize & (virtcubesize - 1)) != 0 ||
132                 virtcubesize > 32)
133             {
134                 usage("cube size must by a power of 2 <= 32");
135             }
136         } else if (strcmp(argv[i], "-verbose") == 0) {
137             makecube_verbose = 1;
138         } else {
139             usage("unknown argument");
140         }
141     }
142 
143     if (cmapsize == 0) {
144         cmapsize = CMAPSIZE;
145     }
146     if (virtcubesize == 0) {
147         virtcubesize = VIRTCUBESIZE;
148     }
149 
150     if (0) {  // For testing
151         HDC hDC = CreateDC("DISPLAY", NULL, NULL, NULL);
152         HPALETTE hPal = CreateHalftonePalette(hDC);
153         printPalette("Halftone palette for current display", hPal);
154         printPalette("Stock DEFAULT_PALETTE", (HPALETTE)GetStockObject(DEFAULT_PALETTE));
155         BITMAPINFOHEADER bmInfo = {
156             sizeof(BITMAPINFOHEADER), 1, 1, 1, 8, BI_RGB, 0, 1000, 1000, 0, 0
157             };
158         HBITMAP hBitmap = CreateDIBitmap(hDC, &bmInfo,
159                                          0, NULL, NULL, DIB_RGB_COLORS);
160         HDC hMemDC = CreateCompatibleDC(hDC);
161         SelectObject(hDC, hBitmap);
162         hPal = CreateHalftonePalette(hMemDC);
163         printPalette("Halftone palette for 8-bit DIBitmap", hPal);
164         exit(0);
165     }
166 
167     // Allocate Windows static system colors.
168     {
169         PALETTEENTRY palEntries[256];
170         HPALETTE hPal = (HPALETTE)GetStockObject(DEFAULT_PALETTE);
171         int n = GetPaletteEntries(hPal, 0, 256, palEntries);
172         for (i = 0; i < n; i++) {
173             addcmapcolor(palEntries[i].peRed,
174                          palEntries[i].peGreen,
175                          palEntries[i].peBlue);
176             setsyscolor((i < n / 2) ? i : i + (256 - n),
177                         palEntries[i].peRed,
178                         palEntries[i].peGreen,
179                         palEntries[i].peBlue);
180         }
181     }
182 
183     // Allocate java.awt.Color constant colors.
184     addcmapcolor(  0,   0,   0);        // black
185     addcmapcolor(255, 255, 255);        // white
186     addcmapcolor(255,   0,   0);        // red
187     addcmapcolor(  0, 255,   0);        // green
188     addcmapcolor(  0,   0, 255);        // blue
189     addcmapcolor(255, 255,   0);        // yellow
190     addcmapcolor(255,   0, 255);        // magenta
191     addcmapcolor(  0, 255, 255);        // cyan
192     addcmapcolor(192, 192, 192);        // lightGray
193     addcmapcolor(128, 128, 128);        // gray
194     addcmapcolor( 64,  64,  64);        // darkGray
195     addcmapcolor(255, 175, 175);        // pink
196     addcmapcolor(255, 200,   0);        // orange
197 
198     img_makePalette(cmapsize, virtcubesize, LOOKUPSIZE,
199                     50.0f, 250.0f,
200                     num_colors, TRUE, reds, greens, blues, cube);
201 
202     if (makecube_verbose) {
203         fprintf(stderr, "Calculated colormap:\n");
204         for (i = 0; i < cmapsize; i++) {
205             fprintf(stderr, "%3d:(%3d,%3d,%3d)   ",
206                     i, reds[i], greens[i], blues[i]);
207         }
208         fprintf(stderr, "\n");
209     }
210 
211     // Now simulate adding the halftone palette to the system
212     // palette to get an idea of palette ordering.
213     {
214         int cubevals[6] = {0, 44, 86, 135, 192, 255};
215         for (int b = 0; b < 6; b++) {
216             for (int g = 0; g < 6; g++) {
217                 for (int r = 0; r < 6; r++) {
218                     setsyscolor(-1, cubevals[r], cubevals[g], cubevals[b]);
219                 }
220             }
221         }
222         int grayvals[26] = {  0,  17,  24,  30,  37,  44,  52,  60,
223                              68,  77,  86,  95, 105, 114, 125, 135,
224                             146, 157, 168, 180, 192, 204, 216, 229,
225                             242, 255 };
226         for (i = 0; i < 26; i++) {
227             setsyscolor(-1, grayvals[i], grayvals[i], grayvals[i]);
228         }
229     }
230 
231     if (makecube_verbose) {
232         fprintf(stderr, "System palette with simulated halftone palette:\n");
233         for (i = 0; i < 256; i++) {
234             fprintf(stderr, "%3d:(%3d,%3d,%3d)   ",
235                     i, sysPal[i].peRed, sysPal[i].peGreen, sysPal[i].peBlue);
236         }
237     }
238 
239     if (makecube_verbose) {
240         HDC hDC = CreateDC("DISPLAY", NULL, NULL, NULL);
241         HPALETTE hPal = CreateHalftonePalette(hDC);
242         SelectPalette(hDC, hPal, FALSE);
243         RealizePalette(hDC);
244         PALETTEENTRY palEntries[256];
245         int n = GetSystemPaletteEntries(hDC, 0, 256, palEntries);
246         fprintf(stderr,
247                 "realized halftone palette reads back %d entries\n", n);
248         int broken = 0;
249         for (i = 0; i < 256; i++) {
250             char *msg1 = "";
251             char *msg2 = "";
252             if (palEntries[i].peRed != sysPal[i].peRed ||
253                 palEntries[i].peGreen != sysPal[i].peGreen ||
254                 palEntries[i].peBlue != sysPal[i].peBlue)
255             {
256                 msg1 = "no sysPal match!";
257                 if (sysPal[i].peFlags == 0) {
258                     msg2 = "(OK)";
259                 } else {
260                     broken++;
261                 }
262             } else if (sysPal[i].peFlags == 0) {
263                 msg1 = "no sysPal entry...";
264             }
265             fprintf(stderr,
266                     "palEntries[%3d] = (%3d, %3d, %3d), flags = %d  %s %s\n",
267                     i,
268                     palEntries[i].peRed,
269                     palEntries[i].peGreen,
270                     palEntries[i].peBlue,
271                     palEntries[i].peFlags, msg1, msg2);
272         }
273         fprintf(stderr, "%d broken entries\n", broken);
274     }
275 
276 #if 0
277 #define BIGERROR (255 * 255 * 255)
278 
279     for (i = 0; i < 256; i++) {
280         sys2cmap[i] = -1;
281         cmap2sys[i] = -1;
282         error[i] = BIGERROR;
283         // error[i] = -1 means cmap[i] is locked to cmap2sys[i]
284         // error[i] >= 0 means cmap[i] may lock to cmap2sys[i] on this run
285     }
286 
287     int nummapped;
288     int totalmapped = 0;
289     do {
290         int maxerror = BIGERROR;
291         for (i = 0; i < 256; i++) {
292             if (sysPal[i].peFlags == 0 || sys2cmap[i] >= 0) {
293                 continue;
294             }
295             int red   = sysPal[i].peRed;
296             int green = sysPal[i].peGreen;
297             int blue  = sysPal[i].peBlue;
298             int e = maxerror;
299             int ix = -1;
300             for (int j = 0; j < 256; j++) {
301                 if (error[j] < 0) {
302                     continue;
303                 }
304                 int t = red - reds[j];
305                 int d = t * t;
306                 t = green - greens[j];
307                 d += t * t;
308                 t = blue - blues[j];
309                 d += t * t;
310                 if (d < e) {
311                     e = d;
312                     ix = j;
313                 }
314             }
315             if (ix >= 0) {
316                 if (e < error[ix]) {
317                     if (cmap2sys[ix] >= 0) {
318                         // To be fair we will not accept any matches
319                         // looser than this former match that we just
320                         // displaced with a better match.
321                         if (maxerror > error[ix]) {
322                             maxerror = error[ix];
323                         }
324                         sys2cmap[cmap2sys[ix]] = -1;
325                     }
326                     error[ix] = e;
327                     sys2cmap[i] = ix;
328                     cmap2sys[ix] = i;
329                 }
330             }
331         }
332         nummapped = 0;
333         for (i = 0; i < 256; i++) {
334             if (error[i] >= 0) {
335                 if (error[i] >= maxerror) {
336                     // Throw this one back to be fair to a displaced entry.
337                     error[i] = BIGERROR;
338                     sys2cmap[cmap2sys[i]] = -1;
339                     cmap2sys[i] = -1;
340                     continue;
341                 }
342                 error[i] = -1;
343                 nummapped++;
344             }
345         }
346         totalmapped += nummapped;
347         if (makecube_verbose) {
348             fprintf(stderr, "%3d colors mapped (%3d total), maxerror = %d\n",
349                     nummapped, totalmapped, maxerror);
350         }
351     } while (nummapped != 0);
352 
353     for (i = 0; i < 256; i++) {
354         if (cmap2sys[i] < 0) {
355             for (int j = 0; j < 256; j++) {
356                 if (sys2cmap[j] < 0) {
357                     cmap2sys[i] = j;
358                     sys2cmap[j] = i;
359                     break;
360                 }
361             }
362             if (j == 256) {
363                 usage("Internal error: no unused system entry for cmap entry!\n");
364             }
365         }
366     }
367 #else
368     for (i = 0; i < 256; i++) {
369         if (i < 10) {
370             sys2cmap[i] = i;
371             cmap2sys[i] = i;
372         } else if (i < 20) {
373             sys2cmap[256 - 20 + i] = i;
374             cmap2sys[i] = 256 - 20 + i;
375         } else {
376             sys2cmap[i - 10] = i;
377             cmap2sys[i] = i - 10;
378         }
379     }
380 #endif
381 
382     if (makecube_verbose) {
383         fprintf(stderr, "cmap2sys mapping: \n");
384         for (i = 0; i < 256; i++) {
385             fprintf(stderr, "%4d", cmap2sys[i]);
386             if (sys2cmap[cmap2sys[i]] != i) {
387                 usage("Internal error: bad system palette back pointer!\n");
388             }
389         }
390         fprintf(stderr, "\n");
391     }
392 
393     printf("unsigned char awt_reds[256] = {");
394     for (i = 0; i < 256; i++) {
395         if ((i & 0xf) == 0) printf("\n\t");
396         printf("%3d,", reds[sys2cmap[i]]);
397     }
398     printf("\n};\n");
399     printf("unsigned char awt_greens[256] = {");
400     for (i = 0; i < 256; i++) {
401         if ((i & 0xf) == 0) printf("\n\t");
402         printf("%3d,", greens[sys2cmap[i]]);
403     }
404     printf("\n};\n");
405     printf("unsigned char awt_blues[256] = {");
406     for (i = 0; i < 256; i++) {
407         if ((i & 0xf) == 0) printf("\n\t");
408         printf("%3d,", blues[sys2cmap[i]]);
409     }
410     printf("\n};\n");
411     fflush(stdout);
412     return 0;
413 }
414 
printPalette(char * label,HPALETTE hPal)415 void printPalette(char *label, HPALETTE hPal)
416 {
417     PALETTEENTRY palEntries[256];
418     fprintf(stderr, "%s (0x%08x):\n", label, hPal);
419     int n = GetPaletteEntries(hPal, 0, 256, palEntries);
420     for (int i = 0; i < n; i++) {
421         fprintf(stderr, "palEntries[%3d] = (%3d, %3d, %3d), flags = %d\n",
422                 i,
423                 palEntries[i].peRed,
424                 palEntries[i].peGreen,
425                 palEntries[i].peBlue,
426                 palEntries[i].peFlags);
427     }
428 }
429 
430 /* This helps eliminate any dependence on javai.dll at build time. */
431 int
jio_fprintf(FILE * handle,const char * format,...)432 jio_fprintf (FILE *handle, const char *format, ...)
433 {
434     int len;
435 
436     va_list args;
437     va_start(args, format);
438     len = vfprintf(handle, format, args);
439     va_end(args);
440 
441     return len;
442 }
443