Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pnmtologo.c
Go to the documentation of this file.
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 <[email protected]>
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, "const struct linux_logo %s __initconst = {\n", logoname);
248  fprintf(out, "\t.type\t\t= %s,\n", logo_types[logo_type]);
249  fprintf(out, "\t.width\t\t= %d,\n", logo_width);
250  fprintf(out, "\t.height\t\t= %d,\n", logo_height);
251  if (logo_type == LINUX_LOGO_CLUT224) {
252  fprintf(out, "\t.clutsize\t= %d,\n", logo_clutsize);
253  fprintf(out, "\t.clut\t\t= %s_clut,\n", logoname);
254  }
255  fprintf(out, "\t.data\t\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",
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