HaikuDepot: notify work status from main window
[haiku.git] / src / tools / generate_boot_screen.cpp
blob5869ad26d3cbae2c92d6359a9e22b39d746e50f5
1 /*
2 * Copyright (c) 2008-2011, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT license.
5 * Authors:
6 * Artur Wyszynski <harakash@gmail.com>
7 * Stephan Aßmus <superstippi@gmx.de>
8 * Philippe Saint-Pierre <stpere@gmail.com>
9 * David Powell <david@mad.scientist.com>
10 * Philippe Houdoin
13 //! Haiku boot splash image generator/converter
15 #include <iostream>
16 #include <png.h>
17 #include <string>
18 #include <stdarg.h>
19 #include <stdint.h>
20 #include <stdlib.h>
22 #include <zlib.h>
24 #include <ColorQuantizer.h>
26 // TODO: Create 4 bit palette version of these
27 // images as well, so that they are ready to be
28 // used during boot in case we need to run in
29 // palette 4 bit VGA mode.
32 FILE* sOutput = NULL;
33 int sOffset = 0;
35 static void
36 error(const char *s, ...)
38 va_list args;
39 va_start(args, s);
40 vfprintf(stderr, s, args);
41 fprintf(stderr, "\n");
42 va_end(args);
43 exit(-1);
47 static void
48 new_line_if_required()
50 sOffset++;
51 if (sOffset % 12 == 0)
52 fprintf(sOutput, "\n\t");
56 // #pragma mark -
59 class AutoFileCloser {
60 public:
61 AutoFileCloser(FILE* file)
62 : fFile(file)
64 ~AutoFileCloser()
66 fclose(fFile);
68 private:
69 FILE* fFile;
73 // #pragma mark -
76 class ZlibCompressor {
77 public:
78 ZlibCompressor(FILE* output);
80 int Compress(const void* data, int dataSize, int flush = Z_NO_FLUSH);
81 int Finish();
83 private:
84 FILE* fOutput;
85 z_stream fStream;
89 ZlibCompressor::ZlibCompressor(FILE* output)
90 : fOutput(output)
92 // prepare zlib stream
94 fStream.next_in = NULL;
95 fStream.avail_in = 0;
96 fStream.total_in = 0;
97 fStream.next_out = NULL;
98 fStream.avail_out = 0;
99 fStream.total_out = 0;
100 fStream.msg = 0;
101 fStream.state = 0;
102 fStream.zalloc = Z_NULL;
103 fStream.zfree = Z_NULL;
104 fStream.opaque = Z_NULL;
105 fStream.data_type = 0;
106 fStream.adler = 0;
107 fStream.reserved = 0;
109 int zlibError = deflateInit(&fStream, Z_BEST_COMPRESSION);
110 if (zlibError != Z_OK)
111 return; // TODO: translate zlibError
116 ZlibCompressor::Compress(const void* data, int dataSize, int flush)
118 uint8 buffer[1024];
120 fStream.next_in = (Bytef*)data;
121 fStream.avail_in = dataSize;
123 int zlibError = Z_OK;
125 do {
126 fStream.next_out = (Bytef*)buffer;
127 fStream.avail_out = sizeof(buffer);
129 zlibError = deflate(&fStream, flush);
130 if (zlibError != Z_OK &&
131 (flush == Z_FINISH && zlibError != Z_STREAM_END))
132 return zlibError;
134 unsigned int outputSize = sizeof(buffer) - fStream.avail_out;
135 for (unsigned int i = 0; i < outputSize; i++) {
136 fprintf(fOutput, "%d, ", buffer[i]);
137 new_line_if_required();
140 if (zlibError == Z_STREAM_END)
141 break;
143 } while (fStream.avail_in > 0 || flush == Z_FINISH);
145 return zlibError;
150 ZlibCompressor::Finish()
152 Compress(NULL, 0, Z_FINISH);
153 return deflateEnd(&fStream);
157 // #pragma mark -
160 static void
161 read_png(const char* filename, int& width, int& height, png_bytep*& rowPtrs,
162 png_structp& pngPtr, png_infop& infoPtr)
164 char header[8];
165 FILE* input = fopen(filename, "rb");
166 if (!input)
167 error("[read_png] File %s could not be opened for reading", filename);
169 AutoFileCloser _(input);
171 fread(header, 1, 8, input);
172 if (png_sig_cmp((png_byte *)header, 0, 8 ))
173 error("[read_png] File %s is not recognized as a PNG file", filename);
175 pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
176 NULL, NULL, NULL);
177 if (!pngPtr)
178 error("[read_png] png_create_read_struct failed");
180 infoPtr = png_create_info_struct(pngPtr);
181 if (!infoPtr)
182 error("[read_png] png_create_info_struct failed");
184 // TODO: I don't know which version of libpng introduced this feature:
185 #if PNG_LIBPNG_VER > 10005
186 if (setjmp(png_jmpbuf(pngPtr)))
187 error("[read_png] Error during init_io");
188 #endif
190 png_init_io(pngPtr, input);
191 png_set_sig_bytes(pngPtr, 8);
193 // make sure we automatically get RGB data with 8 bits per channel
194 // also make sure the alpha channel is stripped, in the end, we
195 // expect 24 bits BGR data
196 png_set_expand(pngPtr);
197 png_set_expand_gray_1_2_4_to_8(pngPtr);
198 png_set_palette_to_rgb(pngPtr);
199 png_set_gray_to_rgb(pngPtr);
200 png_set_strip_alpha(pngPtr);
201 png_set_bgr(pngPtr);
203 png_read_info(pngPtr, infoPtr);
204 width = (int)png_get_image_width(pngPtr, infoPtr);
205 height = (int)png_get_image_height(pngPtr, infoPtr);
206 if (png_get_bit_depth(pngPtr, infoPtr) != 8)
207 error("[read_png] File %s has wrong bit depth\n", filename);
208 if ((int)png_get_rowbytes(pngPtr, infoPtr) < width * 3) {
209 error("[read_png] File %s has wrong color type (RGB required)\n",
210 filename);
214 png_set_interlace_handling(pngPtr);
215 png_read_update_info(pngPtr, infoPtr);
217 #if PNG_LIBPNG_VER > 10005
218 if (setjmp(png_jmpbuf(pngPtr)))
219 error("[read_png] Error during read_image");
220 #endif
222 rowPtrs = (png_bytep*)malloc(sizeof(png_bytep) * height);
223 for (int y = 0; y < height; y++)
224 rowPtrs[y] = (png_byte*)malloc(png_get_rowbytes(pngPtr, infoPtr));
226 png_read_image(pngPtr, rowPtrs);
230 static void
231 write_24bit_image(const char* baseName, int width, int height, png_bytep* rowPtrs)
233 fprintf(sOutput, "static const uint16 %sWidth = %d;\n", baseName, width);
234 fprintf(sOutput, "static const uint16 %sHeight = %d;\n", baseName, height);
235 fprintf(sOutput, "#ifndef __BOOTSPLASH_KERNEL__\n");
237 fprintf(sOutput, "static uint8 %s24BitCompressedImage[] = {\n\t",
238 baseName);
240 ZlibCompressor zlib(sOutput);
242 for (int y = 0; y < height; y++)
243 zlib.Compress(rowPtrs[y], width * 3);
245 zlib.Finish();
247 fprintf(sOutput, "\n};\n");
248 fprintf(sOutput, "#endif\n\n");
252 static void
253 write_8bit_image(const char* baseName, int width, int height, unsigned char** rowPtrs)
255 //int buffer[128];
256 // buffer[0] stores count, buffer[1..127] holds the actual values
258 fprintf(sOutput, "static uint8 %s8BitCompressedImage[] = {\n\t",
259 baseName);
262 ZlibCompressor zlib(sOutput);
264 for (int y = 0; y < height; y++)
265 zlib.Compress(rowPtrs[y], width);
267 zlib.Finish();
269 fprintf(sOutput, "\n};\n\n");
273 unsigned char
274 nearest_color(unsigned char* color, RGBA palette[256])
276 int i, dist, minDist, index = 0;
277 minDist = 255 * 255 + 255 * 255 + 255 * 255 + 1;
278 for (i = 0; i < 256; i++) {
279 int dr = ((int)color[2]) - palette[i].r;
280 int dg = ((int)color[1]) - palette[i].g;
281 int db = ((int)color[0]) - palette[i].b;
282 dist = dr * dr + dg * dg + db * db;
283 if (dist < minDist) {
284 minDist = dist;
285 index = i;
288 return index;
292 static void
293 create_8bit_images(const char* logoBaseName, int logoWidth, int logoHeight,
294 png_bytep* logoRowPtrs, const char* iconsBaseName, int iconsWidth,
295 int iconsHeight, png_bytep* iconsRowPtrs)
297 // Generate 8-bit palette
298 BColorQuantizer quantizer(256, 8);
299 quantizer.ProcessImage(logoRowPtrs, logoWidth, logoHeight);
300 quantizer.ProcessImage(iconsRowPtrs, iconsWidth, iconsHeight);
302 RGBA palette[256];
303 quantizer.GetColorTable(palette);
305 // convert 24-bit logo image to 8-bit indexed color
306 uint8* logoIndexedImageRows[logoHeight];
307 for (int y = 0; y < logoHeight; y++) {
308 logoIndexedImageRows[y] = new uint8[logoWidth];
309 for (int x = 0; x < logoWidth; x++) {
310 logoIndexedImageRows[y][x] = nearest_color(&logoRowPtrs[y][x*3],
311 palette);
315 // convert 24-bit icons image to 8-bit indexed color
316 uint8* iconsIndexedImageRows[iconsHeight];
317 for (int y = 0; y < iconsHeight; y++) {
318 iconsIndexedImageRows[y] = new uint8[iconsWidth];
319 for (int x = 0; x < iconsWidth; x++) {
320 iconsIndexedImageRows[y][x] = nearest_color(&iconsRowPtrs[y][x*3],
321 palette);
326 fprintf(sOutput, "#ifndef __BOOTSPLASH_KERNEL__\n");
328 // write the 8-bit color palette
329 fprintf(sOutput, "static const uint8 k8BitPalette[] = {\n");
330 for (int c = 0; c < 256; c++) {
331 fprintf(sOutput, "\t0x%x, 0x%x, 0x%x,\n",
332 palette[c].r, palette[c].g, palette[c].b);
334 fprintf(sOutput, "\t};\n\n");
336 // write the 8-bit images
337 write_8bit_image(logoBaseName, logoWidth, logoHeight, logoIndexedImageRows);
338 write_8bit_image(iconsBaseName, iconsWidth, iconsHeight,
339 iconsIndexedImageRows);
341 fprintf(sOutput, "#endif\n\n");
343 // free memory
344 for (int y = 0; y < logoHeight; y++)
345 delete[] logoIndexedImageRows[y];
347 for (int y = 0; y < iconsHeight; y++)
348 delete[] iconsIndexedImageRows[y];
352 static void
353 parse_images(const char* logoFilename, const char* logoBaseName,
354 const char* iconsFilename, const char* iconsBaseName)
356 int logoWidth;
357 int logoHeight;
358 png_bytep* logoRowPtrs = NULL;
359 png_structp logoPngPtr;
360 png_infop logoInfoPtr;
362 int iconsWidth;
363 int iconsHeight;
364 png_bytep* iconsRowPtrs = NULL;
365 png_structp iconsPngPtr;
366 png_infop iconsInfoPtr;
368 read_png(logoFilename, logoWidth, logoHeight, logoRowPtrs, logoPngPtr,
369 logoInfoPtr);
370 read_png(iconsFilename, iconsWidth, iconsHeight, iconsRowPtrs, iconsPngPtr,
371 iconsInfoPtr);
373 // write 24-bit images
374 write_24bit_image(logoBaseName, logoWidth, logoHeight, logoRowPtrs);
375 write_24bit_image(iconsBaseName, iconsWidth, iconsHeight, iconsRowPtrs);
377 // write 8-bit index color images
378 create_8bit_images(logoBaseName, logoWidth, logoHeight, logoRowPtrs,
379 iconsBaseName, iconsWidth, iconsHeight, iconsRowPtrs);
381 // free resources
382 png_destroy_read_struct(&logoPngPtr, &logoInfoPtr, NULL);
383 for (int y = 0; y < logoHeight; y++)
384 free(logoRowPtrs[y]);
385 free(logoRowPtrs);
387 png_destroy_read_struct(&iconsPngPtr, &iconsInfoPtr, NULL);
388 for (int y = 0; y < iconsHeight; y++)
389 free(iconsRowPtrs[y]);
390 free(iconsRowPtrs);
395 main(int argc, char* argv[])
397 if (argc < 8) {
398 printf("Usage:\n");
399 printf("\t%s <splash.png> <x placement in %%> <y placement in %%> "
400 "<icons.png> <x placement in %%> <y placement in %%> <images.h>\n",
401 argv[0]);
402 return 0;
405 int logoPlacementX = atoi(argv[2]);
406 int logoPlacementY = atoi(argv[3]);
407 int iconPlacementX = atoi(argv[5]);
408 int iconPlacementY = atoi(argv[6]);
409 if (logoPlacementX < 0 || logoPlacementX > 100) {
410 printf("Bad X placement for logo: %d%%\n", logoPlacementX);
411 return 1;
413 if (logoPlacementY < 0 || logoPlacementY > 100) {
414 printf("Bad Y placement for logo: %d%%\n\n", logoPlacementY);
415 return 1;
417 if (iconPlacementX < 0 || iconPlacementX > 100) {
418 printf("Bad X placement for icons: %d%%\n", iconPlacementX);
419 return 1;
421 if (iconPlacementY < 0 || iconPlacementY > 100) {
422 printf("Bad Y placement for icons: %d%%\n", iconPlacementY);
423 return 1;
426 const char* headerFileName = argv[7];
427 sOutput = fopen(headerFileName, "wb");
428 if (!sOutput)
429 error("Could not open file \"%s\" for writing", headerFileName);
431 fputs("// This file was generated by the generate_boot_screen Haiku build "
432 "tool.\n\n", sOutput);
434 fprintf(sOutput, "static const int32 kSplashLogoPlacementX = %d;\n",
435 logoPlacementX);
436 fprintf(sOutput, "static const int32 kSplashLogoPlacementY = %d;\n",
437 logoPlacementY);
438 fprintf(sOutput, "static const int32 kSplashIconsPlacementX = %d;\n",
439 iconPlacementX);
440 fprintf(sOutput, "static const int32 kSplashIconsPlacementY = %d;\n\n",
441 iconPlacementY);
443 parse_images(argv[1], "kSplashLogo", argv[4], "kSplashIcons");
445 fclose(sOutput);
446 return 0;