root/scripts/pnmtologo.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_number
  2. get_number255
  3. read_image
  4. is_black
  5. is_white
  6. is_gray
  7. is_equal
  8. write_header
  9. write_footer
  10. write_hex
  11. write_logo_mono
  12. write_logo_vga16
  13. write_logo_clut224
  14. write_logo_gray256
  15. die
  16. usage
  17. main

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

/* [<][>][^][v][top][bottom][index][help] */