/* The image inliner converts PNG images to C++ code. * * Usage: inliner snake_case_image.png * * The inliner creates a .h and a .cpp file in the same directory as the input * file. The implementation file declares an Image in the ImageStore namespace, * and the header exposes a pointer to this variable. The Image embedds the * bitmap data in the RGB565 format. */ #include #include #include #include #include #include #define ERROR_IF(cond, message) if (cond) { printf(message); return -1; }; #define MAX_FILENAME_LENGTH 255 void generateHeaderFromImage(FILE * file, const char * guardian, const char * variable); void generateImplementationFromImage(FILE * file, const char * header, const char * variable, uint32_t width, uint32_t height, png_bytep * pixelsRowPointers); void fileNameToSnakeCaseName(const char * fileName, char * snakeCaseName, size_t maxLength); void snakeCaseNameToUpperSnakeName(const char * snakeCaseName, char * upperSnakeCaseName, size_t maxLength); void camelCaseNameFromSnakeCaseNames(const char * snakeCaseName, const char * upperSnakeCaseName, char * camelCaseName, size_t maxLength); // TODO: fix inliner to handle any png file // TODO: truncate the app image dimensions to 55x56 pixels int main(int argc, char * argv[]) { ERROR_IF(argc != 2, "Usage: inliner source.png"); const char * inputPath = argv[1]; FILE * inputFile = fopen(inputPath, "rb"); ERROR_IF(inputFile == NULL, "Error: could not open input file."); unsigned char magic[8]; fread(magic, 1, 8, inputFile); ERROR_IF(png_sig_cmp(magic, 0, 8), "Error: Input file is not a PNG file"); png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); ERROR_IF(png == NULL, "Could not read png struct"); png_infop info = png_create_info_struct(png); ERROR_IF(info == NULL, "Could not read info struct"); png_init_io(png, inputFile); png_set_sig_bytes(png, 8); png_read_info(png, info); png_uint_32 width = png_get_image_width(png, info); png_uint_32 height = png_get_image_height(png, info); png_byte colorType = png_get_color_type(png, info); png_byte bitDepth = png_get_bit_depth(png, info); ERROR_IF(colorType != PNG_COLOR_TYPE_RGB_ALPHA, "Error: Inliner only handles RGBA PNG images."); ERROR_IF(bitDepth != 8, "Error: Inliner only handles RGBA8888 PNG images."); png_bytep * rowPointers = (png_bytep *)malloc(sizeof(png_bytep)*height); for (int i=0; i\n\n"); fprintf(file, "namespace ImageStore {\n\n"); fprintf(file, "extern const Image * %s;\n\n", variable); fprintf(file, "};\n\n"); fprintf(file, "#endif\n"); } void generateImplementationFromImage(FILE * file, const char * header, const char * variable, uint32_t width, uint32_t height, png_bytep * pixelsRowPointers) { fprintf(file, "// This file is auto-generated by Inliner. Do not edit manually.\n"); fprintf(file, "#include \"%s.h\"\n\n", header); fprintf(file, "#define P(c) KDColor::RGB24(c)\n\n"); fprintf(file, "const KDColor pixels[] = {"); for (int j=0; j