Back to home page

LXR

 
 

    


0001 
0002 /*
0003  *  Convert a logo in ASCII PNM format to C source suitable for inclusion in
0004  *  the Linux kernel
0005  *
0006  *  (C) Copyright 2001-2003 by Geert Uytterhoeven <geert@linux-m68k.org>
0007  *
0008  *  --------------------------------------------------------------------------
0009  *
0010  *  This file is subject to the terms and conditions of the GNU General Public
0011  *  License. See the file COPYING in the main directory of the Linux
0012  *  distribution for more details.
0013  */
0014 
0015 #include <ctype.h>
0016 #include <errno.h>
0017 #include <stdarg.h>
0018 #include <stdio.h>
0019 #include <stdlib.h>
0020 #include <string.h>
0021 #include <unistd.h>
0022 
0023 
0024 static const char *programname;
0025 static const char *filename;
0026 static const char *logoname = "linux_logo";
0027 static const char *outputname;
0028 static FILE *out;
0029 
0030 
0031 #define LINUX_LOGO_MONO     1   /* monochrome black/white */
0032 #define LINUX_LOGO_VGA16    2   /* 16 colors VGA text palette */
0033 #define LINUX_LOGO_CLUT224  3   /* 224 colors */
0034 #define LINUX_LOGO_GRAY256  4   /* 256 levels grayscale */
0035 
0036 static const char *logo_types[LINUX_LOGO_GRAY256+1] = {
0037     [LINUX_LOGO_MONO] = "LINUX_LOGO_MONO",
0038     [LINUX_LOGO_VGA16] = "LINUX_LOGO_VGA16",
0039     [LINUX_LOGO_CLUT224] = "LINUX_LOGO_CLUT224",
0040     [LINUX_LOGO_GRAY256] = "LINUX_LOGO_GRAY256"
0041 };
0042 
0043 #define MAX_LINUX_LOGO_COLORS   224
0044 
0045 struct color {
0046     unsigned char red;
0047     unsigned char green;
0048     unsigned char blue;
0049 };
0050 
0051 static const struct color clut_vga16[16] = {
0052     { 0x00, 0x00, 0x00 },
0053     { 0x00, 0x00, 0xaa },
0054     { 0x00, 0xaa, 0x00 },
0055     { 0x00, 0xaa, 0xaa },
0056     { 0xaa, 0x00, 0x00 },
0057     { 0xaa, 0x00, 0xaa },
0058     { 0xaa, 0x55, 0x00 },
0059     { 0xaa, 0xaa, 0xaa },
0060     { 0x55, 0x55, 0x55 },
0061     { 0x55, 0x55, 0xff },
0062     { 0x55, 0xff, 0x55 },
0063     { 0x55, 0xff, 0xff },
0064     { 0xff, 0x55, 0x55 },
0065     { 0xff, 0x55, 0xff },
0066     { 0xff, 0xff, 0x55 },
0067     { 0xff, 0xff, 0xff },
0068 };
0069 
0070 
0071 static int logo_type = LINUX_LOGO_CLUT224;
0072 static unsigned int logo_width;
0073 static unsigned int logo_height;
0074 static struct color **logo_data;
0075 static struct color logo_clut[MAX_LINUX_LOGO_COLORS];
0076 static unsigned int logo_clutsize;
0077 static int is_plain_pbm = 0;
0078 
0079 static void die(const char *fmt, ...)
0080     __attribute__ ((noreturn)) __attribute ((format (printf, 1, 2)));
0081 static void usage(void) __attribute ((noreturn));
0082 
0083 
0084 static unsigned int get_number(FILE *fp)
0085 {
0086     int c, val;
0087 
0088     /* Skip leading whitespace */
0089     do {
0090     c = fgetc(fp);
0091     if (c == EOF)
0092         die("%s: end of file\n", filename);
0093     if (c == '#') {
0094         /* Ignore comments 'till end of line */
0095         do {
0096         c = fgetc(fp);
0097         if (c == EOF)
0098             die("%s: end of file\n", filename);
0099         } while (c != '\n');
0100     }
0101     } while (isspace(c));
0102 
0103     /* Parse decimal number */
0104     val = 0;
0105     while (isdigit(c)) {
0106     val = 10*val+c-'0';
0107     /* some PBM are 'broken'; GiMP for example exports a PBM without space
0108      * between the digits. This is Ok cause we know a PBM can only have a '1'
0109      * or a '0' for the digit. */
0110     if (is_plain_pbm)
0111         break;
0112     c = fgetc(fp);
0113     if (c == EOF)
0114         die("%s: end of file\n", filename);
0115     }
0116     return val;
0117 }
0118 
0119 static unsigned int get_number255(FILE *fp, unsigned int maxval)
0120 {
0121     unsigned int val = get_number(fp);
0122     return (255*val+maxval/2)/maxval;
0123 }
0124 
0125 static void read_image(void)
0126 {
0127     FILE *fp;
0128     unsigned int i, j;
0129     int magic;
0130     unsigned int maxval;
0131 
0132     /* open image file */
0133     fp = fopen(filename, "r");
0134     if (!fp)
0135     die("Cannot open file %s: %s\n", filename, strerror(errno));
0136 
0137     /* check file type and read file header */
0138     magic = fgetc(fp);
0139     if (magic != 'P')
0140     die("%s is not a PNM file\n", filename);
0141     magic = fgetc(fp);
0142     switch (magic) {
0143     case '1':
0144     case '2':
0145     case '3':
0146         /* Plain PBM/PGM/PPM */
0147         break;
0148 
0149     case '4':
0150     case '5':
0151     case '6':
0152         /* Binary PBM/PGM/PPM */
0153         die("%s: Binary PNM is not supported\n"
0154         "Use pnmnoraw(1) to convert it to ASCII PNM\n", filename);
0155 
0156     default:
0157         die("%s is not a PNM file\n", filename);
0158     }
0159     logo_width = get_number(fp);
0160     logo_height = get_number(fp);
0161 
0162     /* allocate image data */
0163     logo_data = (struct color **)malloc(logo_height*sizeof(struct color *));
0164     if (!logo_data)
0165     die("%s\n", strerror(errno));
0166     for (i = 0; i < logo_height; i++) {
0167     logo_data[i] = malloc(logo_width*sizeof(struct color));
0168     if (!logo_data[i])
0169         die("%s\n", strerror(errno));
0170     }
0171 
0172     /* read image data */
0173     switch (magic) {
0174     case '1':
0175         /* Plain PBM */
0176         is_plain_pbm = 1;
0177         for (i = 0; i < logo_height; i++)
0178         for (j = 0; j < logo_width; j++)
0179             logo_data[i][j].red = logo_data[i][j].green =
0180             logo_data[i][j].blue = 255*(1-get_number(fp));
0181         break;
0182 
0183     case '2':
0184         /* Plain PGM */
0185         maxval = get_number(fp);
0186         for (i = 0; i < logo_height; i++)
0187         for (j = 0; j < logo_width; j++)
0188             logo_data[i][j].red = logo_data[i][j].green =
0189             logo_data[i][j].blue = get_number255(fp, maxval);
0190         break;
0191 
0192     case '3':
0193         /* Plain PPM */
0194         maxval = get_number(fp);
0195         for (i = 0; i < logo_height; i++)
0196         for (j = 0; j < logo_width; j++) {
0197             logo_data[i][j].red = get_number255(fp, maxval);
0198             logo_data[i][j].green = get_number255(fp, maxval);
0199             logo_data[i][j].blue = get_number255(fp, maxval);
0200         }
0201         break;
0202     }
0203 
0204     /* close file */
0205     fclose(fp);
0206 }
0207 
0208 static inline int is_black(struct color c)
0209 {
0210     return c.red == 0 && c.green == 0 && c.blue == 0;
0211 }
0212 
0213 static inline int is_white(struct color c)
0214 {
0215     return c.red == 255 && c.green == 255 && c.blue == 255;
0216 }
0217 
0218 static inline int is_gray(struct color c)
0219 {
0220     return c.red == c.green && c.red == c.blue;
0221 }
0222 
0223 static inline int is_equal(struct color c1, struct color c2)
0224 {
0225     return c1.red == c2.red && c1.green == c2.green && c1.blue == c2.blue;
0226 }
0227 
0228 static void write_header(void)
0229 {
0230     /* open logo file */
0231     if (outputname) {
0232     out = fopen(outputname, "w");
0233     if (!out)
0234         die("Cannot create file %s: %s\n", outputname, strerror(errno));
0235     } else {
0236     out = stdout;
0237     }
0238 
0239     fputs("/*\n", out);
0240     fputs(" *  DO NOT EDIT THIS FILE!\n", out);
0241     fputs(" *\n", out);
0242     fprintf(out, " *  It was automatically generated from %s\n", filename);
0243     fputs(" *\n", out);
0244     fprintf(out, " *  Linux logo %s\n", logoname);
0245     fputs(" */\n\n", out);
0246     fputs("#include <linux/linux_logo.h>\n\n", out);
0247     fprintf(out, "static unsigned char %s_data[] __initdata = {\n",
0248         logoname);
0249 }
0250 
0251 static void write_footer(void)
0252 {
0253     fputs("\n};\n\n", out);
0254     fprintf(out, "const struct linux_logo %s __initconst = {\n", logoname);
0255     fprintf(out, "\t.type\t\t= %s,\n", logo_types[logo_type]);
0256     fprintf(out, "\t.width\t\t= %d,\n", logo_width);
0257     fprintf(out, "\t.height\t\t= %d,\n", logo_height);
0258     if (logo_type == LINUX_LOGO_CLUT224) {
0259     fprintf(out, "\t.clutsize\t= %d,\n", logo_clutsize);
0260     fprintf(out, "\t.clut\t\t= %s_clut,\n", logoname);
0261     }
0262     fprintf(out, "\t.data\t\t= %s_data\n", logoname);
0263     fputs("};\n\n", out);
0264 
0265     /* close logo file */
0266     if (outputname)
0267     fclose(out);
0268 }
0269 
0270 static int write_hex_cnt;
0271 
0272 static void write_hex(unsigned char byte)
0273 {
0274     if (write_hex_cnt % 12)
0275     fprintf(out, ", 0x%02x", byte);
0276     else if (write_hex_cnt)
0277     fprintf(out, ",\n\t0x%02x", byte);
0278     else
0279     fprintf(out, "\t0x%02x", byte);
0280     write_hex_cnt++;
0281 }
0282 
0283 static void write_logo_mono(void)
0284 {
0285     unsigned int i, j;
0286     unsigned char val, bit;
0287 
0288     /* validate image */
0289     for (i = 0; i < logo_height; i++)
0290     for (j = 0; j < logo_width; j++)
0291         if (!is_black(logo_data[i][j]) && !is_white(logo_data[i][j]))
0292         die("Image must be monochrome\n");
0293 
0294     /* write file header */
0295     write_header();
0296 
0297     /* write logo data */
0298     for (i = 0; i < logo_height; i++) {
0299     for (j = 0; j < logo_width;) {
0300         for (val = 0, bit = 0x80; bit && j < logo_width; j++, bit >>= 1)
0301         if (logo_data[i][j].red)
0302             val |= bit;
0303         write_hex(val);
0304     }
0305     }
0306 
0307     /* write logo structure and file footer */
0308     write_footer();
0309 }
0310 
0311 static void write_logo_vga16(void)
0312 {
0313     unsigned int i, j, k;
0314     unsigned char val;
0315 
0316     /* validate image */
0317     for (i = 0; i < logo_height; i++)
0318     for (j = 0; j < logo_width; j++) {
0319         for (k = 0; k < 16; k++)
0320         if (is_equal(logo_data[i][j], clut_vga16[k]))
0321             break;
0322         if (k == 16)
0323         die("Image must use the 16 console colors only\n"
0324             "Use ppmquant(1) -map clut_vga16.ppm to reduce the number "
0325             "of colors\n");
0326     }
0327 
0328     /* write file header */
0329     write_header();
0330 
0331     /* write logo data */
0332     for (i = 0; i < logo_height; i++)
0333     for (j = 0; j < logo_width; j++) {
0334         for (k = 0; k < 16; k++)
0335         if (is_equal(logo_data[i][j], clut_vga16[k]))
0336             break;
0337         val = k<<4;
0338         if (++j < logo_width) {
0339         for (k = 0; k < 16; k++)
0340             if (is_equal(logo_data[i][j], clut_vga16[k]))
0341             break;
0342         val |= k;
0343         }
0344         write_hex(val);
0345     }
0346 
0347     /* write logo structure and file footer */
0348     write_footer();
0349 }
0350 
0351 static void write_logo_clut224(void)
0352 {
0353     unsigned int i, j, k;
0354 
0355     /* validate image */
0356     for (i = 0; i < logo_height; i++)
0357     for (j = 0; j < logo_width; j++) {
0358         for (k = 0; k < logo_clutsize; k++)
0359         if (is_equal(logo_data[i][j], logo_clut[k]))
0360             break;
0361         if (k == logo_clutsize) {
0362         if (logo_clutsize == MAX_LINUX_LOGO_COLORS)
0363             die("Image has more than %d colors\n"
0364             "Use ppmquant(1) to reduce the number of colors\n",
0365             MAX_LINUX_LOGO_COLORS);
0366         logo_clut[logo_clutsize++] = logo_data[i][j];
0367         }
0368     }
0369 
0370     /* write file header */
0371     write_header();
0372 
0373     /* write logo data */
0374     for (i = 0; i < logo_height; i++)
0375     for (j = 0; j < logo_width; j++) {
0376         for (k = 0; k < logo_clutsize; k++)
0377         if (is_equal(logo_data[i][j], logo_clut[k]))
0378             break;
0379         write_hex(k+32);
0380     }
0381     fputs("\n};\n\n", out);
0382 
0383     /* write logo clut */
0384     fprintf(out, "static unsigned char %s_clut[] __initdata = {\n",
0385         logoname);
0386     write_hex_cnt = 0;
0387     for (i = 0; i < logo_clutsize; i++) {
0388     write_hex(logo_clut[i].red);
0389     write_hex(logo_clut[i].green);
0390     write_hex(logo_clut[i].blue);
0391     }
0392 
0393     /* write logo structure and file footer */
0394     write_footer();
0395 }
0396 
0397 static void write_logo_gray256(void)
0398 {
0399     unsigned int i, j;
0400 
0401     /* validate image */
0402     for (i = 0; i < logo_height; i++)
0403     for (j = 0; j < logo_width; j++)
0404         if (!is_gray(logo_data[i][j]))
0405         die("Image must be grayscale\n");
0406 
0407     /* write file header */
0408     write_header();
0409 
0410     /* write logo data */
0411     for (i = 0; i < logo_height; i++)
0412     for (j = 0; j < logo_width; j++)
0413         write_hex(logo_data[i][j].red);
0414 
0415     /* write logo structure and file footer */
0416     write_footer();
0417 }
0418 
0419 static void die(const char *fmt, ...)
0420 {
0421     va_list ap;
0422 
0423     va_start(ap, fmt);
0424     vfprintf(stderr, fmt, ap);
0425     va_end(ap);
0426 
0427     exit(1);
0428 }
0429 
0430 static void usage(void)
0431 {
0432     die("\n"
0433     "Usage: %s [options] <filename>\n"
0434     "\n"
0435     "Valid options:\n"
0436     "    -h          : display this usage information\n"
0437     "    -n <name>   : specify logo name (default: linux_logo)\n"
0438     "    -o <output> : output to file <output> instead of stdout\n"
0439     "    -t <type>   : specify logo type, one of\n"
0440     "                      mono    : monochrome black/white\n"
0441     "                      vga16   : 16 colors VGA text palette\n"
0442     "                      clut224 : 224 colors (default)\n"
0443     "                      gray256 : 256 levels grayscale\n"
0444     "\n", programname);
0445 }
0446 
0447 int main(int argc, char *argv[])
0448 {
0449     int opt;
0450 
0451     programname = argv[0];
0452 
0453     opterr = 0;
0454     while (1) {
0455     opt = getopt(argc, argv, "hn:o:t:");
0456     if (opt == -1)
0457         break;
0458 
0459     switch (opt) {
0460         case 'h':
0461         usage();
0462         break;
0463 
0464         case 'n':
0465         logoname = optarg;
0466         break;
0467 
0468         case 'o':
0469         outputname = optarg;
0470         break;
0471 
0472         case 't':
0473         if (!strcmp(optarg, "mono"))
0474             logo_type = LINUX_LOGO_MONO;
0475         else if (!strcmp(optarg, "vga16"))
0476             logo_type = LINUX_LOGO_VGA16;
0477         else if (!strcmp(optarg, "clut224"))
0478             logo_type = LINUX_LOGO_CLUT224;
0479         else if (!strcmp(optarg, "gray256"))
0480             logo_type = LINUX_LOGO_GRAY256;
0481         else
0482             usage();
0483         break;
0484 
0485         default:
0486         usage();
0487         break;
0488     }
0489     }
0490     if (optind != argc-1)
0491     usage();
0492 
0493     filename = argv[optind];
0494 
0495     read_image();
0496     switch (logo_type) {
0497     case LINUX_LOGO_MONO:
0498         write_logo_mono();
0499         break;
0500 
0501     case LINUX_LOGO_VGA16:
0502         write_logo_vga16();
0503         break;
0504 
0505     case LINUX_LOGO_CLUT224:
0506         write_logo_clut224();
0507         break;
0508 
0509     case LINUX_LOGO_GRAY256:
0510         write_logo_gray256();
0511         break;
0512     }
0513     exit(0);
0514 }