linux/scripts/pnmtologo.c
<<
>>
Prefs
   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
  24static const char *programname;
  25static const char *filename;
  26static const char *logoname = "linux_logo";
  27static const char *outputname;
  28static 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
  36static 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
  45struct color {
  46    unsigned char red;
  47    unsigned char green;
  48    unsigned char blue;
  49};
  50
  51static 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
  71static int logo_type = LINUX_LOGO_CLUT224;
  72static unsigned int logo_width;
  73static unsigned int logo_height;
  74static struct color **logo_data;
  75static struct color logo_clut[MAX_LINUX_LOGO_COLORS];
  76static unsigned int logo_clutsize;
  77
  78static void die(const char *fmt, ...)
  79    __attribute__ ((noreturn)) __attribute ((format (printf, 1, 2)));
  80static void usage(void) __attribute ((noreturn));
  81
  82
  83static 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
 113static 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
 119static 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
 201static inline int is_black(struct color c)
 202{
 203    return c.red == 0 && c.green == 0 && c.blue == 0;
 204}
 205
 206static inline int is_white(struct color c)
 207{
 208    return c.red == 255 && c.green == 255 && c.blue == 255;
 209}
 210
 211static inline int is_gray(struct color c)
 212{
 213    return c.red == c.green && c.red == c.blue;
 214}
 215
 216static 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
 221static 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
 244static void write_footer(void)
 245{
 246    fputs("\n};\n\n", out);
 247    fprintf(out, "struct linux_logo %s __initdata = {\n", logoname);
 248    fprintf(out, "    .type\t= %s,\n", logo_types[logo_type]);
 249    fprintf(out, "    .width\t= %d,\n", logo_width);
 250    fprintf(out, "    .height\t= %d,\n", logo_height);
 251    if (logo_type == LINUX_LOGO_CLUT224) {
 252        fprintf(out, "    .clutsize\t= %d,\n", logo_clutsize);
 253        fprintf(out, "    .clut\t= %s_clut,\n", logoname);
 254    }
 255    fprintf(out, "    .data\t= %s_data\n", logoname);
 256    fputs("};\n\n", out);
 257
 258    /* close logo file */
 259    if (outputname)
 260        fclose(out);
 261}
 262
 263static int write_hex_cnt;
 264
 265static 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
 276static 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
 304static 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
 344static 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",
 358                        MAX_LINUX_LOGO_COLORS);
 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
 390static 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
 412static 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
 423static 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
 440int 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
 509