The usual stuff ...
[linux-2.6/linux-mips.git] / scripts / pnmtologo.c
blob8964097b3c7da7e654bb398ec00942331b9656a3
2 /*
3 * Convert a logo in ASCII PNM format to C source suitable for inclusion in
4 * the Linux kernel
6 * (C) Copyright 2001-2003 by Geert Uytterhoeven <geert@linux-m68k.org>
8 * --------------------------------------------------------------------------
10 * This file is subject to the terms and conditions of the GNU General Public
11 * License. See the file COPYING in the main directory of the Linux
12 * distribution for more details.
15 #include <ctype.h>
16 #include <errno.h>
17 #include <stdarg.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
24 static const char *programname;
25 static const char *filename;
26 static const char *logoname = "linux_logo";
27 static const char *outputname;
28 static FILE *out;
31 #define LINUX_LOGO_MONO 1 /* monochrome black/white */
32 #define LINUX_LOGO_VGA16 2 /* 16 colors VGA text palette */
33 #define LINUX_LOGO_CLUT224 3 /* 224 colors */
34 #define LINUX_LOGO_GRAY256 4 /* 256 levels grayscale */
36 static const char *logo_types[LINUX_LOGO_GRAY256+1] = {
37 [LINUX_LOGO_MONO] = "LINUX_LOGO_MONO",
38 [LINUX_LOGO_VGA16] = "LINUX_LOGO_VGA16",
39 [LINUX_LOGO_CLUT224] = "LINUX_LOGO_CLUT224",
40 [LINUX_LOGO_GRAY256] = "LINUX_LOGO_GRAY256"
43 #define MAX_LINUX_LOGO_COLORS 224
45 struct color {
46 unsigned char red;
47 unsigned char green;
48 unsigned char blue;
51 static const struct color clut_vga16[16] = {
52 { 0x00, 0x00, 0x00 },
53 { 0x00, 0x00, 0xaa },
54 { 0x00, 0xaa, 0x00 },
55 { 0x00, 0xaa, 0xaa },
56 { 0xaa, 0x00, 0x00 },
57 { 0xaa, 0x00, 0xaa },
58 { 0xaa, 0x55, 0x00 },
59 { 0xaa, 0xaa, 0xaa },
60 { 0x55, 0x55, 0x55 },
61 { 0x55, 0x55, 0xff },
62 { 0x55, 0xff, 0x55 },
63 { 0x55, 0xff, 0xff },
64 { 0xff, 0x55, 0x55 },
65 { 0xff, 0x55, 0xff },
66 { 0xff, 0xff, 0x55 },
67 { 0xff, 0xff, 0xff },
71 static int logo_type = LINUX_LOGO_CLUT224;
72 static unsigned int logo_width;
73 static unsigned int logo_height;
74 static struct color **logo_data;
75 static struct color logo_clut[MAX_LINUX_LOGO_COLORS];
76 static unsigned int logo_clutsize = 0;
78 static void die(const char *fmt, ...)
79 __attribute__ ((noreturn)) __attribute ((format (printf, 1, 2)));
80 static void usage(void) __attribute ((noreturn));
83 static unsigned int get_number(FILE *fp)
85 int c, val;
87 /* Skip leading whitespace */
88 do {
89 c = fgetc(fp);
90 if (c == EOF)
91 die("%s: end of file\n", filename);
92 if (c == '#') {
93 /* Ignore comments 'till end of line */
94 do {
95 c = fgetc(fp);
96 if (c == EOF)
97 die("%s: end of file\n", filename);
98 } while (c != '\n');
100 } while (isspace(c));
102 /* Parse decimal number */
103 val = 0;
104 while (isdigit(c)) {
105 val = 10*val+c-'0';
106 c = fgetc(fp);
107 if (c == EOF)
108 die("%s: end of file\n", filename);
110 return val;
113 static unsigned int get_number255(FILE *fp, unsigned int maxval)
115 unsigned int val = get_number(fp);
116 return (255*val+maxval/2)/maxval;
119 static void read_image(void)
121 FILE *fp;
122 int i, j, magic;
123 unsigned int maxval;
125 /* open image file */
126 fp = fopen(filename, "r");
127 if (!fp)
128 die("Cannot open file %s: %s\n", filename, strerror(errno));
130 /* check file type and read file header */
131 magic = fgetc(fp);
132 if (magic != 'P')
133 die("%s is not a PNM file\n", filename);
134 magic = fgetc(fp);
135 switch (magic) {
136 case '1':
137 case '2':
138 case '3':
139 /* Plain PBM/PGM/PPM */
140 break;
142 case '4':
143 case '5':
144 case '6':
145 /* Binary PBM/PGM/PPM */
146 die("%s: Binary PNM is not supported\n"
147 "Use pnmnoraw(1) to convert it to ASCII PNM\n", filename);
149 default:
150 die("%s is not a PNM file\n", filename);
152 logo_width = get_number(fp);
153 logo_height = get_number(fp);
155 /* allocate image data */
156 logo_data = (struct color **)malloc(logo_height*sizeof(struct color *));
157 if (!logo_data)
158 die("%s\n", strerror(errno));
159 for (i = 0; i < logo_height; i++) {
160 logo_data[i] = malloc(logo_width*sizeof(struct color));
161 if (!logo_data[i])
162 die("%s\n", strerror(errno));
165 /* read image data */
166 switch (magic) {
167 case '1':
168 /* Plain PBM */
169 for (i = 0; i < logo_height; i++)
170 for (j = 0; j < logo_width; j++)
171 logo_data[i][j].red = logo_data[i][j].green =
172 logo_data[i][j].blue = 255*(1-get_number(fp));
173 break;
175 case '2':
176 /* Plain PGM */
177 maxval = get_number(fp);
178 for (i = 0; i < logo_height; i++)
179 for (j = 0; j < logo_width; j++)
180 logo_data[i][j].red = logo_data[i][j].green =
181 logo_data[i][j].blue = get_number255(fp, maxval);
182 break;
184 case '3':
185 /* Plain PPM */
186 maxval = get_number(fp);
187 for (i = 0; i < logo_height; i++)
188 for (j = 0; j < logo_width; j++) {
189 logo_data[i][j].red = get_number255(fp, maxval);
190 logo_data[i][j].green = get_number255(fp, maxval);
191 logo_data[i][j].blue = get_number255(fp, maxval);
193 break;
196 /* close file */
197 fclose(fp);
200 static inline int is_black(struct color c)
202 return c.red == 0 && c.green == 0 && c.blue == 0;
205 static inline int is_white(struct color c)
207 return c.red == 255 && c.green == 255 && c.blue == 255;
210 static inline int is_gray(struct color c)
212 return c.red == c.green && c.red == c.blue;
215 static inline int is_equal(struct color c1, struct color c2)
217 return c1.red == c2.red && c1.green == c2.green && c1.blue == c2.blue;
220 static void write_header(void)
222 /* open logo file */
223 if (outputname) {
224 out = fopen(outputname, "w");
225 if (!out)
226 die("Cannot create file %s: %s\n", outputname, strerror(errno));
227 } else {
228 out = stdout;
231 fputs("/*\n", out);
232 fputs(" * DO NOT EDIT THIS FILE!\n", out);
233 fputs(" *\n", out);
234 fprintf(out, " * It was automatically generated from %s\n", filename);
235 fputs(" *\n", out);
236 fprintf(out, " * Linux logo %s\n", logoname);
237 fputs(" */\n\n", out);
238 fputs("#include <linux/linux_logo.h>\n\n", out);
239 fprintf(out, "static const unsigned char %s_data[] __initdata = {\n",
240 logoname);
243 static void write_footer(void)
245 fputs("\n};\n\n", out);
246 fprintf(out, "const struct linux_logo %s __initdata = {\n", logoname);
247 fprintf(out, " .type\t= %s,\n", logo_types[logo_type]);
248 fprintf(out, " .width\t= %d,\n", logo_width);
249 fprintf(out, " .height\t= %d,\n", logo_height);
250 if (logo_type == LINUX_LOGO_CLUT224) {
251 fprintf(out, " .clutsize\t= %d,\n", logo_clutsize);
252 fprintf(out, " .clut\t= %s_clut,\n", logoname);
254 fprintf(out, " .data\t= %s_data\n", logoname);
255 fputs("};\n\n", out);
257 /* close logo file */
258 if (outputname)
259 fclose(out);
262 static int write_hex_cnt = 0;
264 static void write_hex(unsigned char byte)
266 if (write_hex_cnt % 12)
267 fprintf(out, ", 0x%02x", byte);
268 else if (write_hex_cnt)
269 fprintf(out, ",\n\t0x%02x", byte);
270 else
271 fprintf(out, "\t0x%02x", byte);
272 write_hex_cnt++;
275 static void write_logo_mono(void)
277 int i, j;
278 unsigned char val, bit;
280 /* validate image */
281 for (i = 0; i < logo_height; i++)
282 for (j = 0; j < logo_width; j++)
283 if (!is_black(logo_data[i][j]) && !is_white(logo_data[i][j]))
284 die("Image must be monochrome\n");
286 /* write file header */
287 write_header();
289 /* write logo data */
290 for (i = 0; i < logo_height; i++) {
291 for (j = 0; j < logo_width;) {
292 for (val = 0, bit = 0x80; bit && j < logo_width; j++, bit >>= 1)
293 if (logo_data[i][j].red)
294 val |= bit;
295 write_hex(val);
299 /* write logo structure and file footer */
300 write_footer();
303 static void write_logo_vga16(void)
305 int i, j, k;
306 unsigned char val;
308 /* validate image */
309 for (i = 0; i < logo_height; i++)
310 for (j = 0; j < logo_width; j++) {
311 for (k = 0; k < 16; k++)
312 if (is_equal(logo_data[i][j], clut_vga16[k]))
313 break;
314 if (k == 16)
315 die("Image must use the 16 console colors only\n"
316 "Use ppmquant(1) -map clut_vga16.ppm to reduce the number "
317 "of colors\n");
320 /* write file header */
321 write_header();
323 /* write logo data */
324 for (i = 0; i < logo_height; i++)
325 for (j = 0; j < logo_width; j++) {
326 for (k = 0; k < 16; k++)
327 if (is_equal(logo_data[i][j], clut_vga16[k]))
328 break;
329 val = k<<4;
330 if (++j < logo_width) {
331 for (k = 0; k < 16; k++)
332 if (is_equal(logo_data[i][j], clut_vga16[k]))
333 break;
334 val |= k;
336 write_hex(val);
339 /* write logo structure and file footer */
340 write_footer();
343 static void write_logo_clut224(void)
345 int i, j, k;
347 /* validate image */
348 for (i = 0; i < logo_height; i++)
349 for (j = 0; j < logo_width; j++) {
350 for (k = 0; k < logo_clutsize; k++)
351 if (is_equal(logo_data[i][j], logo_clut[k]))
352 break;
353 if (k == logo_clutsize) {
354 if (logo_clutsize == MAX_LINUX_LOGO_COLORS)
355 die("Image has more than %d colors\n"
356 "Use ppmquant(1) to reduce the number of colors\n",
357 MAX_LINUX_LOGO_COLORS);
358 logo_clut[logo_clutsize++] = logo_data[i][j];
362 /* write file header */
363 write_header();
365 /* write logo data */
366 for (i = 0; i < logo_height; i++)
367 for (j = 0; j < logo_width; j++) {
368 for (k = 0; k < logo_clutsize; k++)
369 if (is_equal(logo_data[i][j], logo_clut[k]))
370 break;
371 write_hex(k+32);
373 fputs("\n};\n\n", out);
375 /* write logo clut */
376 fprintf(out, "static const unsigned char %s_clut[] __initdata = {\n",
377 logoname);
378 write_hex_cnt = 0;
379 for (i = 0; i < logo_clutsize; i++) {
380 write_hex(logo_clut[i].red);
381 write_hex(logo_clut[i].green);
382 write_hex(logo_clut[i].blue);
385 /* write logo structure and file footer */
386 write_footer();
389 static void write_logo_gray256(void)
391 int i, j;
393 /* validate image */
394 for (i = 0; i < logo_height; i++)
395 for (j = 0; j < logo_width; j++)
396 if (!is_gray(logo_data[i][j]))
397 die("Image must be grayscale\n");
399 /* write file header */
400 write_header();
402 /* write logo data */
403 for (i = 0; i < logo_height; i++)
404 for (j = 0; j < logo_width; j++)
405 write_hex(logo_data[i][j].red);
407 /* write logo structure and file footer */
408 write_footer();
411 static void die(const char *fmt, ...)
413 va_list ap;
415 va_start(ap, fmt);
416 vfprintf(stderr, fmt, ap);
417 va_end(ap);
419 exit(1);
422 static void usage(void)
424 die("\n"
425 "Usage: %s [options] <filename>\n"
426 "\n"
427 "Valid options:\n"
428 " -h : display this usage information\n"
429 " -n <name> : specify logo name (default: linux_logo)\n"
430 " -o <output> : output to file <output> instead of stdout\n"
431 " -t <type> : specify logo type, one of\n"
432 " mono : monochrome black/white\n"
433 " vga16 : 16 colors VGA text palette\n"
434 " clut224 : 224 colors (default)\n"
435 " gray256 : 256 levels grayscale\n"
436 "\n", programname);
439 int main(int argc, char *argv[])
441 int opt;
443 programname = argv[0];
445 opterr = 0;
446 while (1) {
447 opt = getopt(argc, argv, "hn:o:t:");
448 if (opt == -1)
449 break;
451 switch (opt) {
452 case 'h':
453 usage();
454 break;
456 case 'n':
457 logoname = optarg;
458 break;
460 case 'o':
461 outputname = optarg;
462 break;
464 case 't':
465 if (!strcmp(optarg, "mono"))
466 logo_type = LINUX_LOGO_MONO;
467 else if (!strcmp(optarg, "vga16"))
468 logo_type = LINUX_LOGO_VGA16;
469 else if (!strcmp(optarg, "clut224"))
470 logo_type = LINUX_LOGO_CLUT224;
471 else if (!strcmp(optarg, "gray256"))
472 logo_type = LINUX_LOGO_GRAY256;
473 else
474 usage();
475 break;
477 default:
478 usage();
479 break;
482 if (optind != argc-1)
483 usage();
485 filename = argv[optind];
487 read_image();
488 switch (logo_type) {
489 case LINUX_LOGO_MONO:
490 write_logo_mono();
491 break;
493 case LINUX_LOGO_VGA16:
494 write_logo_vga16();
495 break;
497 case LINUX_LOGO_CLUT224:
498 write_logo_clut224();
499 break;
501 case LINUX_LOGO_GRAY256:
502 write_logo_gray256();
503 break;
505 exit(0);