1 /* See LICENSE file for licensing information.
2 */
3 
4 #include "pm_c_util.h"
5 #include "mallocvar.h"
6 #include "pnm.h"
7 #include "palm.h"
8 
9 #include "palmcolormap.h"
10 
11 
12 
13 static pixval
scaleSample(pixval const arg,pixval const oldMaxval,pixval const newMaxval)14 scaleSample(pixval const arg,
15             pixval const oldMaxval,
16             pixval const newMaxval) {
17 
18     return (arg * newMaxval + oldMaxval/2) / oldMaxval;
19 }
20 
21 
22 
23 ColormapEntry
palmcolor_mapEntryColorFmPixel(pixel const color,pixval const maxval,pixval const newMaxval)24 palmcolor_mapEntryColorFmPixel(pixel  const color,
25                                pixval const maxval,
26                                pixval const newMaxval) {
27 
28 
29     return
30         0
31         | (scaleSample(PPM_GETR(color), maxval, newMaxval) << 16)
32         | (scaleSample(PPM_GETG(color), maxval, newMaxval) <<  8)
33         | (scaleSample(PPM_GETB(color), maxval, newMaxval) <<  0);
34 }
35 
36 
37 
38 int
palmcolor_compare_indices(const void * const p1,const void * const p2)39 palmcolor_compare_indices(const void * const p1,
40                           const void * const p2) {
41 /*----------------------------------------------------------------------------
42    This is a 'qsort' collation function.
43 -----------------------------------------------------------------------------*/
44     if ((*((ColormapEntry *) p1) & 0xFF000000) < (*((ColormapEntry *) p2) & 0xFF000000))
45         return -1;
46     else if ((*((ColormapEntry *) p1) & 0xFF000000) > (*((ColormapEntry *) p2) & 0xFF000000))
47         return 1;
48     else
49         return 0;
50 }
51 
52 
53 
54 int
palmcolor_compare_colors(const void * const p1,const void * const p2)55 palmcolor_compare_colors(const void * const p1,
56                          const void * const p2) {
57 /*----------------------------------------------------------------------------
58    This is a 'qsort' collation function.
59 -----------------------------------------------------------------------------*/
60     unsigned long const val1 = *((const unsigned long *) p1) & 0xFFFFFF;
61     unsigned long const val2 = *((const unsigned long *) p2) & 0xFFFFFF;
62 
63     if (val1 < val2)
64         return -1;
65     else if (val1 > val2)
66         return 1;
67     else
68         return 0;
69 }
70 
71 /***********************************************************************
72  ***********************************************************************
73  ***********************************************************************
74  ******* colortables from pilrc-2.6/bitmap.c ***************************
75  ***********************************************************************
76  ***********************************************************************
77  ***********************************************************************/
78 
79 #if 0
80 
81 /*
82  * The 1bit-2 color system palette for Palm Computing Devices.
83  */
84 static int PalmPalette1bpp[2][3] =
85 {
86   { 255, 255, 255}, {   0,   0,   0 }
87 };
88 
89 /*
90  * The 2bit-4 color system palette for Palm Computing Devices.
91  */
92 static int PalmPalette2bpp[4][3] =
93 {
94   { 255, 255, 255}, { 192, 192, 192}, { 128, 128, 128 }, {   0,   0,   0 }
95 };
96 
97 /*
98  * The 4bit-16 color system palette for Palm Computing Devices.
99  */
100 static int PalmPalette4bpp[16][3] =
101 {
102   { 255, 255, 255}, { 238, 238, 238 }, { 221, 221, 221 }, { 204, 204, 204 },
103   { 187, 187, 187}, { 170, 170, 170 }, { 153, 153, 153 }, { 136, 136, 136 },
104   { 119, 119, 119}, { 102, 102, 102 }, {  85,  85,  85 }, {  68,  68,  68 },
105   {  51,  51,  51}, {  34,  34,  34 }, {  17,  17,  17 }, {   0,   0,   0 }
106 };
107 
108 /*
109  * The 4bit-16 color system palette for Palm Computing Devices.
110  */
111 static int PalmPalette4bppColor[16][3] =
112 {
113   { 255, 255, 255}, { 128, 128, 128 }, { 128,   0,   0 }, { 128, 128,   0 },
114   {   0, 128,   0}, {   0, 128, 128 }, {   0,   0, 128 }, { 128,   0, 128 },
115   { 255,   0, 255}, { 192, 192, 192 }, { 255,   0,   0 }, { 255, 255,   0 },
116   {   0, 255,   0}, {   0, 255, 255 }, {   0,   0, 255 }, {   0,   0,   0 }
117 };
118 
119 #endif  /* 0 */
120 
121 /*
122  * The 8bit-256 color system palette for Palm Computing Devices.
123  *
124  * NOTE:  only the first 231, plus the last one, are valid.
125  */
126 static int PalmPalette8bpp[256][3] =
127 {
128   { 255, 255, 255 }, { 255, 204, 255 }, { 255, 153, 255 }, { 255, 102, 255 },
129   { 255,  51, 255 }, { 255,   0, 255 }, { 255, 255, 204 }, { 255, 204, 204 },
130   { 255, 153, 204 }, { 255, 102, 204 }, { 255,  51, 204 }, { 255,   0, 204 },
131   { 255, 255, 153 }, { 255, 204, 153 }, { 255, 153, 153 }, { 255, 102, 153 },
132   { 255,  51, 153 }, { 255,   0, 153 }, { 204, 255, 255 }, { 204, 204, 255 },
133   { 204, 153, 255 }, { 204, 102, 255 }, { 204,  51, 255 }, { 204,   0, 255 },
134   { 204, 255, 204 }, { 204, 204, 204 }, { 204, 153, 204 }, { 204, 102, 204 },
135   { 204,  51, 204 }, { 204,   0, 204 }, { 204, 255, 153 }, { 204, 204, 153 },
136   { 204, 153, 153 }, { 204, 102, 153 }, { 204,  51, 153 }, { 204,   0, 153 },
137   { 153, 255, 255 }, { 153, 204, 255 }, { 153, 153, 255 }, { 153, 102, 255 },
138   { 153,  51, 255 }, { 153,   0, 255 }, { 153, 255, 204 }, { 153, 204, 204 },
139   { 153, 153, 204 }, { 153, 102, 204 }, { 153,  51, 204 }, { 153,   0, 204 },
140   { 153, 255, 153 }, { 153, 204, 153 }, { 153, 153, 153 }, { 153, 102, 153 },
141   { 153,  51, 153 }, { 153,   0, 153 }, { 102, 255, 255 }, { 102, 204, 255 },
142   { 102, 153, 255 }, { 102, 102, 255 }, { 102,  51, 255 }, { 102,   0, 255 },
143   { 102, 255, 204 }, { 102, 204, 204 }, { 102, 153, 204 }, { 102, 102, 204 },
144   { 102,  51, 204 }, { 102,   0, 204 }, { 102, 255, 153 }, { 102, 204, 153 },
145   { 102, 153, 153 }, { 102, 102, 153 }, { 102,  51, 153 }, { 102,   0, 153 },
146   {  51, 255, 255 }, {  51, 204, 255 }, {  51, 153, 255 }, {  51, 102, 255 },
147   {  51,  51, 255 }, {  51,   0, 255 }, {  51, 255, 204 }, {  51, 204, 204 },
148   {  51, 153, 204 }, {  51, 102, 204 }, {  51,  51, 204 }, {  51,   0, 204 },
149   {  51, 255, 153 }, {  51, 204, 153 }, {  51, 153, 153 }, {  51, 102, 153 },
150   {  51,  51, 153 }, {  51,   0, 153 }, {   0, 255, 255 }, {   0, 204, 255 },
151   {   0, 153, 255 }, {   0, 102, 255 }, {   0,  51, 255 }, {   0,   0, 255 },
152   {   0, 255, 204 }, {   0, 204, 204 }, {   0, 153, 204 }, {   0, 102, 204 },
153   {   0,  51, 204 }, {   0,   0, 204 }, {   0, 255, 153 }, {   0, 204, 153 },
154   {   0, 153, 153 }, {   0, 102, 153 }, {   0,  51, 153 }, {   0,   0, 153 },
155   { 255, 255, 102 }, { 255, 204, 102 }, { 255, 153, 102 }, { 255, 102, 102 },
156   { 255,  51, 102 }, { 255,   0, 102 }, { 255, 255,  51 }, { 255, 204,  51 },
157   { 255, 153,  51 }, { 255, 102,  51 }, { 255,  51,  51 }, { 255,   0,  51 },
158   { 255, 255,   0 }, { 255, 204,   0 }, { 255, 153,   0 }, { 255, 102,   0 },
159   { 255,  51,   0 }, { 255,   0,   0 }, { 204, 255, 102 }, { 204, 204, 102 },
160   { 204, 153, 102 }, { 204, 102, 102 }, { 204,  51, 102 }, { 204,   0, 102 },
161   { 204, 255,  51 }, { 204, 204,  51 }, { 204, 153,  51 }, { 204, 102,  51 },
162   { 204,  51,  51 }, { 204,   0,  51 }, { 204, 255,   0 }, { 204, 204,   0 },
163   { 204, 153,   0 }, { 204, 102,   0 }, { 204,  51,   0 }, { 204,   0,   0 },
164   { 153, 255, 102 }, { 153, 204, 102 }, { 153, 153, 102 }, { 153, 102, 102 },
165   { 153,  51, 102 }, { 153,   0, 102 }, { 153, 255,  51 }, { 153, 204,  51 },
166   { 153, 153,  51 }, { 153, 102,  51 }, { 153,  51,  51 }, { 153,   0,  51 },
167   { 153, 255,   0 }, { 153, 204,   0 }, { 153, 153,   0 }, { 153, 102,   0 },
168   { 153,  51,   0 }, { 153,   0,   0 }, { 102, 255, 102 }, { 102, 204, 102 },
169   { 102, 153, 102 }, { 102, 102, 102 }, { 102,  51, 102 }, { 102,   0, 102 },
170   { 102, 255,  51 }, { 102, 204,  51 }, { 102, 153,  51 }, { 102, 102,  51 },
171   { 102,  51,  51 }, { 102,   0,  51 }, { 102, 255,   0 }, { 102, 204,   0 },
172   { 102, 153,   0 }, { 102, 102,   0 }, { 102,  51,   0 }, { 102,   0,   0 },
173   {  51, 255, 102 }, {  51, 204, 102 }, {  51, 153, 102 }, {  51, 102, 102 },
174   {  51,  51, 102 }, {  51,   0, 102 }, {  51, 255,  51 }, {  51, 204,  51 },
175   {  51, 153,  51 }, {  51, 102,  51 }, {  51,  51,  51 }, {  51,   0,  51 },
176   {  51, 255,   0 }, {  51, 204,   0 }, {  51, 153,   0 }, {  51, 102,   0 },
177   {  51,  51,   0 }, {  51,   0,   0 }, {   0, 255, 102 }, {   0, 204, 102 },
178   {   0, 153, 102 }, {   0, 102, 102 }, {   0,  51, 102 }, {   0,   0, 102 },
179   {   0, 255,  51 }, {   0, 204,  51 }, {   0, 153,  51 }, {   0, 102,  51 },
180   {   0,  51,  51 }, {   0,   0,  51 }, {   0, 255,   0 }, {   0, 204,   0 },
181   {   0, 153,   0 }, {   0, 102,   0 }, {   0,  51,   0 }, {  17,  17,  17 },
182   {  34,  34,  34 }, {  68,  68,  68 }, {  85,  85,  85 }, { 119, 119, 119 },
183   { 136, 136, 136 }, { 170, 170, 170 }, { 187, 187, 187 }, { 221, 221, 221 },
184   { 238, 238, 238 }, { 192, 192, 192 }, { 128,   0,   0 }, { 128,   0, 128 },
185   {   0, 128,   0 }, {   0, 128, 128 }, {   0,   0,   0 }, {   0,   0,   0 },
186   {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 },
187   {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 },
188   {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 },
189   {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 },
190   {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 },
191   {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 }
192 };
193 
194 
195 
196 Colormap *
palmcolor_build_default_8bit_colormap(void)197 palmcolor_build_default_8bit_colormap(void) {
198 
199     unsigned int i;
200 
201     Colormap * cmP;
202 
203     MALLOCVAR_NOFAIL(cmP);
204     cmP->nentries = 232;
205     MALLOCARRAY_NOFAIL(cmP->color_entries, cmP->nentries);
206 
207     /* Fill in the colors */
208     for (i = 0; i < 231; ++i) {
209         cmP->color_entries[i] = ((i << 24) |
210                                 (PalmPalette8bpp[i][0] << 16) |
211                                 (PalmPalette8bpp[i][1] << 8) |
212                                 (PalmPalette8bpp[i][2]));
213     }
214     cmP->color_entries[231] = 0xFF000000;
215     cmP->ncolors = 232;
216 
217     /* now sort the table */
218     qsort(cmP->color_entries, cmP->ncolors, sizeof(ColormapEntry),
219           palmcolor_compare_colors);
220     return cmP;
221 }
222 
223 
224 
225 Colormap *
palmcolor_build_custom_8bit_colormap(pixel ** const pixels,unsigned int const rows,unsigned int const cols,pixval const maxval)226 palmcolor_build_custom_8bit_colormap(pixel **     const pixels,
227                                      unsigned int const rows,
228                                      unsigned int const cols,
229                                      pixval       const maxval) {
230 
231     unsigned int row;
232     Colormap * colormapP;
233 
234     MALLOCVAR_NOFAIL(colormapP);
235     colormapP->nentries = 256;
236     MALLOCARRAY_NOFAIL(colormapP->color_entries, colormapP->nentries);
237     colormapP->ncolors = 0;  /* initial value */
238 
239     for (row = 0; row < rows; ++row) {
240         unsigned int col;
241         for (col = 0; col < cols; ++col) {
242             ColormapEntry * foundEntryP;
243             ColormapEntry const searchTarget =
244                 palmcolor_mapEntryColorFmPixel(pixels[row][col], maxval, 255);
245 
246             foundEntryP =
247                 bsearch(&searchTarget,
248                         colormapP->color_entries, colormapP->ncolors,
249                         sizeof(ColormapEntry), palmcolor_compare_colors);
250             if (!foundEntryP) {
251                 if (colormapP->ncolors >= colormapP->nentries)
252                     pm_error("Too many colors for custom colormap "
253                              "(max %u).  "
254                              "Try using pnmquant to reduce the number "
255                              "of colors.", colormapP->nentries);
256                 else {
257                     /* add the new color, and re-sort */
258                     unsigned int const colorIndex = colormapP->ncolors++;
259                     ColormapEntry const newEntry =
260                         searchTarget | (colorIndex << 24);
261                     colormapP->color_entries[colorIndex] = newEntry;
262                     qsort(colormapP->color_entries, colormapP->ncolors,
263                           sizeof(ColormapEntry), palmcolor_compare_colors);
264                 }
265             }
266         }
267     }
268     return colormapP;
269 }
270 
271 
272 
273 Colormap *
palmcolor_read_colormap(FILE * const ifP)274 palmcolor_read_colormap (FILE * const ifP) {
275 
276     unsigned short ncolors;
277     Colormap * retval;
278     int rc;
279 
280     rc = pm_readbigshort(ifP, (short *) &ncolors);
281     if (rc != 0)
282         retval = NULL;
283     else {
284         long colorentry;
285         Colormap * colormapP;
286         unsigned int i;
287         bool error;
288 
289         MALLOCVAR_NOFAIL(colormapP);
290         colormapP->nentries = ncolors;
291         MALLOCARRAY_NOFAIL(colormapP->color_entries, colormapP->nentries);
292 
293         for (i = 0, error = FALSE;  i < ncolors && !error;  ++i) {
294             int rc;
295             rc = pm_readbiglong(ifP, &colorentry);
296             if (rc != 0)
297                 error = TRUE;
298             else
299                 colormapP->color_entries[i] = (colorentry & 0xFFFFFFFF);
300         }
301         if (error) {
302             free (colormapP->color_entries);
303             free (colormapP);
304             retval = NULL;
305         } else {
306             colormapP->ncolors = ncolors;
307             retval = colormapP;
308         }
309     }
310     return retval;
311 }
312