xref: /haiku/src/tools/generate_boot_screen.cpp (revision 89755088d790ff4fe36f8aa77dacb2bd15507108)
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