diff --git a/buildutils/Makefile b/buildutils/Makefile new file mode 100644 index 0000000..91c309c --- /dev/null +++ b/buildutils/Makefile @@ -0,0 +1,7 @@ +ALL: mksplash + +mksplash: mksplash.c + gcc -o mksplash -O -Wall -I/usr/include/libpng mksplash.c -lpng12 -lz + +clean: + rm -f *.o mksplash diff --git a/buildutils/mksplash.c b/buildutils/mksplash.c new file mode 100644 index 0000000..b32bfb0 --- /dev/null +++ b/buildutils/mksplash.c @@ -0,0 +1,304 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef png_jmpbuf +#define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) +#endif + +png_structp png_ptr = NULL; +png_infop info_ptr = NULL; + +png_uint_32 width, height; +int bit_depth, color_type; +uch *image_data = NULL; + +/* returns 0 on success, -1 on error */ +int readpng_init(const char *fname, FILE *infile, ulg *pWidth, ulg *pHeight) +{ + uch sig[8]; + + fread(sig, 1, 8, infile); + if (!png_check_sig(sig, 8)) + { + fprintf(stderr, "%s: invalid PNG file signature\n", fname); + return -1; + } + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + { + fprintf(stderr, "%s: out of memory\n", fname); + return -1; + } + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + { + png_destroy_read_struct(&png_ptr, NULL, NULL); + fprintf(stderr, "%s: out of memory\n", fname); + return -1; + } + + if (setjmp(png_jmpbuf(png_ptr))) + { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + fprintf(stderr, "%s: bad header in PNG image\n", fname); + return -1; + } + + png_init_io(png_ptr, infile); + png_set_sig_bytes(png_ptr, 8); + png_read_info(png_ptr, info_ptr); + + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); + *pWidth = width; + *pHeight = height; + + return 0; +} + +/* returns -1 on error, 0 otherwise (out vars not touched if we can't find background */ +int readpng_get_bgcolor(const char *fname, uch *red, uch *green, uch *blue) +{ + png_color_16p pBackground; + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + fprintf(stderr, "%s: unspecified error in background reading\n", fname); + return -1; + } + + if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) + return 0; + + png_get_bKGD(png_ptr, info_ptr, &pBackground); + + if (bit_depth == 16) + { + *red = pBackground->red >> 8; + *green = pBackground->green >> 8; + *blue = pBackground->blue >> 8; + } + else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + { + if (bit_depth == 1) + *red = *green = *blue = pBackground->gray ? 255 : 0; + else if (bit_depth == 2) + *red = *green = *blue = (255/3) * pBackground->gray; + else /* bit_depth == 4 */ + *red = *green = *blue = (255/15) * pBackground->gray; + } + else + { + *red = (uch)pBackground->red; + *green = (uch)pBackground->green; + *blue = (uch)pBackground->blue; + } + + return 0; +} + +/* display_exponent == LUT_exponent * CRT_exponent */ +uch *readpng_get_image(const char *fname, double display_exponent, int *pChannels, ulg *pRowbytes) +{ + double gamma; + png_uint_32 i, rowbytes; + png_bytepp row_pointers = NULL; + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + fprintf(stderr, "%s: unspecified error in image data reading\n", fname); + return NULL; + } + + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_expand(png_ptr); + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_expand(png_ptr); + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_expand(png_ptr); + if (bit_depth == 16) + png_set_strip_16(png_ptr); + if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png_ptr); + + if (png_get_gAMA(png_ptr, info_ptr, &gamma)) + png_set_gamma(png_ptr, display_exponent, gamma); + + png_read_update_info(png_ptr, info_ptr); + + *pRowbytes = rowbytes = png_get_rowbytes(png_ptr, info_ptr); + *pChannels = (int)png_get_channels(png_ptr, info_ptr); + + if ((image_data = (uch *)malloc(rowbytes*height)) == NULL) + { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + fprintf(stderr, "%s: could not allocate image buffer\n", fname); + return NULL; + } + + if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) + { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + free(image_data); + image_data = NULL; + fprintf(stderr, "%s: could not allocate image row buffer\n", fname); + return NULL; + } + + fprintf(stderr, "image %s: chans=%d rowbytes=%ld height=%ld\n", fname, *pChannels, + rowbytes, height); + + for (i = 0; i < height; ++i) + row_pointers[i] = image_data + i * rowbytes; + + png_read_image(png_ptr, row_pointers); + + free(row_pointers); + row_pointers = NULL; + + png_read_end(png_ptr, NULL); + + return image_data; +} + +void readpng_cleanup(int free_image_data) +{ + if (free_image_data && image_data) + { + free(image_data); + image_data = NULL; + } + + if (png_ptr && info_ptr) + { + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + png_ptr = NULL; + info_ptr = NULL; + } +} + +int do_convert(const char *infilename, const char *outfilename) +{ + ulg image_width, image_height, image_rowbytes, row, i; + FILE *fpin; + uch *image_data, *src; + uint16_t bred, bgreen, bblue, buf; + int image_channels, fdout; + uch bg_red=0, bg_green=0, bg_blue=0, br, bg, bb, ba; + double display_exponent = 2.2; /* a guesstimate */ + + if (!(fpin = fopen(infilename, "rb"))) + { + fprintf(stderr, "%s: could not open file\n", infilename); + return -1; + } + + if (readpng_init(fpin, &image_width, &image_height)) + { + readpng_cleanup(1); + fclose(fpin); + return -1; + } + + if ((image_width != 320) || (image_height != 240)) + { + readpng_cleanup(1); + fclose(fpin); + fprintf(stderr, "%s: image is %lux%lu, should be 320x240\n", infilename, image_width, image_height); + return -1; + } + + if (readpng_get_bgcolor(infilename, &bg_red, &bg_green, &bg_blue)) + { + readpng_cleanup(1); + fclose(fpin); + return -1; + } + + image_data = readpng_get_image(display_exponent, &image_channels, &image_rowbytes); + readpng_cleanup(0); + fclose(fpin); + if (!image_data) + return -1; + + if ((fdout = creat(outfilename, S_IREAD|S_IWRITE)) < 0) + { + free(image_data); + fprintf(stderr, "%s: could not open file\n", outfilename); + return -1; + } + + for (row = 0; row < image_height; ++row) + { + src = image_data + (row * image_rowbytes); + for (i = image_width; i > 0; --i) + { + if (image_channels == 3) + { + bred = *src++; + bgreen = *src++; + bblue = *src++; + } + else if (image_channels == 4) + { + br = *src++; + bg = *src++; + bb = *src++; + ba = *src++; + if (ba == 255) + { + bred = br; + bgreen = bg; + bblue = bb; + } + else if (ba == 0) + { + bred = bg_red; + bgreen = bg_green; + bblue = bg_blue; + } + else + { + alpha_composite(bred, br, ba, bg_red); + alpha_composite(bgreen, bg, ba, bg_green); + alpha_composite(bblue, bb, ba, bg_blue); + } + } + bred = (bred >> 3) & 0x1F; + bgreen = (bgreen >> 2) & 0x3F; + bblue = (bblue >> 3) & 0x1F; + buf = (bred << 11) | (bgreen << 5) | bblue; + if (write(fdout, &buf, sizeof(uint16_t)) < 0) + { + close(fdout); + free(image_data); + fprintf(stderr, "%s: error writing image data\n", outfilename); + return -1; + } + } + } + + close(fdout); + free(image_data); + return 0; +} + +int main(int argc, char *argv[]) +{ + if (argc < 3) + { + fprintf(stderr, "usage: mksplash inputfile outputfile\n"); + return EXIT_FAILURE; + } + + if (do_convert(argv[1], argv[2])) + return EXIT_FAILURE; + return EXIT_SUCCESS; +} diff --git a/src/splash.png b/src/splash.png new file mode 100644 index 0000000..f272d2f Binary files /dev/null and b/src/splash.png differ