mii_emu/libmui/utils/png2raw.c
Michel Pollet 11cdb8b209 Version 1.9: See Changelog for details
List is too long...

Signed-off-by: Michel Pollet <buserror@gmail.com>
2024-05-13 16:40:51 +01:00

109 lines
3.3 KiB
C

#!/usr/bin/tcc -run
/*
* This tool is made to load a PNG, and convert it to a C array with
* ARGB8888 format, premultiplied alpha.
* It uses stb_image.h to load the PNG, which isn't included in the
* repository. The tool isn't essential to build, but is useful if you
* want icons in your menus.
* The output is a C array, with the width and height of the image
* followed by the pixels in ARGB8888 format.
* The output is written to stdout, unless -o is used.
*/
#include <ctype.h>
#define STB_IMAGE_IMPLEMENTATION
#define STBI_NO_SIMD
#define STBI_NO_HDR
#include "/opt/projects/stb/stb_image.h"
static void usage(const char *argv0)
{
fprintf(stderr,
"Usage: %s -n <array_name> "
"[-o <output_filename>] "
"[-t <int type>] "
"<PNG filename>\n",
argv0);
}
int main(int argc, char **argv)
{
const char *array_name = NULL;
const char *fname = "docs/Apple_logo_rainbow_version2_28x28.png";
const char *int_type = "uint32_t";
FILE *out = stdout;
for (int i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-n") && i + 1 < argc) {
array_name = argv[i + 1];
i++;
} else if (!strcmp(argv[i], "-o") && i + 1 < argc) {
out = fopen(argv[i + 1], "w");
if (!out) {
fprintf(stderr, "Error opening %s\n", argv[i + 1]);
usage(argv[0]);
return 1;
}
i++;
} else if (!strcmp(argv[i], "-t") && i + 1 < argc) {
int_type = argv[i + 1];
i++;
} else if (!strcmp(argv[i], "-h")) {
usage(argv[0]);
return 0;
} else {
fname = argv[i];
}
}
if (!array_name) {
fprintf(stderr, "Missing array name\n");
usage(argv[0]);
return 1;
}
char define_name[256];
strcpy(define_name, array_name);
for (int i = 0; define_name[i]; i++)
define_name[i] = toupper(define_name[i]);
int width, height, channels;
unsigned char *data = stbi_load(fname, &width, &height, &channels, 0);
if (!data) {
fprintf(stderr, "Error loading image\n");
return 1;
}
fprintf(out, "// Autogenerated with:\n//\t");
for (int i = 0; i < argc; i++)
fprintf(out, " %s", argv[i]);
fprintf(out, "\n");
fprintf(out, "// Image with a W:%dpx, H:%dpx and %d channels\n"
"// Converted to ARGB8888 and premultiplied alpha\n"
"#pragma once\n",
width, height, channels);
fprintf(out, "#define %s_SIZE %d\n", define_name, 2 + (width * height));
fprintf(out, "extern const %s %s[%s_SIZE];\n", int_type, array_name, define_name);
fprintf(out, "#ifdef %s_DEFINE\n", define_name);
fprintf(out, "const %s %s[%s_SIZE] = {\n", int_type, array_name, define_name);
fprintf(out, "%d, %d, // width, height\n", width, height);
uint32_t *pixels = (uint32_t *)data;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
uint32_t pixel = pixels[y * width + x];
// flip R and B channels
pixel = (pixel & 0xff00ff00) |
((pixel & 0xff) << 16) | ((pixel >> 16) & 0xff);
// also premultiply channels with alpha
uint32_t a = pixel >> 24;
pixel = (pixel & ~(0xff << 0)) |
((((((pixel >> 0) & 0xff) * a) >> 8) & 0xff) << 0);
pixel = (pixel & ~(0xff << 8)) |
((((((pixel >> 8) & 0xff) * a) >> 8) & 0xff) << 8);
pixel = (pixel & ~(0xff << 16)) |
((((((pixel >> 16) & 0xff) * a) >> 8) & 0xff) << 16);
fprintf(out, "0x%08x,", pixel);
if (((y * height) + x) % 8 == 7)
fprintf(out, "\n");
}
}
fprintf(out, "};\n");
fprintf(out, "#endif /* %s_DEFINE */\n", define_name);
return 0;
}