#!/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 #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 " "[-o ] " "[-t ] " "\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; }