0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
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
0032 #define LINUX_LOGO_VGA16 2
0033 #define LINUX_LOGO_CLUT224 3
0034 #define LINUX_LOGO_GRAY256 4
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
0089 do {
0090 c = fgetc(fp);
0091 if (c == EOF)
0092 die("%s: end of file\n", filename);
0093 if (c == '#') {
0094
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
0104 val = 0;
0105 while (isdigit(c)) {
0106 val = 10*val+c-'0';
0107
0108
0109
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
0133 fp = fopen(filename, "r");
0134 if (!fp)
0135 die("Cannot open file %s: %s\n", filename, strerror(errno));
0136
0137
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
0147 break;
0148
0149 case '4':
0150 case '5':
0151 case '6':
0152
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
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
0173 switch (magic) {
0174 case '1':
0175
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
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
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
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
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
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
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
0295 write_header();
0296
0297
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
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
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
0329 write_header();
0330
0331
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
0348 write_footer();
0349 }
0350
0351 static void write_logo_clut224(void)
0352 {
0353 unsigned int i, j, k;
0354
0355
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
0371 write_header();
0372
0373
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
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
0394 write_footer();
0395 }
0396
0397 static void write_logo_gray256(void)
0398 {
0399 unsigned int i, j;
0400
0401
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
0408 write_header();
0409
0410
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
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 }