1 // SPDX-License-Identifier: GPL-2.0-only
3 * Convert a logo in ASCII PNM format to C source suitable for inclusion in
6 * (C) Copyright 2001-2003 by Geert Uytterhoeven <geert@linux-m68k.org>
18 static const char *programname
;
19 static const char *filename
;
20 static const char *logoname
= "linux_logo";
21 static const char *outputname
;
25 #define LINUX_LOGO_MONO 1 /* monochrome black/white */
26 #define LINUX_LOGO_VGA16 2 /* 16 colors VGA text palette */
27 #define LINUX_LOGO_CLUT224 3 /* 224 colors */
28 #define LINUX_LOGO_GRAY256 4 /* 256 levels grayscale */
30 static const char *logo_types
[LINUX_LOGO_GRAY256
+1] = {
31 [LINUX_LOGO_MONO
] = "LINUX_LOGO_MONO",
32 [LINUX_LOGO_VGA16
] = "LINUX_LOGO_VGA16",
33 [LINUX_LOGO_CLUT224
] = "LINUX_LOGO_CLUT224",
34 [LINUX_LOGO_GRAY256
] = "LINUX_LOGO_GRAY256"
37 #define MAX_LINUX_LOGO_COLORS 224
45 static const struct color clut_vga16
[16] = {
65 static int logo_type
= LINUX_LOGO_CLUT224
;
66 static unsigned int logo_width
;
67 static unsigned int logo_height
;
68 static struct color
**logo_data
;
69 static struct color logo_clut
[MAX_LINUX_LOGO_COLORS
];
70 static unsigned int logo_clutsize
;
71 static int is_plain_pbm
= 0;
73 static void die(const char *fmt
, ...)
74 __attribute__((noreturn
)) __attribute((format (printf
, 1, 2)));
75 static void usage(void) __attribute((noreturn
));
78 static unsigned int get_number(FILE *fp
)
82 /* Skip leading whitespace */
86 die("%s: end of file\n", filename
);
88 /* Ignore comments 'till end of line */
92 die("%s: end of file\n", filename
);
97 /* Parse decimal number */
101 /* some PBM are 'broken'; GiMP for example exports a PBM without space
102 * between the digits. This is Ok cause we know a PBM can only have a '1'
103 * or a '0' for the digit.
109 die("%s: end of file\n", filename
);
114 static unsigned int get_number255(FILE *fp
, unsigned int maxval
)
116 unsigned int val
= get_number(fp
);
118 return (255*val
+maxval
/2)/maxval
;
121 static void read_image(void)
128 /* open image file */
129 fp
= fopen(filename
, "r");
131 die("Cannot open file %s: %s\n", filename
, strerror(errno
));
133 /* check file type and read file header */
136 die("%s is not a PNM file\n", filename
);
142 /* Plain PBM/PGM/PPM */
148 /* Binary PBM/PGM/PPM */
149 die("%s: Binary PNM is not supported\n"
150 "Use pnmnoraw(1) to convert it to ASCII PNM\n", filename
);
153 die("%s is not a PNM file\n", filename
);
155 logo_width
= get_number(fp
);
156 logo_height
= get_number(fp
);
158 /* allocate image data */
159 logo_data
= (struct color
**)malloc(logo_height
*sizeof(struct color
*));
161 die("%s\n", strerror(errno
));
162 for (i
= 0; i
< logo_height
; i
++) {
163 logo_data
[i
] = malloc(logo_width
*sizeof(struct color
));
165 die("%s\n", strerror(errno
));
168 /* read image data */
173 for (i
= 0; i
< logo_height
; i
++)
174 for (j
= 0; j
< logo_width
; j
++)
175 logo_data
[i
][j
].red
= logo_data
[i
][j
].green
=
176 logo_data
[i
][j
].blue
= 255*(1-get_number(fp
));
181 maxval
= get_number(fp
);
182 for (i
= 0; i
< logo_height
; i
++)
183 for (j
= 0; j
< logo_width
; j
++)
184 logo_data
[i
][j
].red
= logo_data
[i
][j
].green
=
185 logo_data
[i
][j
].blue
= get_number255(fp
, maxval
);
190 maxval
= get_number(fp
);
191 for (i
= 0; i
< logo_height
; i
++)
192 for (j
= 0; j
< logo_width
; j
++) {
193 logo_data
[i
][j
].red
= get_number255(fp
, maxval
);
194 logo_data
[i
][j
].green
= get_number255(fp
, maxval
);
195 logo_data
[i
][j
].blue
= get_number255(fp
, maxval
);
204 static inline int is_black(struct color c
)
206 return c
.red
== 0 && c
.green
== 0 && c
.blue
== 0;
209 static inline int is_white(struct color c
)
211 return c
.red
== 255 && c
.green
== 255 && c
.blue
== 255;
214 static inline int is_gray(struct color c
)
216 return c
.red
== c
.green
&& c
.red
== c
.blue
;
219 static inline int is_equal(struct color c1
, struct color c2
)
221 return c1
.red
== c2
.red
&& c1
.green
== c2
.green
&& c1
.blue
== c2
.blue
;
224 static void write_header(void)
228 out
= fopen(outputname
, "w");
230 die("Cannot create file %s: %s\n", outputname
, strerror(errno
));
236 fputs(" * DO NOT EDIT THIS FILE!\n", out
);
238 fprintf(out
, " * Linux logo %s\n", logoname
);
239 fputs(" */\n\n", out
);
240 fputs("#include <linux/linux_logo.h>\n\n", out
);
241 fprintf(out
, "static const unsigned char %s_data[] __initconst = {\n",
245 static void write_footer(void)
247 fputs("\n};\n\n", out
);
248 fprintf(out
, "const struct linux_logo %s __initconst = {\n", logoname
);
249 fprintf(out
, "\t.type\t\t= %s,\n", logo_types
[logo_type
]);
250 fprintf(out
, "\t.width\t\t= %u,\n", logo_width
);
251 fprintf(out
, "\t.height\t\t= %u,\n", logo_height
);
252 if (logo_type
== LINUX_LOGO_CLUT224
) {
253 fprintf(out
, "\t.clutsize\t= %u,\n", logo_clutsize
);
254 fprintf(out
, "\t.clut\t\t= %s_clut,\n", logoname
);
256 fprintf(out
, "\t.data\t\t= %s_data\n", logoname
);
257 fputs("};\n\n", out
);
259 /* close logo file */
264 static int write_hex_cnt
;
266 static void write_hex(unsigned char byte
)
268 if (write_hex_cnt
% 12)
269 fprintf(out
, ", 0x%02x", byte
);
270 else if (write_hex_cnt
)
271 fprintf(out
, ",\n\t0x%02x", byte
);
273 fprintf(out
, "\t0x%02x", byte
);
277 static void write_logo_mono(void)
280 unsigned char val
, bit
;
283 for (i
= 0; i
< logo_height
; i
++)
284 for (j
= 0; j
< logo_width
; j
++)
285 if (!is_black(logo_data
[i
][j
]) && !is_white(logo_data
[i
][j
]))
286 die("Image must be monochrome\n");
288 /* write file header */
291 /* write logo data */
292 for (i
= 0; i
< logo_height
; i
++) {
293 for (j
= 0; j
< logo_width
;) {
294 for (val
= 0, bit
= 0x80; bit
&& j
< logo_width
; j
++, bit
>>= 1)
295 if (logo_data
[i
][j
].red
)
301 /* write logo structure and file footer */
305 static void write_logo_vga16(void)
307 unsigned int i
, j
, k
;
311 for (i
= 0; i
< logo_height
; i
++)
312 for (j
= 0; j
< logo_width
; j
++) {
313 for (k
= 0; k
< 16; k
++)
314 if (is_equal(logo_data
[i
][j
], clut_vga16
[k
]))
317 die("Image must use the 16 console colors only\n"
318 "Use ppmquant(1) -map clut_vga16.ppm to reduce the number "
322 /* write file header */
325 /* write logo data */
326 for (i
= 0; i
< logo_height
; i
++)
327 for (j
= 0; j
< logo_width
; j
++) {
328 for (k
= 0; k
< 16; k
++)
329 if (is_equal(logo_data
[i
][j
], clut_vga16
[k
]))
332 if (++j
< logo_width
) {
333 for (k
= 0; k
< 16; k
++)
334 if (is_equal(logo_data
[i
][j
], clut_vga16
[k
]))
341 /* write logo structure and file footer */
345 static void write_logo_clut224(void)
347 unsigned int i
, j
, k
;
350 for (i
= 0; i
< logo_height
; i
++)
351 for (j
= 0; j
< logo_width
; j
++) {
352 for (k
= 0; k
< logo_clutsize
; k
++)
353 if (is_equal(logo_data
[i
][j
], logo_clut
[k
]))
355 if (k
== logo_clutsize
) {
356 if (logo_clutsize
== MAX_LINUX_LOGO_COLORS
)
357 die("Image has more than %d colors\n"
358 "Use ppmquant(1) to reduce the number of colors\n",
359 MAX_LINUX_LOGO_COLORS
);
360 logo_clut
[logo_clutsize
++] = logo_data
[i
][j
];
364 /* write file header */
367 /* write logo data */
368 for (i
= 0; i
< logo_height
; i
++)
369 for (j
= 0; j
< logo_width
; j
++) {
370 for (k
= 0; k
< logo_clutsize
; k
++)
371 if (is_equal(logo_data
[i
][j
], logo_clut
[k
]))
375 fputs("\n};\n\n", out
);
377 /* write logo clut */
378 fprintf(out
, "static const unsigned char %s_clut[] __initconst = {\n",
381 for (i
= 0; i
< logo_clutsize
; i
++) {
382 write_hex(logo_clut
[i
].red
);
383 write_hex(logo_clut
[i
].green
);
384 write_hex(logo_clut
[i
].blue
);
387 /* write logo structure and file footer */
391 static void write_logo_gray256(void)
396 for (i
= 0; i
< logo_height
; i
++)
397 for (j
= 0; j
< logo_width
; j
++)
398 if (!is_gray(logo_data
[i
][j
]))
399 die("Image must be grayscale\n");
401 /* write file header */
404 /* write logo data */
405 for (i
= 0; i
< logo_height
; i
++)
406 for (j
= 0; j
< logo_width
; j
++)
407 write_hex(logo_data
[i
][j
].red
);
409 /* write logo structure and file footer */
413 static void die(const char *fmt
, ...)
418 vfprintf(stderr
, fmt
, ap
);
424 static void usage(void)
427 "Usage: %s [options] <filename>\n"
430 " -h : display this usage information\n"
431 " -n <name> : specify logo name (default: linux_logo)\n"
432 " -o <output> : output to file <output> instead of stdout\n"
433 " -t <type> : specify logo type, one of\n"
434 " mono : monochrome black/white\n"
435 " vga16 : 16 colors VGA text palette\n"
436 " clut224 : 224 colors (default)\n"
437 " gray256 : 256 levels grayscale\n"
441 int main(int argc
, char *argv
[])
445 programname
= argv
[0];
449 opt
= getopt(argc
, argv
, "hn:o:t:");
467 if (!strcmp(optarg
, "mono"))
468 logo_type
= LINUX_LOGO_MONO
;
469 else if (!strcmp(optarg
, "vga16"))
470 logo_type
= LINUX_LOGO_VGA16
;
471 else if (!strcmp(optarg
, "clut224"))
472 logo_type
= LINUX_LOGO_CLUT224
;
473 else if (!strcmp(optarg
, "gray256"))
474 logo_type
= LINUX_LOGO_GRAY256
;
484 if (optind
!= argc
-1)
487 filename
= argv
[optind
];
491 case LINUX_LOGO_MONO
:
495 case LINUX_LOGO_VGA16
:
499 case LINUX_LOGO_CLUT224
:
500 write_logo_clut224();
503 case LINUX_LOGO_GRAY256
:
504 write_logo_gray256();