1
2 /*
3 * Diverse Bristol audio routines.
4 * Copyright (c) by Nick Copeland <nickycopeland@hotmail.com> 1996,2012
5 *
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <unistd.h>
26 #include <sys/types.h>
27 #include <sys/wait.h>
28
29 #include "brightoninternals.h"
30
31 static int hex2num(char);
32 static int xpmchar2num(brightonBitmap *,char);
33 static int convertindex(brightonBitmap *, char *, int);
34 static int convertcolor(char *);
35
36 extern void brightonSprintColor(brightonWindow *, char *, int);
37
38 #define BUFSIZE 8192
39
40 #define CTAB_SIZE 2048
41
42 /*
43 * In the next peice of code we are calling brightonfopen(), brightonfgets()
44 * and brightonfclose(), these are empty stubs that would get removed at
45 * -O3 or so however I have used them at times for debugging heap corruption
46 * and the overhead is minimal and only affects startup, not runtime.
47 */
48 brightonBitmap *
xpmread(brightonWindow * bwin,char * filename)49 xpmread(brightonWindow *bwin, char *filename)
50 {
51 int color, width = 0, height = 0, colors = 0, bpcolor = 0, i = 1, j;
52 int innerstatic = -1, outerstatic = -1;
53 FILE *fd;
54 char line[BUFSIZE];
55 int *colormap;
56 brightonBitmap *bitmap;
57
58 /*
59 * This code was added to allow using compressed images reducing the size
60 * of the installation to about 1/5th. It spools the gz to /tmp if the xpm
61 * is not found and gunzips.
62 */
63 if ((fd = brightonfopen(filename, "r")) == (FILE *) NULL)
64 {
65 int status;
66 char tfn[256];;
67 pid_t child;
68 char *params[10];
69
70 sprintf(line, "%s.gz", filename);
71 sprintf(tfn, "/tmp/bbm_%i.xpm.gz", getpid());
72
73 if ((fd = brightonfopen(line, "r")) == (FILE *) NULL)
74 return(NULL);
75
76 brightonfclose(fd);
77
78 if ((child = fork()) == 0)
79 {
80 params[0] = "cp";
81 params[1] = "-f";
82 params[2] = line;
83 params[3] = tfn;
84 params[4] = NULL;
85 if ((child = execvp("cp", params)) < 0) {
86 printf("\nCannot spool the compressed source bitmap\n\n");
87 }
88 exit(1);
89 } else
90 waitpid(child, &status, 0);
91
92 if (status) {
93 printf("Error copying %s to %s: %i\n", line, tfn, status);
94 exit(1);
95 }
96
97 if ((child = fork()) == 0)
98 {
99 params[0] = "gunzip";
100 params[1] = "-f";
101 params[2] = tfn;
102 params[3] = NULL;
103 if ((child = execvp("gunzip", params)) < 0) {
104 printf("\nCannot finding the gunzip binary, install it or ");
105 printf("email author for an\nalternative resolution\n\n");
106 }
107 exit(1);
108 } else
109 waitpid(child, &status, 0);
110
111 if (status)
112 exit(1);
113
114 unlink(tfn); /* unlink the zipped file - on error may exist */
115 sprintf(tfn, "/tmp/bbm_%i.xpm", getpid());
116
117 if ((fd = brightonfopen(tfn, "r")) == (FILE *) NULL)
118 {
119 unlink(tfn);
120 return(NULL);
121 }
122
123 unlink(tfn);
124 }
125
126 /* printf("xpmread(\"%s\")\n", filename); */
127
128 while ((brightonfgets(line, BUFSIZE, fd)) != 0)
129 {
130 /*
131 * We are looking for numbers:
132 */
133 if (!isdigit(line[1]))
134 continue;
135 else {
136 /*
137 * Should be able to get width, height, colors and planes from this
138 * line of text.
139 */
140 while (isdigit(line[i]))
141 width = width * 10 + line[i++] - '0';
142 if (line[i++] != ' ')
143 {
144 brightonfclose(fd);
145 return(0);
146 }
147
148 while (isdigit(line[i]))
149 height = height * 10 + line[i++] - '0';
150 if (line[i++] != ' ')
151 {
152 brightonfclose(fd);
153 return(0);
154 }
155
156 while (isdigit(line[i]))
157 colors = colors * 10 + line[i++] - '0';
158 if (line[i++] != ' ')
159 {
160 brightonfclose(fd);
161 return(0);
162 }
163
164 while (isdigit(line[i]))
165 bpcolor = bpcolor * 10 + line[i++] - '0';
166
167 if (line[i] != '"')
168 {
169 while (line[i] == ' ')
170 i++;
171 innerstatic = 0;
172
173 while (isdigit(line[i]))
174 innerstatic = innerstatic * 10 + line[i++] - '0';
175
176 if (line[i] != '"')
177 {
178 while (line[i] == ' ')
179 i++;
180 outerstatic = 0;
181
182 while (isdigit(line[i]))
183 outerstatic = outerstatic * 10 + line[i++] - '0';
184 }
185
186 if (line[i] != '"')
187 {
188 brightonfclose(fd);
189 return(0);
190 }
191 }
192
193 break;
194 }
195 }
196
197 bitmap = brightonCreateBitmap(bwin, width, height);
198
199 if (bitmap->pixels == NULL)
200 bitmap->pixels = (int *) brightonmalloc((2 + width) * (2 + height)
201 * sizeof(int));
202 bitmap->width = width;
203 bitmap->height = height;
204 bitmap->ncolors = colors;
205 bitmap->ctabsize = colors;
206 bitmap->uses = 0;
207
208 bitmap->istatic = innerstatic;
209 bitmap->ostatic = width > height? height / 2: width /2;
210 if (outerstatic != -1)
211 {
212 if (width > height) {
213 if (outerstatic < (height / 2))
214 bitmap->ostatic = outerstatic;
215 } else {
216 if (outerstatic < (width / 2))
217 bitmap->ostatic = outerstatic;
218 }
219 }
220
221 colormap = (int *) brightonmalloc(colors * sizeof(int));
222 if (bitmap->colormap)
223 brightonfree(bitmap->colormap);
224 bitmap->colormap = colormap;
225
226 /*
227 * We now have some reasonable w, h, c and p. Need to parse c color lines.
228 * We have to build a table of the character indeces from the XPM file. To
229 * do this we need a character table and index. Rather than define them in
230 * this file I am going to re-use some parts of the bitmap structure.
231 */
232 bitmap->name = brightonmalloc(CTAB_SIZE * sizeof(char));
233
234 for (i = 0; i < colors;i++)
235 {
236 short r, g, b;
237
238 if (brightonfgets(line, BUFSIZE, fd) == 0)
239 {
240 brightonfclose(fd);
241 printf("e1: %s\n", filename);
242 return(bitmap);
243 }
244
245 if (((line[bpcolor + 1] != '\t') && (line[bpcolor + 1] != ' ')) ||
246 ((line[bpcolor + 2] != 'c') && (line[bpcolor + 2] != 'g')))
247 {
248 brightonfclose(fd);
249 printf("e2: %s: %i %i, %s\n", filename, bpcolor, colors, line);
250 return(bitmap);
251 }
252
253 if (strncmp("None", &line[4 + bpcolor], 4) == 0)
254 {
255 color = convertindex(bitmap, &line[1], bpcolor);
256 colormap[i] = brightonGetGCByName(bwin, "Blue");
257 continue;
258 }
259
260 /*
261 * We need to make a new convertindex that builds its own index table
262 * based on the characters in the xpm file.
263 */
264 color = convertindex(bitmap, &line[1], bpcolor);
265
266 if ((color = convertcolor(&line[bpcolor + 4])) < 0)
267 {
268 line[strlen(line) - 3] = '\0';
269 colormap[i] = brightonGetGCByName(bwin, &line[bpcolor + 4]);
270 } else {
271
272 /*
273 * Call the color manager to get a GC with this color for eventual
274 * rendering.
275 *
276 * XPM has color from 0 to 255. getGC wants 16 bit values.
277 */
278 r = (color >> 16) * 256;
279 g = ((color >> 8) & 0xff) * 256;
280 b = (color & 0x00ff) * 256;
281
282 /*
283 * Brighton color manager is going to find this color, and return
284 * it if found, return a new GC if there is space, or a best match
285 * if not.
286 */
287 colormap[i] = brightonGetGC(bwin, r, g, b);
288 }
289 }
290
291 for (i = 0; i < height;i++)
292 {
293 if (brightonfgets(line, BUFSIZE, fd) == 0)
294 {
295 brightonfclose(fd);
296 printf("e3: %s\n", filename);
297 return(bitmap);
298 }
299 if (line[0] != '\"')
300 continue;
301 for (j = 0; j < width * bpcolor; j+=bpcolor)
302 {
303 color = convertindex(bitmap, &line[j + 1], bpcolor);
304 if (color < 0)
305 {
306 brightonfclose(fd);
307 printf("e4: %s, %i/%i\n", filename, color, colors);
308 return(bitmap);
309 } else if (color >= colors) {
310 // printf("e5: %s, %i/%i\n", filename, color, colors);
311 bitmap->pixels[i * width + j / bpcolor] = colormap[colors - 1];
312 } else {
313 bitmap->pixels[i * width + j / bpcolor] = colormap[color];
314 }
315 }
316 }
317
318 /* Free this temporary holder */
319 brightonfree(bitmap->name);
320
321 bitmap->name = (char *) brightonmalloc(strlen(filename) + 1);
322 sprintf(bitmap->name, "%s", filename);
323
324 /* bitmap->colormap = colormap; */
325
326 bitmap->uses = 1;
327
328 brightonfclose(fd);
329
330 return(bitmap);
331 }
332
333 static int
hex2num(char c)334 hex2num(char c)
335 {
336 if (isxdigit(c))
337 {
338 switch (c) {
339 case '0':
340 case '1':
341 case '2':
342 case '3':
343 case '4':
344 case '5':
345 case '6':
346 case '7':
347 case '8':
348 case '9':
349 return(c - '0');
350 case 'a':
351 case 'b':
352 case 'c':
353 case 'd':
354 case 'e':
355 case 'f':
356 return(c - 'a' + 10);
357 default:
358 return(c - 'A' + 10);
359 }
360 }
361 return(-1);
362 }
363
364 static int
convertcolor(char * line)365 convertcolor(char *line)
366 {
367 int i = 0, color = 0, digit;
368
369 if (strcmp(line, "none") == 0)
370 return(0);
371 else if (strcmp(line, "None") == 0)
372 return(0);
373
374 if (line[0] != '#')
375 return(-1);
376
377 line++;
378
379 while (line[i] != '"')
380 {
381 if ((digit = hex2num(line[i])) < 0)
382 return(0);
383
384 color = color * 16 + digit;
385 i++;
386 }
387
388 return(color);
389 }
390
391 static int
convertindex(brightonBitmap * bitmap,char * line,int bpc)392 convertindex(brightonBitmap *bitmap, char *line, int bpc)
393 {
394 int cindex = 0, i = 0, j = 1;
395
396 while (i < bpc)
397 {
398 cindex = cindex + xpmchar2num(bitmap, line[i]) * j;
399 j += 91;
400 i++;
401 }
402
403 return(cindex);
404 }
405
406 int
xpmchar2num(brightonBitmap * bitmap,char c)407 xpmchar2num(brightonBitmap *bitmap, char c)
408 {
409 int i;
410
411 for (i = 0; i < bitmap->uses; i++)
412 if (c == bitmap->name[i])
413 return(i);
414
415 /*printf("", bitmap->uses, i); */
416 /*
417 * If we got here then the character has not been assigned yet.
418 */
419 bitmap->name[bitmap->uses] = (int) c;
420 bitmap->uses++;
421
422 return(i);
423 }
424
425 int
writeLine(int fd,char * line)426 writeLine(int fd, char *line)
427 {
428 return(write(fd, line, strlen(line)));
429 }
430
431 #define SAVE_IMAGE
432 #ifdef SAVE_IMAGE
433
434 #include <sys/types.h>
435 #include <sys/stat.h>
436 #include <fcntl.h>
437
438 int
brightonXpmWrite(brightonWindow * bwin,char * file)439 brightonXpmWrite(brightonWindow *bwin, char *file)
440 {
441 int fd, x, y, color, lindex;
442 int colors[4096], cindex = 0, ccnt = 0, coff = 0, cagg = 0;
443 long *points;
444 char *line;
445 char cstring[16], filename[64];
446
447 sprintf(filename, "/tmp/%s.xpm", bwin->template->name);
448
449 if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0770)) < 0)
450 return(0);
451
452 points = brightonmalloc(sizeof(long) * bwin->width * bwin->height);
453 line = brightonmalloc(sizeof(char) * (bwin->width + 10) * 2);
454
455 writeLine(fd, "/* XPM */\n");
456 writeLine(fd, "static char * brighton_xpm[] = {\n");
457
458 /*
459 * We need to scan the image to see how many colors it implements. From this
460 * we should build a character table, and then we should scan through the
461 * image printing these characters.
462 */
463 for (y = 0; y < bwin->render->height; y++)
464 {
465 for (x = 0; x < bwin->render->width; x++)
466 {
467 color = bwin->render->pixels[x + y * bwin->render->width];
468
469 for (cindex = 0; cindex < ccnt; cindex++)
470 {
471 if (color == colors[cindex])
472 {
473 /*
474 * This can't work: points[x][y] = cindex; hence
475 */
476 points[x + y * bwin->render->width] = cindex;
477 break;
478 }
479 }
480 if (cindex == ccnt)
481 {
482 colors[cindex] = color;
483 ccnt++;
484 }
485 /*
486 * This can't work: points[x][y] = cindex; hence
487 */
488 points[x + y * bwin->render->width] = cindex;
489 }
490 }
491
492 sprintf(line, "\"%i %i %i %i\",\n", bwin->width, bwin->height, ccnt, 2);
493 writeLine(fd, line);
494
495 for (cindex = 0; cindex < ccnt; cindex++)
496 {
497 /*
498 * We have to be reasonably intelligent with the color indeces. The
499 * first attempt failed when we went over about 80 colors. The index
500 * needs to become a string. We could go for two digits immediately?
501 */
502 brightonSprintColor(bwin, cstring, colors[cindex]);
503 sprintf(line, "\"%c%c c %s\",\n", coff + 35, cagg + 35, cstring);
504
505 if (++cagg >= 90)
506 {
507 cagg = 0;
508 coff++;
509 }
510
511 writeLine(fd, line);
512 }
513
514 for (y = 0; y < bwin->height; y++)
515 {
516 lindex = 1;
517 sprintf(line, "\"");
518
519 for (x = 0; x < bwin->width; x++)
520 {
521 cagg = points[x + y * bwin->render->width] % 90;
522 coff = points[x + y * bwin->render->width] / 90;
523 sprintf(&line[lindex], "%c%c", coff + 35, cagg + 35);
524 lindex+=2;
525 }
526
527 sprintf(&line[lindex], "\"\n");
528 writeLine(fd, line);
529 }
530
531 writeLine(fd, "};\n\n");
532
533 brightonfree(points);
534 brightonfree(line);
535
536 close(fd);
537
538 printf("Image written to %s, %i colors\n", filename, ccnt);
539 printf("Width %i, Height %i\n", bwin->width, bwin->height);
540
541 return(0);
542 }
543 #endif /* SAVE_IMAGE */
544
545