From 4f879c4d6dbb895c4d43d8ce6fe08e6b796194a5 Mon Sep 17 00:00:00 2001 From: Amy Gale Ruth Bowersox Date: Fri, 6 Dec 2019 20:27:52 -0700 Subject: [PATCH] add splash screen graphic as PNG and conversion program --- buildutils/Makefile | 7 + buildutils/mksplash.c | 304 ++++++++++++++++++++++++++++++++++++++++++ src/splash.png | Bin 0 -> 12679 bytes 3 files changed, 311 insertions(+) create mode 100644 buildutils/Makefile create mode 100644 buildutils/mksplash.c create mode 100644 src/splash.png 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 0000000000000000000000000000000000000000..f272d2f34f65143e24b6dd5c4d4cdb03c764bbc9 GIT binary patch literal 12679 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 literal 0 HcmV?d00001