brintos

brintos / linux-shallow public Read only

0
0
Text · 11.0 KiB · 28d9f0b Raw
509 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *  Convert a logo in ASCII PNM format to C source suitable for inclusion in4 *  the Linux kernel5 *6 *  (C) Copyright 2001-2003 by Geert Uytterhoeven <geert@linux-m68k.org>7 */8 9#include <ctype.h>10#include <errno.h>11#include <stdarg.h>12#include <stdio.h>13#include <stdlib.h>14#include <string.h>15#include <unistd.h>16 17 18static const char *programname;19static const char *filename;20static const char *logoname = "linux_logo";21static const char *outputname;22static FILE *out;23 24 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 */29 30static 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"35};36 37#define MAX_LINUX_LOGO_COLORS	22438 39struct color {40	unsigned char red;41	unsigned char green;42	unsigned char blue;43};44 45static const struct color clut_vga16[16] = {46	{ 0x00, 0x00, 0x00 },47	{ 0x00, 0x00, 0xaa },48	{ 0x00, 0xaa, 0x00 },49	{ 0x00, 0xaa, 0xaa },50	{ 0xaa, 0x00, 0x00 },51	{ 0xaa, 0x00, 0xaa },52	{ 0xaa, 0x55, 0x00 },53	{ 0xaa, 0xaa, 0xaa },54	{ 0x55, 0x55, 0x55 },55	{ 0x55, 0x55, 0xff },56	{ 0x55, 0xff, 0x55 },57	{ 0x55, 0xff, 0xff },58	{ 0xff, 0x55, 0x55 },59	{ 0xff, 0x55, 0xff },60	{ 0xff, 0xff, 0x55 },61	{ 0xff, 0xff, 0xff },62};63 64 65static int logo_type = LINUX_LOGO_CLUT224;66static unsigned int logo_width;67static unsigned int logo_height;68static struct color **logo_data;69static struct color logo_clut[MAX_LINUX_LOGO_COLORS];70static unsigned int logo_clutsize;71static int is_plain_pbm = 0;72 73static void die(const char *fmt, ...)74__attribute__((noreturn)) __attribute((format (printf, 1, 2)));75static void usage(void) __attribute((noreturn));76 77 78static unsigned int get_number(FILE *fp)79{80	int c, val;81 82	/* Skip leading whitespace */83	do {84		c = fgetc(fp);85		if (c == EOF)86			die("%s: end of file\n", filename);87		if (c == '#') {88			/* Ignore comments 'till end of line */89			do {90				c = fgetc(fp);91				if (c == EOF)92					die("%s: end of file\n", filename);93			} while (c != '\n');94		}95	} while (isspace(c));96 97	/* Parse decimal number */98	val = 0;99	while (isdigit(c)) {100		val = 10*val+c-'0';101		/* some PBM are 'broken'; GiMP for example exports a PBM without space102		 * between the digits. This is Ok cause we know a PBM can only have a '1'103		 * or a '0' for the digit.104		 */105		if (is_plain_pbm)106			break;107		c = fgetc(fp);108		if (c == EOF)109			die("%s: end of file\n", filename);110	}111	return val;112}113 114static unsigned int get_number255(FILE *fp, unsigned int maxval)115{116	unsigned int val = get_number(fp);117 118	return (255*val+maxval/2)/maxval;119}120 121static void read_image(void)122{123	FILE *fp;124	unsigned int i, j;125	int magic;126	unsigned int maxval;127 128	/* open image file */129	fp = fopen(filename, "r");130	if (!fp)131		die("Cannot open file %s: %s\n", filename, strerror(errno));132 133	/* check file type and read file header */134	magic = fgetc(fp);135	if (magic != 'P')136		die("%s is not a PNM file\n", filename);137	magic = fgetc(fp);138	switch (magic) {139	case '1':140	case '2':141	case '3':142		/* Plain PBM/PGM/PPM */143		break;144 145	case '4':146	case '5':147	case '6':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);151 152	default:153		die("%s is not a PNM file\n", filename);154	}155	logo_width = get_number(fp);156	logo_height = get_number(fp);157 158	/* allocate image data */159	logo_data = (struct color **)malloc(logo_height*sizeof(struct color *));160	if (!logo_data)161		die("%s\n", strerror(errno));162	for (i = 0; i < logo_height; i++) {163		logo_data[i] = malloc(logo_width*sizeof(struct color));164	if (!logo_data[i])165		die("%s\n", strerror(errno));166	}167 168	/* read image data */169	switch (magic) {170	case '1':171		/* Plain PBM */172		is_plain_pbm = 1;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));177		break;178 179	case '2':180		/* Plain PGM */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);186		break;187 188	case '3':189		/* Plain PPM */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);196			}197		break;198	}199 200	/* close file */201	fclose(fp);202}203 204static inline int is_black(struct color c)205{206	return c.red == 0 && c.green == 0 && c.blue == 0;207}208 209static inline int is_white(struct color c)210{211	return c.red == 255 && c.green == 255 && c.blue == 255;212}213 214static inline int is_gray(struct color c)215{216	return c.red == c.green && c.red == c.blue;217}218 219static inline int is_equal(struct color c1, struct color c2)220{221	return c1.red == c2.red && c1.green == c2.green && c1.blue == c2.blue;222}223 224static void write_header(void)225{226	/* open logo file */227	if (outputname) {228		out = fopen(outputname, "w");229		if (!out)230			die("Cannot create file %s: %s\n", outputname, strerror(errno));231	} else {232		out = stdout;233	}234 235	fputs("/*\n", out);236	fputs(" *  DO NOT EDIT THIS FILE!\n", out);237	fputs(" *\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",242		logoname);243}244 245static void write_footer(void)246{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);255	}256	fprintf(out, "\t.data\t\t= %s_data\n", logoname);257	fputs("};\n\n", out);258 259	/* close logo file */260	if (outputname)261		fclose(out);262}263 264static int write_hex_cnt;265 266static void write_hex(unsigned char byte)267{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);272	else273		fprintf(out, "\t0x%02x", byte);274	write_hex_cnt++;275}276 277static void write_logo_mono(void)278{279	unsigned int i, j;280	unsigned char val, bit;281 282	/* validate image */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");287 288	/* write file header */289	write_header();290 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)296					val |= bit;297			write_hex(val);298		}299	}300 301	/* write logo structure and file footer */302	write_footer();303}304 305static void write_logo_vga16(void)306{307	unsigned int i, j, k;308	unsigned char val;309 310	/* validate image */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]))315					break;316			if (k == 16)317				die("Image must use the 16 console colors only\n"318				    "Use ppmquant(1) -map clut_vga16.ppm to reduce the number "319				    "of colors\n");320		}321 322	/* write file header */323	write_header();324 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]))330					break;331			val = k<<4;332			if (++j < logo_width) {333				for (k = 0; k < 16; k++)334					if (is_equal(logo_data[i][j], clut_vga16[k]))335						break;336				val |= k;337			}338			write_hex(val);339		}340 341	/* write logo structure and file footer */342	write_footer();343}344 345static void write_logo_clut224(void)346{347	unsigned int i, j, k;348 349	/* validate image */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]))354					break;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];361			}362		}363 364	/* write file header */365	write_header();366 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]))372					break;373			write_hex(k+32);374		}375	fputs("\n};\n\n", out);376 377	/* write logo clut */378	fprintf(out, "static const unsigned char %s_clut[] __initconst = {\n",379		logoname);380	write_hex_cnt = 0;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);385	}386 387	/* write logo structure and file footer */388	write_footer();389}390 391static void write_logo_gray256(void)392{393	unsigned int i, j;394 395	/* validate image */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");400 401	/* write file header */402	write_header();403 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);408 409	/* write logo structure and file footer */410	write_footer();411}412 413static void die(const char *fmt, ...)414{415	va_list ap;416 417	va_start(ap, fmt);418	vfprintf(stderr, fmt, ap);419	va_end(ap);420 421	exit(1);422}423 424static void usage(void)425{426	die("\n"427	"Usage: %s [options] <filename>\n"428	"\n"429	"Valid options:\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"438	"\n", programname);439}440 441int main(int argc, char *argv[])442{443	int opt;444 445	programname = argv[0];446 447	opterr = 0;448	while (1) {449		opt = getopt(argc, argv, "hn:o:t:");450		if (opt == -1)451			break;452 453		switch (opt) {454		case 'h':455			usage();456			break;457 458		case 'n':459			logoname = optarg;460			break;461 462		case 'o':463			outputname = optarg;464			break;465 466		case '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;475			else476				usage();477			break;478 479		default:480			usage();481			break;482		}483	}484	if (optind != argc-1)485		usage();486 487	filename = argv[optind];488 489	read_image();490	switch (logo_type) {491	case LINUX_LOGO_MONO:492		write_logo_mono();493		break;494 495	case LINUX_LOGO_VGA16:496		write_logo_vga16();497		break;498 499	case LINUX_LOGO_CLUT224:500		write_logo_clut224();501		break;502 503	case LINUX_LOGO_GRAY256:504		write_logo_gray256();505		break;506	}507	exit(0);508}509