1 /* 2 * Copyright (c) 2008, Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT license. 4 * 5 * Authors: 6 * Artur Wyszynski <harakash@gmail.com> 7 * Stephan Aßmus <superstippi@gmx.de> 8 */ 9 10 //! Haiku boot splash image generator/converter 11 12 #include <iostream> 13 #include <png.h> 14 #include <string> 15 16 // TODO: Generate the single optimal palette for all three images, 17 // store palette versions of these images as well, so that they are 18 // ready to be used during boot in case we need to run in palette 19 // VGA mode. 20 21 22 FILE* sOutput = NULL; 23 24 25 static void 26 error(const char *s, ...) 27 { 28 va_list args; 29 va_start(args, s); 30 vfprintf(stderr, s, args); 31 fprintf(stderr, "\n"); 32 va_end(args); 33 exit(-1); 34 } 35 36 37 class AutoFileCloser { 38 public: 39 AutoFileCloser(FILE* file) 40 : fFile(file) 41 {} 42 ~AutoFileCloser() 43 { 44 fclose(fFile); 45 } 46 private: 47 FILE* fFile; 48 }; 49 50 51 static void 52 readPNG(const char* filename, int& width, int& height, png_bytep*& rowPtrs, 53 png_structp& pngPtr, png_infop& infoPtr) 54 { 55 char header[8]; 56 FILE* input = fopen(filename, "rb"); 57 if (!input) 58 error("[readPNG] File %s could not be opened for reading", filename); 59 60 AutoFileCloser _(input); 61 62 fread(header, 1, 8, input); 63 if (png_sig_cmp((png_byte *)header, 0, 8 )) 64 error("[readPNG] File %s is not recognized as a PNG file", filename); 65 66 pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 67 NULL, NULL, NULL); 68 if (!pngPtr) 69 error("[readPNG] png_create_read_struct failed"); 70 71 infoPtr = png_create_info_struct(pngPtr); 72 if (!infoPtr) 73 error("[readPNG] png_create_info_struct failed"); 74 75 // TODO: I don't know which version of libpng introduced this feature: 76 #if PNG_LIBPNG_VER > 10005 77 if (setjmp(png_jmpbuf(pngPtr))) 78 error("[readPNG] Error during init_io"); 79 #endif 80 81 png_init_io(pngPtr, input); 82 png_set_sig_bytes(pngPtr, 8); 83 84 // make sure we automatically get RGB data with 8 bits per channel 85 // also make sure the alpha channel is stripped, in the end, we 86 // expect 24 bits BGR data 87 png_set_expand(pngPtr); 88 png_set_gray_1_2_4_to_8(pngPtr); 89 png_set_palette_to_rgb(pngPtr); 90 png_set_gray_to_rgb(pngPtr); 91 png_set_strip_alpha(pngPtr); 92 png_set_bgr(pngPtr); 93 94 png_read_info(pngPtr, infoPtr); 95 width = infoPtr->width; 96 height = infoPtr->height; 97 if (infoPtr->bit_depth != 8) 98 error("[readPNG] File %s has wrong bit depth\n", filename); 99 if ((int)infoPtr->rowbytes < width * 3) { 100 error("[readPNG] File %s has wrong color type (RGB required)\n", 101 filename); 102 } 103 104 105 png_set_interlace_handling(pngPtr); 106 png_read_update_info(pngPtr, infoPtr); 107 108 #if PNG_LIBPNG_VER > 10005 109 if (setjmp(png_jmpbuf(pngPtr))) 110 error("[readPNG] Error during read_image"); 111 #endif 112 113 rowPtrs = (png_bytep*)malloc(sizeof(png_bytep) * height); 114 for (int y = 0; y < height; y++) 115 rowPtrs[y] = (png_byte*)malloc(infoPtr->rowbytes); 116 117 png_read_image(pngPtr, rowPtrs); 118 } 119 120 121 static void 122 writeHeader(const char* baseName, int width, int height, png_bytep* rowPtrs) 123 { 124 fprintf(sOutput, "static const uint16 %sWidth = %d;\n", baseName, width); 125 fprintf(sOutput, "static const uint16 %sHeight = %d;\n", baseName, height); 126 fprintf(sOutput, "static const uint8 %sImage[] = {\n\t", baseName); 127 128 int offset = 0; 129 for (int y = 0; y < height; y++) { 130 png_byte* row = rowPtrs[y]; 131 for (int x = 0; x < width * 3; x++) { 132 offset++; 133 if (x == width * 3 - 1 && y == height - 1) { 134 fprintf(sOutput, "0x%02x\n};\n\n", row[x]); 135 break; 136 } else if ((offset % 8) == 0) 137 fprintf(sOutput, "0x%02x,\n\t", row[x]); 138 else 139 fprintf(sOutput, "0x%02x, ", row[x]); 140 } 141 } 142 } 143 144 145 static void 146 parseImage(const char* filename, const char* baseName) 147 { 148 int width; 149 int height; 150 png_bytep* rowPtrs = NULL; 151 png_structp pngPtr; 152 png_infop infoPtr; 153 readPNG(filename, width, height, rowPtrs, pngPtr, infoPtr); 154 writeHeader(baseName, width, height, rowPtrs); 155 156 // free resources 157 png_destroy_read_struct(&pngPtr, &infoPtr, NULL); 158 for (int y = 0; y < height; y++) 159 free(rowPtrs[y]); 160 free(rowPtrs); 161 } 162 163 164 int 165 main(int argc, char* argv[]) 166 { 167 if (argc < 4) { 168 printf("Usage:\n"); 169 printf("\t%s <splash.png> <icons.png> <images.h>\n", 170 argv[0]); 171 return 0; 172 } 173 174 const char* headerFileName = argv[3]; 175 176 sOutput = fopen(headerFileName, "wb"); 177 if (!sOutput) 178 error("Could not open file \"%s\" for writing", headerFileName); 179 180 fputs("// This file was generated by the generate_boot_screen build tool." 181 "\n\n", sOutput); 182 183 parseImage(argv[1], "kSplashLogo"); 184 parseImage(argv[2], "kSplashIcons"); 185 186 fclose(sOutput); 187 return 0; 188 } 189 190