Merge remote-tracking branch 'kernel-2.6.32/develop' into develop-2.6.36
[firefly-linux-kernel-4.4.55.git] / scripts / pnmtologo.c
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 #define LINUX_LOGO_MONO         1       /* monochrome black/white */
31 #define LINUX_LOGO_VGA16        2       /* 16 colors VGA text palette */
32 #define LINUX_LOGO_CLUT224      3       /* 224 colors */
33 #define LINUX_LOGO_GRAY256      4       /* 256 levels grayscale */
34
35 static const char *logo_types[LINUX_LOGO_GRAY256+1] = {
36     [LINUX_LOGO_MONO] = "LINUX_LOGO_MONO",
37     [LINUX_LOGO_VGA16] = "LINUX_LOGO_VGA16",
38     [LINUX_LOGO_CLUT224] = "LINUX_LOGO_CLUT224",
39     [LINUX_LOGO_GRAY256] = "LINUX_LOGO_GRAY256"
40 };
41
42 #define MAX_LINUX_LOGO_COLORS   224
43 #define MAX_LINUX_LOGO_WIDTH  1280
44 #define MAX_LINUX_LOGO_HEIGHT 800
45
46 struct color {
47     unsigned char red;
48     unsigned char green;
49     unsigned char blue;
50 };
51
52 static const struct color clut_vga16[16] = {
53     { 0x00, 0x00, 0x00 },
54     { 0x00, 0x00, 0xaa },
55     { 0x00, 0xaa, 0x00 },
56     { 0x00, 0xaa, 0xaa },
57     { 0xaa, 0x00, 0x00 },
58     { 0xaa, 0x00, 0xaa },
59     { 0xaa, 0x55, 0x00 },
60     { 0xaa, 0xaa, 0xaa },
61     { 0x55, 0x55, 0x55 },
62     { 0x55, 0x55, 0xff },
63     { 0x55, 0xff, 0x55 },
64     { 0x55, 0xff, 0xff },
65     { 0xff, 0x55, 0x55 },
66     { 0xff, 0x55, 0xff },
67     { 0xff, 0xff, 0x55 },
68     { 0xff, 0xff, 0xff },
69 };
70
71 unsigned char data_name[] = {
72         0x6C, 0x6F, 0x67,
73         0x6F, 0x5F, 0x52,
74         0x4B, 0x6C, 0x6F,
75         0x67, 0x6F, 0x5F,
76         0x64, 0x61, 0x74,
77         0x61
78 };
79
80 unsigned char clut_name[] = {
81         0x6C, 0x6F, 0x67,
82         0x6F, 0x5F, 0x52,
83         0x4B, 0x6C, 0x6F,
84         0x67, 0x6F, 0x5F,
85         0x63, 0x6C, 0x75,
86         0x74
87 };
88
89 static int logo_type = LINUX_LOGO_CLUT224;
90 static unsigned int logo_width;
91 static unsigned int logo_height;
92 static struct color **logo_data;
93 static struct color logo_clut[MAX_LINUX_LOGO_COLORS];
94 static unsigned int logo_clutsize;
95
96 static void die(const char *fmt, ...)
97     __attribute__ ((noreturn)) __attribute ((format (printf, 1, 2)));
98 static void usage(void) __attribute ((noreturn));
99
100 static unsigned int get_number(FILE *fp)
101 {
102     int c, val;
103
104     /* Skip leading whitespace */
105     do {
106         c = fgetc(fp);
107         if (c == EOF)
108             die("%s: end of file\n", filename);
109         if (c == '#') {
110             /* Ignore comments 'till end of line */
111             do {
112                 c = fgetc(fp);
113                 if (c == EOF)
114                     die("%s: end of file\n", filename);
115             } while (c != '\n');
116         }
117     } while (isspace(c));
118
119     /* Parse decimal number */
120     val = 0;
121     while (isdigit(c)) {
122         val = 10*val+c-'0';
123         c = fgetc(fp);
124         if (c == EOF)
125             die("%s: end of file\n", filename);
126     }
127     return val;
128 }
129
130 static unsigned int get_number255(FILE *fp, unsigned int maxval)
131 {
132     unsigned int val = get_number(fp);
133     return (255*val+maxval/2)/maxval;
134 }
135
136 static void read_image(void)
137 {
138         FILE *fp;
139         unsigned int i, j;
140         int magic;
141         unsigned int maxval;
142
143         /* open image file */
144         fp = fopen(filename, "r");
145         if (!fp)
146                 die("Cannot open file %s: %s\n", filename, strerror(errno));
147
148     /* check file type and read file header */
149     magic = fgetc(fp);
150     if (magic != 'P')
151         die("%s is not a PNM file\n", filename);
152     magic = fgetc(fp);
153     switch (magic) {
154         case '1':
155         case '2':
156         case '3':
157             /* Plain PBM/PGM/PPM */
158             break;
159
160         case '4':
161         case '5':
162         case '6':
163             /* Binary PBM/PGM/PPM */
164             die("%s: Binary PNM is not supported\n"
165                 "Use pnmnoraw(1) to convert it to ASCII PNM\n", filename);
166
167         default:
168             die("%s is not a PNM file\n", filename);
169     }
170         logo_width = get_number(fp);
171         logo_height = get_number(fp);
172
173
174         /* allocate image data */
175         logo_data = (struct color **)malloc(logo_height * sizeof(struct color *));
176         if (!logo_data)
177                 die("%s\n", strerror(errno));
178         for (i = 0; i < logo_height; i++) {
179                 logo_data[i] = (struct color *)malloc(logo_width * sizeof(struct color));
180                 if (!logo_data[i])
181                 die("%s\n", strerror(errno));
182         }
183
184     /* read image data */
185     switch (magic) {
186         case '1':
187             /* Plain PBM */
188             for (i = 0; i < logo_height; i++)
189                 for (j = 0; j < logo_width; j++)
190                     logo_data[i][j].red = logo_data[i][j].green =
191                         logo_data[i][j].blue = 255*(1-get_number(fp));
192             break;
193
194         case '2':
195             /* Plain PGM */
196             maxval = get_number(fp);
197             for (i = 0; i < logo_height; i++)
198                 for (j = 0; j < logo_width; j++)
199                     logo_data[i][j].red = logo_data[i][j].green =
200                         logo_data[i][j].blue = get_number255(fp, maxval);
201             break;
202
203         case '3':
204             /* Plain PPM */
205             maxval = get_number(fp);
206             for (i = 0; i < logo_height; i++)
207                 for (j = 0; j < logo_width; j++) {
208                     logo_data[i][j].red = get_number255(fp, maxval);
209                     logo_data[i][j].green = get_number255(fp, maxval);
210                     logo_data[i][j].blue = get_number255(fp, maxval);
211                 }
212             break;
213     }
214
215     /* close file */
216     fclose(fp);
217 }
218
219 static inline int is_black(struct color c)
220 {
221     return c.red == 0 && c.green == 0 && c.blue == 0;
222 }
223
224 static inline int is_white(struct color c)
225 {
226     return c.red == 255 && c.green == 255 && c.blue == 255;
227 }
228
229 static inline int is_gray(struct color c)
230 {
231     return c.red == c.green && c.red == c.blue;
232 }
233
234 static inline int is_equal(struct color c1, struct color c2)
235 {
236     return c1.red == c2.red && c1.green == c2.green && c1.blue == c2.blue;
237 }
238
239 static int write_hex_cnt;
240
241 static void write_hex(unsigned char byte)
242 {
243     if (write_hex_cnt % 12)
244         fprintf(out, ", 0x%02x", byte);
245     else if (write_hex_cnt)
246         fprintf(out, ",\n\t0x%02x", byte);
247     else
248         fprintf(out, "\t0x%02x", byte);
249     write_hex_cnt++;
250 }
251
252 static void write_header(void)
253 {
254         /* open logo file */
255         if (outputname) {
256                 out = fopen(outputname, "w");
257                 if (!out)
258                         die("Cannot create file %s: %s\n", outputname, strerror(errno));
259         } else {
260                 out = stdout;
261         }
262
263         fputs("/*\n", out);
264         fputs(" *  DO NOT EDIT THIS FILE!\n", out);
265         fputs(" *\n", out);
266         fprintf(out, " *  It was automatically generated from %s\n", filename);
267         fputs(" *\n", out);
268         fprintf(out, " *  Linux logo %s\n", logoname);
269         fputs(" */\n\n", out);
270         fputs("#include <linux/linux_logo.h>\n\n", out);
271         fprintf(out, "static unsigned char %s_data[] __initdata = {\n",
272                 logoname);
273 }
274
275 static void write_footer(void)
276 {
277         fputs("\n};\n\n", out);
278         fprintf(out, "const struct linux_logo %s __initconst = {\n", logoname);
279         fprintf(out, "\t.type\t\t= %s,\n", logo_types[logo_type]);
280
281         if (logo_type == LINUX_LOGO_CLUT224) {
282                 fprintf(out, "\t.clut\t\t= &(%s_clut[%ld]),\n", logoname, sizeof(clut_name));
283                 fprintf(out, "\t.data\t\t= &(%s_data[%ld])\n", logoname, sizeof(data_name));
284         } else {
285                 fprintf(out, "\t.width\t\t= %d,\n", logo_width);
286                 fprintf(out, "\t.height\t\t= %d,\n", logo_height);
287                 if (logo_type == LINUX_LOGO_CLUT224) {
288                         fprintf(out, "\t.clutsize\t= %d,\n", logo_clutsize);
289                         fprintf(out, "\t.clut\t\t= %s_clut,\n", logoname);
290                 }
291                 fprintf(out, "\t.data\t\t= %s_data\n", logoname);
292         }
293
294         fputs("};\n\n", out);
295
296         /* close logo file */
297         if (outputname)
298                 fclose(out);
299 }
300
301 static void write_logo_mono(void)
302 {
303     unsigned int i, j;
304     unsigned char val, bit;
305
306     /* validate image */
307     for (i = 0; i < logo_height; i++)
308         for (j = 0; j < logo_width; j++)
309             if (!is_black(logo_data[i][j]) && !is_white(logo_data[i][j]))
310                 die("Image must be monochrome\n");
311
312     /* write file header */
313     write_header();
314
315     /* write logo data */
316     for (i = 0; i < logo_height; i++) {
317         for (j = 0; j < logo_width;) {
318             for (val = 0, bit = 0x80; bit && j < logo_width; j++, bit >>= 1)
319                 if (logo_data[i][j].red)
320                     val |= bit;
321             write_hex(val);
322         }
323     }
324
325
326     /* write logo structure and file footer */
327     write_footer();
328 }
329
330 static void write_logo_vga16(void)
331 {
332     unsigned int i, j, k;
333     unsigned char val;
334
335     /* validate image */
336     for (i = 0; i < logo_height; i++)
337         for (j = 0; j < logo_width; j++) {
338             for (k = 0; k < 16; k++)
339                 if (is_equal(logo_data[i][j], clut_vga16[k]))
340                     break;
341             if (k == 16)
342                 die("Image must use the 16 console colors only\n"
343                     "Use ppmquant(1) -map clut_vga16.ppm to reduce the number "
344                     "of colors\n");
345         }
346
347     /* write file header */
348     write_header();
349
350     /* write logo data */
351     for (i = 0; i < logo_height; i++)
352         for (j = 0; j < logo_width; j++) {
353             for (k = 0; k < 16; k++)
354                 if (is_equal(logo_data[i][j], clut_vga16[k]))
355                     break;
356             val = k<<4;
357             if (++j < logo_width) {
358                 for (k = 0; k < 16; k++)
359                     if (is_equal(logo_data[i][j], clut_vga16[k]))
360                         break;
361                 val |= k;
362             }
363             write_hex(val);
364         }
365
366     /* write logo structure and file footer */
367     write_footer();
368 }
369
370 static void write_logo_clut224(void)
371 {
372         unsigned int i, j, k;
373
374         logo_clutsize = 0;
375
376         /* validate image */
377         for (i = 0; i < logo_height; i++)
378                 for (j = 0; j < logo_width; j++) {
379                         for (k = 0; k < logo_clutsize; k++)
380                                 if (is_equal(logo_data[i][j], logo_clut[k]))
381                                         break;
382                         if (k == logo_clutsize) {
383                                 if (logo_clutsize == MAX_LINUX_LOGO_COLORS)
384                                         die("Image has more than %d colors\n"
385                                                 "Use ppmquant(1) to reduce the number of colors\n",
386                                                 MAX_LINUX_LOGO_COLORS);
387                                         logo_clut[logo_clutsize++] = logo_data[i][j];
388                         }
389                 }
390
391         write_hex_cnt = 0;
392
393         /* write file header */
394         write_header();
395
396         for (i = 0; i < sizeof(data_name); i++){
397                 write_hex(data_name[i]);
398         }
399         write_hex((unsigned char)(logo_width >> 8));
400         write_hex((unsigned char)logo_width);
401         write_hex((unsigned char)(logo_height >> 8));
402         write_hex((unsigned char)logo_height);
403
404         /* write logo data */
405         for (i = 0; i < logo_height; i++)
406                 for (j = 0; j < logo_width; j++) {
407                         for (k = 0; k < logo_clutsize; k++)
408                                 if (is_equal(logo_data[i][j], logo_clut[k]))
409                                         break;
410                         write_hex(k+32);
411                 }
412
413         if (logo_height < MAX_LINUX_LOGO_HEIGHT ||  logo_width < MAX_LINUX_LOGO_WIDTH) {
414                 if (logo_height == MAX_LINUX_LOGO_HEIGHT) {
415                         for (i = 0; i < MAX_LINUX_LOGO_HEIGHT; i++)
416                                 for (j = logo_width; j < MAX_LINUX_LOGO_WIDTH; j++)
417                                         write_hex(32);
418                 } else if (logo_width == MAX_LINUX_LOGO_WIDTH) {
419                         for (i = logo_height; i < MAX_LINUX_LOGO_HEIGHT; i++)
420                                 for (j = 0; j < MAX_LINUX_LOGO_WIDTH; j++)
421                                         write_hex(32);
422                 } else {
423                         for (i = logo_height; i < MAX_LINUX_LOGO_HEIGHT; i++)
424                                 for (j = 0; j < MAX_LINUX_LOGO_WIDTH; j++)
425                                         write_hex(32);
426
427                         for (i = 0; i < logo_height; i++)
428                                 for (j = logo_width; j < MAX_LINUX_LOGO_WIDTH; j++)
429                                         write_hex(32);
430                 }
431         }
432
433         fputs("\n};\n\n", out);
434
435         /* write logo clut */
436         fprintf(out, "static unsigned char %s_clut[] __initdata = {\n",
437                 logoname);
438
439         write_hex_cnt = 0;
440
441         for (i = 0; i < sizeof(clut_name); i++){
442                 write_hex(clut_name[i]);
443         }
444         write_hex(logo_clutsize);
445
446         for (i = 0; i < logo_clutsize; i++) {
447                 write_hex(logo_clut[i].red);
448                 write_hex(logo_clut[i].green);
449                 write_hex(logo_clut[i].blue);
450         }
451
452         /* write logo structure and file footer */
453         write_footer();
454 }
455
456 static void write_logo_gray256(void)
457 {
458     unsigned int i, j;
459
460     /* validate image */
461     for (i = 0; i < logo_height; i++)
462         for (j = 0; j < logo_width; j++)
463             if (!is_gray(logo_data[i][j]))
464                 die("Image must be grayscale\n");
465
466     /* write file header */
467     write_header();
468
469     /* write logo data */
470     for (i = 0; i < logo_height; i++)
471         for (j = 0; j < logo_width; j++)
472             write_hex(logo_data[i][j].red);
473
474     /* write logo structure and file footer */
475     write_footer();
476 }
477
478 static void die(const char *fmt, ...)
479 {
480     va_list ap;
481
482     va_start(ap, fmt);
483     vfprintf(stderr, fmt, ap);
484     va_end(ap);
485
486     exit(1);
487 }
488
489 static void usage(void)
490 {
491     die("\n"
492         "Usage: %s [options] <filename>\n"
493         "\n"
494         "Valid options:\n"
495         "    -h          : display this usage information\n"
496         "    -n <name>   : specify logo name (default: linux_logo)\n"
497         "    -o <output> : output to file <output> instead of stdout\n"
498         "    -t <type>   : specify logo type, one of\n"
499         "                      mono    : monochrome black/white\n"
500         "                      vga16   : 16 colors VGA text palette\n"
501         "                      clut224 : 224 colors (default)\n"
502         "                      gray256 : 256 levels grayscale\n"
503         "\n", programname);
504 }
505
506 int main(int argc, char *argv[])
507 {
508     int opt;
509
510     programname = argv[0];
511
512     opterr = 0;
513     while (1) {
514         opt = getopt(argc, argv, "hn:o:t:");
515         if (opt == -1)
516             break;
517
518         switch (opt) {
519             case 'h':
520                 usage();
521                 break;
522
523             case 'n':
524                 logoname = optarg;
525                 break;
526
527             case 'o':
528                 outputname = optarg;
529                 break;
530
531             case 't':
532                 if (!strcmp(optarg, "mono"))
533                     logo_type = LINUX_LOGO_MONO;
534                 else if (!strcmp(optarg, "vga16"))
535                     logo_type = LINUX_LOGO_VGA16;
536                 else if (!strcmp(optarg, "clut224"))
537                     logo_type = LINUX_LOGO_CLUT224;
538                 else if (!strcmp(optarg, "gray256"))
539                     logo_type = LINUX_LOGO_GRAY256;
540                 else
541                     usage();
542                 break;
543
544             default:
545                 usage();
546                 break;
547         }
548     }
549     if (optind != argc-1)
550         usage();
551
552     filename = argv[optind];
553
554     read_image();
555     switch (logo_type) {
556         case LINUX_LOGO_MONO:
557             write_logo_mono();
558             break;
559
560         case LINUX_LOGO_VGA16:
561             write_logo_vga16();
562             break;
563
564         case LINUX_LOGO_CLUT224:
565             write_logo_clut224();
566             break;
567
568         case LINUX_LOGO_GRAY256:
569             write_logo_gray256();
570             break;
571     }
572     exit(0);
573 }
574