/*
fblogo.c
Generate linux_logo.h header file for use with the framebuffer boot logo
Daniel Ved鴜 <> 1999
Gordon Fraser <> 2001/2002/2003
This software comes with ABSOLUTELY NO WARRANTY
This software is free software, and you are welcome to redistribute it
under certain conditions
See the COPYING file for details.
*/
#include "fblogo.h"
/*--------------------------------------------------------------------*/
int main(int argc, char** argv)
{
char* input_filename = NULL;
char* output_filename = NULL;
version_ = LINUX_24;
verbose_ = FALSE;
palette_ = NULL;
image_data_ = NULL;
parseArguments(argc, argv, &input_filename, &output_filename);
if(openFiles(input_filename, output_filename) != SUCCESS)
{
cleanup();
return ERROR;
}
if(readInputFile() != SUCCESS)
{
cleanup();
exit(EXIT_FAILURE);
}
writeOutputFile();
displayNotice();
cleanup();
if(input_filename != NULL)
free(input_filename);
if(output_filename != NULL)
free(output_filename);
return SUCCESS;
}
/*--------------------------------------------------------------------*/
void cleanup()
{
if(input_file_ != NULL)
fclose(input_file_);
if(output_file_ != NULL)
fclose(output_file_);
if(image_data_ != NULL)
free(image_data_);
if(palette_ != NULL)
free(palette_);
}
/*--------------------------------------------------------------------*/
void displayUsage(char* program_name)
{
printf("Usage:\n");
printf("%s [-2|-4] [-d] [-v] [-h] [inputfile [outputfile]]\n", program_name);
printf(" -h, --help display this help screen\n");
printf(" -v, --version display program version\n");
printf(" -d, --verbose display helpful messages\n");
printf(" -2, --linux-2.2 Create for 2.2.x kernels\n");
printf(" -4, --linux-2.4 Create for 2.4.x kernels (default)\n");
printf(" inputfile name of image file\n");
printf(" outputfile name of output file\n");
printf("If outputfile is omitted, results will be sent to stdout.\nIf inputfile is omitted too, input will be read from stdin.\n");
}
/*--------------------------------------------------------------------*/
void displayNotice()
{
if(!verbose_)
return;
fprintf(stderr, "Logo generated successfully\n\n");
fprintf(stderr, "Remember to modify linux/drivers/video/fbcon.c:\n");
fprintf(stderr, " Change \"#define LOGO_H 80\" to \"#define LOGO_H %li\"\n", height_);
fprintf(stderr, " Change \"#define LOGO_W 80\" to \"#define LOGO_W %li\"\n\n", width_);
if(version_ == LINUX_22)
{
fprintf(stderr, "As you are going to use it for Linux 2.2,\nmodify linux/include/asm-
/linux_logo.h:\n");
fprintf(stderr, " Change \"#define LINUX_LOGO_COLORS 214\" to \"#define LINUX_LOGO_COLORS %i\"\n\n", num_palette_);
}
fprintf(stderr, "Then copy your new header to linux/include/linux/linux_logo.h,\n");
fprintf(stderr, "and recompile the kernel.\n");
}
/*--------------------------------------------------------------------*/
void displayVersion(void)
{
printf("fblogo version %s\n", PROGRAM_VERSION);
}
/*--------------------------------------------------------------------*/
int parseArguments(int argc, char** argv, char** input_filename, char** output_filename)
{
static struct option long_opts[] = {
{"help", 0, NULL, 'h'},
{"version", 0, NULL, 'v'},
{"linux-2.4", 0, NULL, '4'},
{"linux-2.2", 0, NULL, '2'},
{"verbose", 0, NULL, 'd'},
{NULL, 0, NULL, 0 }};
int counter;
int filename_position;
if(argc > MAX_ARGUMENTS)
{
displayUsage(argv[0]);
exit(EXIT_FAILURE);
}
while ((counter = getopt_long(argc, argv, "hvd24", long_opts, NULL)) != -1)
{
switch (counter)
{
case 'h':
case ':':
case '?':
displayUsage(argv[0]);
exit(0);
break;
case 'v':
displayVersion();
exit(0);
break;
case 'd':
verbose_ = TRUE;
break;
case '2':
version_ = LINUX_22;
break;
case '4':
version_ = LINUX_24;
break;
}
}
filename_position = optind;
if(filename_position < argc)
{
*input_filename = (char*)malloc(strlen(argv[filename_position])+1);
strcpy(*input_filename, argv[filename_position]);
}
if(++filename_position < argc)
{
*output_filename = (char*)malloc(strlen(argv[filename_position])+1);
strcpy(*output_filename, argv[filename_position]);
}
return optind;
}
/*--------------------------------------------------------------------*/
int openFiles(char* input_filename, char* output_filename)
{
if(input_filename == NULL)
{
if ((input_file_ = fdopen(0, "rb")) == (FILE *)NULL)
{
fprintf(stderr, "fblogo error: cannot open stdin\n");
return ERROR;
}
}
else
{
if ((input_file_ = fopen(input_filename, "rb")) == (FILE *)NULL)
{
fprintf(stderr, "fblogo error: cannot open input file %s\n", input_filename);
return ERROR;
}
}
if(output_filename == NULL)
{
if ((output_file_ = fdopen(1, "w")) == (FILE *)NULL)
{
fprintf(stderr, "fblogo error: cannot open stdout\n");
return ERROR;
}
}
else
{
if ((output_file_ = fopen(output_filename, "w")) == (FILE *)NULL)
{
fprintf(stderr, "fblogo error: cannot open output file %s\n", output_filename);
return ERROR;
}
}
return SUCCESS;
}
/*--------------------------------------------------------------------*/
int pngCheck()
{
unsigned char buf[PNG_SIG_BYTES];
if (fread(buf, 1, PNG_SIG_BYTES, input_file_) != PNG_SIG_BYTES)
{
fprintf(stderr, "fblogo error: image is not a png\n");
return ERROR;
}
if(png_sig_cmp(buf, 0, PNG_SIG_BYTES))
{
fprintf(stderr, "fblogo error: image is not a png\n");
return ERROR;
}
return SUCCESS;
}
/*--------------------------------------------------------------------*/
int pngInit(png_structp *png_ptr, png_infop *info_ptr)
{
/* Now create png_struct and png_info */
*png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL);
if (!*png_ptr)
{
fprintf(stderr, "fblogo error reading png\n");
return ERROR;
}
*info_ptr = png_create_info_struct(*png_ptr);
if (!*info_ptr)
{
fprintf(stderr, "fblogo error reading png\n");
png_destroy_read_struct(&*png_ptr, (png_infopp)NULL, (png_infopp)NULL);
return ERROR;
}
png_init_io(*png_ptr, input_file_);
png_set_sig_bytes(*png_ptr, PNG_SIG_BYTES);
png_read_info(*png_ptr, *info_ptr);
return SUCCESS;
}
/*--------------------------------------------------------------------*/int pngGetPalette(png_structp png_ptr, png_infop info_ptr, int bit_depth, int color_type)
{
int num_colours = 0;
png_colorp png_palette;
if (color_type != PNG_COLOR_TYPE_PALETTE || bit_depth > 8) {
fprintf(stderr, "fblogo error: only palette PNGs supported\n");
return ERROR;
}
if (bit_depth < 8)
png_set_packing(png_ptr); /* expand to 1 byte per pixel */
png_get_PLTE(png_ptr, info_ptr, &png_palette, &num_colours);
if (num_colours > 223)
{
fprintf(stderr, "fblogo error: too many colors (%d); must be less than 224\n", num_colours);
return ERROR;
}
palette_ = malloc(sizeof(png_color) * num_colours);
memcpy(palette_, png_palette, sizeof(png_color) * num_colours);
num_palette_ = num_colours;
return SUCCESS;
}
/*--------------------------------------------------------------------*/
int pngReadImage(png_structp png_ptr, png_infop info_ptr)
{
png_uint_32 rowbytes;
png_bytepp row_pointers = NULL;
unsigned counter;
/* allocate space for the PNG image data */
rowbytes = png_get_rowbytes(png_ptr, info_ptr);
if ((image_data_ = (png_bytep)malloc(width_*height_)) == NULL)
{
fprintf(stderr, "fblogo error: can't allocate image data\n");
return ERROR;
}
if ((row_pointers = (png_bytepp)malloc(height_*sizeof(png_bytep))) == NULL)
{
fprintf(stderr, "fblogo error: can't allocate row pointers\n");
free(row_pointers);
return ERROR;
}
/* set the individual row_pointers to point at the correct offsets */
for (counter = 0; counter < height_; counter++)
row_pointers[counter] = image_data_ + counter * rowbytes;
png_read_image(png_ptr, row_pointers);
png_read_end(png_ptr, info_ptr);
free(row_pointers);
return SUCCESS;
}
/*--------------------------------------------------------------------
Based on libpng example.c and
png2linuxlogo by Greg Roelofs <>
*/
int readInputFile()
{
int bit_depth, color_type;
png_structp png_ptr;
png_infop info_ptr;
if(pngCheck())
{
return ERR_NOPNG;
}
if(pngInit(&png_ptr, &info_ptr))
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return ERR_PNGPTR;
}
png_get_IHDR(png_ptr, info_ptr, &width_, &height_, &bit_depth, &color_type, NULL, NULL, NULL);
if(pngGetPalette(png_ptr, info_ptr, bit_depth, color_type))
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return ERR_NOPNG;
}
if(pngReadImage(png_ptr, info_ptr))
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return ERR_PNGPTR;
}
png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
return SUCCESS;
}
/*--------------------------------------------------------------------*/
void writeOutputFileHeader()
{
time_t timestamp;
char datestr[32];
timestamp = time((time_t *)NULL);
strftime(datestr, 32, "%Y/%m/%d %H:%M:%S", localtime(×tamp));
fprintf(output_file_, "/* linux_logo.h created with fblogo, %s\n"
" * include/linux/linux_logo.h: This is a linux logo\n"
" * to be displayed on boot.\n"
" *\n"
" * Copyright (C) 1996 Larry Ewing ("
" * Copyright (C) 1996,1998 Jakub Jelinek (
jj@sunsite.mff.cuni.cz)\n"
" *\n"
" * You can put anything here, but:\n"
" * LINUX_LOGO_COLORS has to be less than 224\n", datestr);
fprintf(output_file_, " * Generated by fblogo version %s\n *\n", PROGRAM_VERSION);
if(version_ == LINUX_22)
{
fprintf(output_file_, " *\n * As you are going to use it for Linux 2.2,\n * modify include/asm-
/linux_logo.h:\n");
fprintf(output_file_, " * Change \"#define LINUX_LOGO_COLORS 214\" to \"#define LINUX_LOGO_COLORS %i\"\n", num_palette_);
}
fprintf(output_file_, " *\n * Remember to modify drivers/video/fbcon.c:\n");
fprintf(output_file_, " * Change \"#define LOGO_H 80\" to \"#define LOGO_H %li\"\n", height_);
fprintf(output_file_, " * Change \"#define LOGO_W 80\" to \"#define LOGO_W %li\"\n */\n\n", width_);
if(version_ == LINUX_24)
{
fprintf(output_file_, "#ifndef __HAVE_ARCH_LINUX_LOGO\n");
/* fprintf(output_file_, "#define LINUX_LOGO_COLORS %d\n", num_palette_); */
fprintf(output_file_, "#define LINUX_LOGO_COLORS %d\n", 223);
fprintf(output_file_, "#endif\n");
fprintf(output_file_, "#ifdef INCLUDE_LINUX_LOGO_DATA\n");
fprintf(output_file_, "#ifndef __HAVE_ARCH_LINUX_LOGO\n");
}
else
{
fprintf(output_file_, "#if LINUX_LOGO_COLORS == %d\n", num_palette_);
}
}
/*--------------------------------------------------------------------*/
void writeOutputFile()
{
png_bytep pixel;
unsigned counter;
if(version_ == LINUX_22 && verbose_)
printf("Creating for Linux kernel version 2.2.x\n");
else if(version_ == LINUX_24 && verbose_)
printf("Creating for Linux kernel version 2.4.x/2.5.x\n");
writeOutputFileHeader();
/* red palette */
fprintf(output_file_, "unsigned char linux_logo_red[] __initdata = {");
for(counter=0; counter {
if(counter % 8 == 0)
fprintf(output_file_, "\n ");
fprintf(output_file_, "0x%2.2X",palette_[counter].red);
if(counter != num_palette_-1)
fprintf(output_file_, ", ");
}
fprintf(output_file_,"\n};\n\n");
/* green palette */
fprintf(output_file_, "unsigned char linux_logo_green[] __initdata = {");
for(counter=0; counter {
if(counter % 8 == 0)
fprintf(output_file_, "\n ");
fprintf(output_file_, "0x%2.2X",palette_[counter].green);
if(counter != num_palette_-1)
fprintf(output_file_, ", ");
}
fprintf(output_file_,"\n};\n\n");
/* blue palette */
fprintf(output_file_, "unsigned char linux_logo_blue[] __initdata = {");
for(counter=0; counter {
if(counter % 8 == 0)
fprintf(output_file_, "\n ");
fprintf(output_file_, "0x%2.2X",palette_[counter].blue);
if(counter!=num_palette_-1)
fprintf(output_file_, ", ");
}
fprintf(output_file_,"\n};\n\n");
/* image data */
fprintf(output_file_, "unsigned char linux_logo[] __initdata = {");
pixel = image_data_;
for (counter = 0; counter < width_*height_; counter++)
{
if (counter > 0)
fprintf(output_file_, ",");
if (counter % 8 == 0)
fprintf(output_file_, "\n ");
fprintf(output_file_, " 0x%2.2X", (*pixel++) + 0x20);
}
/* footer */
if(version_ == LINUX_22)
{
fprintf(output_file_,"\n};\n\n#endif\n\n");
fprintf(output_file_, low_color_logo_22);
}
else
{
fprintf(output_file_,"\n};\n\n#endif /* !__HAVE_ARCH_LINUX_LOGO */\n");
fprintf(output_file_, low_color_logo_24);
}
}