diff options
Diffstat (limited to 'scripts/pnmtologo.c')
-rw-r--r-- | scripts/pnmtologo.c | 508 |
1 files changed, 508 insertions, 0 deletions
diff --git a/scripts/pnmtologo.c b/scripts/pnmtologo.c new file mode 100644 index 000000000000..6aa2a2483f8d --- /dev/null +++ b/scripts/pnmtologo.c | |||
@@ -0,0 +1,508 @@ | |||
1 | |||
2 | /* | ||
3 | * Convert a logo in ASCII PNM format to C source suitable for inclusion in | ||
4 | * the Linux kernel | ||
5 | * | ||
6 | * (C) Copyright 2001-2003 by Geert Uytterhoeven <geert@linux-m68k.org> | ||
7 | * | ||
8 | * -------------------------------------------------------------------------- | ||
9 | * | ||
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. | ||
13 | */ | ||
14 | |||
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> | ||
22 | |||
23 | |||
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; | ||
29 | |||
30 | |||
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 */ | ||
35 | |||
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" | ||
41 | }; | ||
42 | |||
43 | #define MAX_LINUX_LOGO_COLORS 224 | ||
44 | |||
45 | struct color { | ||
46 | unsigned char red; | ||
47 | unsigned char green; | ||
48 | unsigned char blue; | ||
49 | }; | ||
50 | |||
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 }, | ||
68 | }; | ||
69 | |||
70 | |||
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; | ||
77 | |||
78 | static void die(const char *fmt, ...) | ||
79 | __attribute__ ((noreturn)) __attribute ((format (printf, 1, 2))); | ||
80 | static void usage(void) __attribute ((noreturn)); | ||
81 | |||
82 | |||
83 | static unsigned int get_number(FILE *fp) | ||
84 | { | ||
85 | int c, val; | ||
86 | |||
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'); | ||
99 | } | ||
100 | } while (isspace(c)); | ||
101 | |||
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); | ||
109 | } | ||
110 | return val; | ||
111 | } | ||
112 | |||
113 | static unsigned int get_number255(FILE *fp, unsigned int maxval) | ||
114 | { | ||
115 | unsigned int val = get_number(fp); | ||
116 | return (255*val+maxval/2)/maxval; | ||
117 | } | ||
118 | |||
119 | static void read_image(void) | ||
120 | { | ||
121 | FILE *fp; | ||
122 | unsigned int i, j; | ||
123 | int magic; | ||
124 | unsigned int maxval; | ||
125 | |||
126 | /* open image file */ | ||
127 | fp = fopen(filename, "r"); | ||
128 | if (!fp) | ||
129 | die("Cannot open file %s: %s\n", filename, strerror(errno)); | ||
130 | |||
131 | /* check file type and read file header */ | ||
132 | magic = fgetc(fp); | ||
133 | if (magic != 'P') | ||
134 | die("%s is not a PNM file\n", filename); | ||
135 | magic = fgetc(fp); | ||
136 | switch (magic) { | ||
137 | case '1': | ||
138 | case '2': | ||
139 | case '3': | ||
140 | /* Plain PBM/PGM/PPM */ | ||
141 | break; | ||
142 | |||
143 | case '4': | ||
144 | case '5': | ||
145 | case '6': | ||
146 | /* Binary PBM/PGM/PPM */ | ||
147 | die("%s: Binary PNM is not supported\n" | ||
148 | "Use pnmnoraw(1) to convert it to ASCII PNM\n", filename); | ||
149 | |||
150 | default: | ||
151 | die("%s is not a PNM file\n", filename); | ||
152 | } | ||
153 | logo_width = get_number(fp); | ||
154 | logo_height = get_number(fp); | ||
155 | |||
156 | /* allocate image data */ | ||
157 | logo_data = (struct color **)malloc(logo_height*sizeof(struct color *)); | ||
158 | if (!logo_data) | ||
159 | die("%s\n", strerror(errno)); | ||
160 | for (i = 0; i < logo_height; i++) { | ||
161 | logo_data[i] = malloc(logo_width*sizeof(struct color)); | ||
162 | if (!logo_data[i]) | ||
163 | die("%s\n", strerror(errno)); | ||
164 | } | ||
165 | |||
166 | /* read image data */ | ||
167 | switch (magic) { | ||
168 | case '1': | ||
169 | /* Plain PBM */ | ||
170 | for (i = 0; i < logo_height; i++) | ||
171 | for (j = 0; j < logo_width; j++) | ||
172 | logo_data[i][j].red = logo_data[i][j].green = | ||
173 | logo_data[i][j].blue = 255*(1-get_number(fp)); | ||
174 | break; | ||
175 | |||
176 | case '2': | ||
177 | /* Plain PGM */ | ||
178 | maxval = get_number(fp); | ||
179 | for (i = 0; i < logo_height; i++) | ||
180 | for (j = 0; j < logo_width; j++) | ||
181 | logo_data[i][j].red = logo_data[i][j].green = | ||
182 | logo_data[i][j].blue = get_number255(fp, maxval); | ||
183 | break; | ||
184 | |||
185 | case '3': | ||
186 | /* Plain PPM */ | ||
187 | maxval = get_number(fp); | ||
188 | for (i = 0; i < logo_height; i++) | ||
189 | for (j = 0; j < logo_width; j++) { | ||
190 | logo_data[i][j].red = get_number255(fp, maxval); | ||
191 | logo_data[i][j].green = get_number255(fp, maxval); | ||
192 | logo_data[i][j].blue = get_number255(fp, maxval); | ||
193 | } | ||
194 | break; | ||
195 | } | ||
196 | |||
197 | /* close file */ | ||
198 | fclose(fp); | ||
199 | } | ||
200 | |||
201 | static inline int is_black(struct color c) | ||
202 | { | ||
203 | return c.red == 0 && c.green == 0 && c.blue == 0; | ||
204 | } | ||
205 | |||
206 | static inline int is_white(struct color c) | ||
207 | { | ||
208 | return c.red == 255 && c.green == 255 && c.blue == 255; | ||
209 | } | ||
210 | |||
211 | static inline int is_gray(struct color c) | ||
212 | { | ||
213 | return c.red == c.green && c.red == c.blue; | ||
214 | } | ||
215 | |||
216 | static inline int is_equal(struct color c1, struct color c2) | ||
217 | { | ||
218 | return c1.red == c2.red && c1.green == c2.green && c1.blue == c2.blue; | ||
219 | } | ||
220 | |||
221 | static void write_header(void) | ||
222 | { | ||
223 | /* open logo file */ | ||
224 | if (outputname) { | ||
225 | out = fopen(outputname, "w"); | ||
226 | if (!out) | ||
227 | die("Cannot create file %s: %s\n", outputname, strerror(errno)); | ||
228 | } else { | ||
229 | out = stdout; | ||
230 | } | ||
231 | |||
232 | fputs("/*\n", out); | ||
233 | fputs(" * DO NOT EDIT THIS FILE!\n", out); | ||
234 | fputs(" *\n", out); | ||
235 | fprintf(out, " * It was automatically generated from %s\n", filename); | ||
236 | fputs(" *\n", out); | ||
237 | fprintf(out, " * Linux logo %s\n", logoname); | ||
238 | fputs(" */\n\n", out); | ||
239 | fputs("#include <linux/linux_logo.h>\n\n", out); | ||
240 | fprintf(out, "static unsigned char %s_data[] __initdata = {\n", | ||
241 | logoname); | ||
242 | } | ||
243 | |||
244 | static void write_footer(void) | ||
245 | { | ||
246 | fputs("\n};\n\n", out); | ||
247 | fprintf(out, "struct linux_logo %s __initdata = {\n", logoname); | ||
248 | fprintf(out, " .type\t= %s,\n", logo_types[logo_type]); | ||
249 | fprintf(out, " .width\t= %d,\n", logo_width); | ||
250 | fprintf(out, " .height\t= %d,\n", logo_height); | ||
251 | if (logo_type == LINUX_LOGO_CLUT224) { | ||
252 | fprintf(out, " .clutsize\t= %d,\n", logo_clutsize); | ||
253 | fprintf(out, " .clut\t= %s_clut,\n", logoname); | ||
254 | } | ||
255 | fprintf(out, " .data\t= %s_data\n", logoname); | ||
256 | fputs("};\n\n", out); | ||
257 | |||
258 | /* close logo file */ | ||
259 | if (outputname) | ||
260 | fclose(out); | ||
261 | } | ||
262 | |||
263 | static int write_hex_cnt; | ||
264 | |||
265 | static void write_hex(unsigned char byte) | ||
266 | { | ||
267 | if (write_hex_cnt % 12) | ||
268 | fprintf(out, ", 0x%02x", byte); | ||
269 | else if (write_hex_cnt) | ||
270 | fprintf(out, ",\n\t0x%02x", byte); | ||
271 | else | ||
272 | fprintf(out, "\t0x%02x", byte); | ||
273 | write_hex_cnt++; | ||
274 | } | ||
275 | |||
276 | static void write_logo_mono(void) | ||
277 | { | ||
278 | unsigned int i, j; | ||
279 | unsigned char val, bit; | ||
280 | |||
281 | /* validate image */ | ||
282 | for (i = 0; i < logo_height; i++) | ||
283 | for (j = 0; j < logo_width; j++) | ||
284 | if (!is_black(logo_data[i][j]) && !is_white(logo_data[i][j])) | ||
285 | die("Image must be monochrome\n"); | ||
286 | |||
287 | /* write file header */ | ||
288 | write_header(); | ||
289 | |||
290 | /* write logo data */ | ||
291 | for (i = 0; i < logo_height; i++) { | ||
292 | for (j = 0; j < logo_width;) { | ||
293 | for (val = 0, bit = 0x80; bit && j < logo_width; j++, bit >>= 1) | ||
294 | if (logo_data[i][j].red) | ||
295 | val |= bit; | ||
296 | write_hex(val); | ||
297 | } | ||
298 | } | ||
299 | |||
300 | /* write logo structure and file footer */ | ||
301 | write_footer(); | ||
302 | } | ||
303 | |||
304 | static void write_logo_vga16(void) | ||
305 | { | ||
306 | unsigned int i, j, k; | ||
307 | unsigned char val; | ||
308 | |||
309 | /* validate image */ | ||
310 | for (i = 0; i < logo_height; i++) | ||
311 | for (j = 0; j < logo_width; j++) { | ||
312 | for (k = 0; k < 16; k++) | ||
313 | if (is_equal(logo_data[i][j], clut_vga16[k])) | ||
314 | break; | ||
315 | if (k == 16) | ||
316 | die("Image must use the 16 console colors only\n" | ||
317 | "Use ppmquant(1) -map clut_vga16.ppm to reduce the number " | ||
318 | "of colors\n"); | ||
319 | } | ||
320 | |||
321 | /* write file header */ | ||
322 | write_header(); | ||
323 | |||
324 | /* write logo data */ | ||
325 | for (i = 0; i < logo_height; i++) | ||
326 | for (j = 0; j < logo_width; j++) { | ||
327 | for (k = 0; k < 16; k++) | ||
328 | if (is_equal(logo_data[i][j], clut_vga16[k])) | ||
329 | break; | ||
330 | val = k<<4; | ||
331 | if (++j < logo_width) { | ||
332 | for (k = 0; k < 16; k++) | ||
333 | if (is_equal(logo_data[i][j], clut_vga16[k])) | ||
334 | break; | ||
335 | val |= k; | ||
336 | } | ||
337 | write_hex(val); | ||
338 | } | ||
339 | |||
340 | /* write logo structure and file footer */ | ||
341 | write_footer(); | ||
342 | } | ||
343 | |||
344 | static void write_logo_clut224(void) | ||
345 | { | ||
346 | unsigned int i, j, k; | ||
347 | |||
348 | /* validate image */ | ||
349 | for (i = 0; i < logo_height; i++) | ||
350 | for (j = 0; j < logo_width; j++) { | ||
351 | for (k = 0; k < logo_clutsize; k++) | ||
352 | if (is_equal(logo_data[i][j], logo_clut[k])) | ||
353 | break; | ||
354 | if (k == logo_clutsize) { | ||
355 | if (logo_clutsize == MAX_LINUX_LOGO_COLORS) | ||
356 | die("Image has more than %d colors\n" | ||
357 | "Use ppmquant(1) to reduce the number of colors\n", | ||
358 | MAX_LINUX_LOGO_COLORS); | ||
359 | logo_clut[logo_clutsize++] = logo_data[i][j]; | ||
360 | } | ||
361 | } | ||
362 | |||
363 | /* write file header */ | ||
364 | write_header(); | ||
365 | |||
366 | /* write logo data */ | ||
367 | for (i = 0; i < logo_height; i++) | ||
368 | for (j = 0; j < logo_width; j++) { | ||
369 | for (k = 0; k < logo_clutsize; k++) | ||
370 | if (is_equal(logo_data[i][j], logo_clut[k])) | ||
371 | break; | ||
372 | write_hex(k+32); | ||
373 | } | ||
374 | fputs("\n};\n\n", out); | ||
375 | |||
376 | /* write logo clut */ | ||
377 | fprintf(out, "static unsigned char %s_clut[] __initdata = {\n", | ||
378 | logoname); | ||
379 | write_hex_cnt = 0; | ||
380 | for (i = 0; i < logo_clutsize; i++) { | ||
381 | write_hex(logo_clut[i].red); | ||
382 | write_hex(logo_clut[i].green); | ||
383 | write_hex(logo_clut[i].blue); | ||
384 | } | ||
385 | |||
386 | /* write logo structure and file footer */ | ||
387 | write_footer(); | ||
388 | } | ||
389 | |||
390 | static void write_logo_gray256(void) | ||
391 | { | ||
392 | unsigned int i, j; | ||
393 | |||
394 | /* validate image */ | ||
395 | for (i = 0; i < logo_height; i++) | ||
396 | for (j = 0; j < logo_width; j++) | ||
397 | if (!is_gray(logo_data[i][j])) | ||
398 | die("Image must be grayscale\n"); | ||
399 | |||
400 | /* write file header */ | ||
401 | write_header(); | ||
402 | |||
403 | /* write logo data */ | ||
404 | for (i = 0; i < logo_height; i++) | ||
405 | for (j = 0; j < logo_width; j++) | ||
406 | write_hex(logo_data[i][j].red); | ||
407 | |||
408 | /* write logo structure and file footer */ | ||
409 | write_footer(); | ||
410 | } | ||
411 | |||
412 | static void die(const char *fmt, ...) | ||
413 | { | ||
414 | va_list ap; | ||
415 | |||
416 | va_start(ap, fmt); | ||
417 | vfprintf(stderr, fmt, ap); | ||
418 | va_end(ap); | ||
419 | |||
420 | exit(1); | ||
421 | } | ||
422 | |||
423 | static void usage(void) | ||
424 | { | ||
425 | die("\n" | ||
426 | "Usage: %s [options] <filename>\n" | ||
427 | "\n" | ||
428 | "Valid options:\n" | ||
429 | " -h : display this usage information\n" | ||
430 | " -n <name> : specify logo name (default: linux_logo)\n" | ||
431 | " -o <output> : output to file <output> instead of stdout\n" | ||
432 | " -t <type> : specify logo type, one of\n" | ||
433 | " mono : monochrome black/white\n" | ||
434 | " vga16 : 16 colors VGA text palette\n" | ||
435 | " clut224 : 224 colors (default)\n" | ||
436 | " gray256 : 256 levels grayscale\n" | ||
437 | "\n", programname); | ||
438 | } | ||
439 | |||
440 | int main(int argc, char *argv[]) | ||
441 | { | ||
442 | int opt; | ||
443 | |||
444 | programname = argv[0]; | ||
445 | |||
446 | opterr = 0; | ||
447 | while (1) { | ||
448 | opt = getopt(argc, argv, "hn:o:t:"); | ||
449 | if (opt == -1) | ||
450 | break; | ||
451 | |||
452 | switch (opt) { | ||
453 | case 'h': | ||
454 | usage(); | ||
455 | break; | ||
456 | |||
457 | case 'n': | ||
458 | logoname = optarg; | ||
459 | break; | ||
460 | |||
461 | case 'o': | ||
462 | outputname = optarg; | ||
463 | break; | ||
464 | |||
465 | case 't': | ||
466 | if (!strcmp(optarg, "mono")) | ||
467 | logo_type = LINUX_LOGO_MONO; | ||
468 | else if (!strcmp(optarg, "vga16")) | ||
469 | logo_type = LINUX_LOGO_VGA16; | ||
470 | else if (!strcmp(optarg, "clut224")) | ||
471 | logo_type = LINUX_LOGO_CLUT224; | ||
472 | else if (!strcmp(optarg, "gray256")) | ||
473 | logo_type = LINUX_LOGO_GRAY256; | ||
474 | else | ||
475 | usage(); | ||
476 | break; | ||
477 | |||
478 | default: | ||
479 | usage(); | ||
480 | break; | ||
481 | } | ||
482 | } | ||
483 | if (optind != argc-1) | ||
484 | usage(); | ||
485 | |||
486 | filename = argv[optind]; | ||
487 | |||
488 | read_image(); | ||
489 | switch (logo_type) { | ||
490 | case LINUX_LOGO_MONO: | ||
491 | write_logo_mono(); | ||
492 | break; | ||
493 | |||
494 | case LINUX_LOGO_VGA16: | ||
495 | write_logo_vga16(); | ||
496 | break; | ||
497 | |||
498 | case LINUX_LOGO_CLUT224: | ||
499 | write_logo_clut224(); | ||
500 | break; | ||
501 | |||
502 | case LINUX_LOGO_GRAY256: | ||
503 | write_logo_gray256(); | ||
504 | break; | ||
505 | } | ||
506 | exit(0); | ||
507 | } | ||
508 | |||