/* Copyright (C) 2025 Chud This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* gcc -Wall -Wextra -Werror -Wstrict-prototypes -pedantic -pedantic-errors -fstack-protector-all -fsanitize=address -std=c99 -Ofast -pipe -lm file2png.c -o file2png */ #include #include #include #include #include #define STB_IMAGE_IMPLEMENTATION #include #define STB_IMAGE_WRITE_IMPLEMENTATION #include int file_exists(const char *filename) { FILE *f = fopen(filename, "rb"); if (!f) return 0; fclose(f); return 1; } uint8_t *read_file(const char *filename, size_t *out_size) { FILE *f = fopen(filename, "rb"); if (!f) return NULL; fseek(f, 0, SEEK_END); *out_size = ftell(f); rewind(f); uint8_t *data = malloc(*out_size); fread(data, 1, *out_size, f); fclose(f); return data; } int main(int argc, char *argv[]) { if (argc < 4) { printf("Usage: %s [data file] [overlay png] [output png]\n" "Example: %s input.mp4 input.png output.png\n", argv[0], argv[0]); return 1; } if (!file_exists(argv[1])) { printf("%s doesn't exist.\n", argv[1]); return 1; } if (!file_exists(argv[2])) { printf("%s doesn't exist.\n", argv[2]); return 1; } size_t data_size; uint8_t *data = read_file(argv[1], &data_size); if (!data) { fprintf(stderr, "Failed to read data file.\n"); return 1; } int overlay_w, overlay_h, overlay_channels; uint8_t *overlay = stbi_load(argv[2], &overlay_w, &overlay_h, &overlay_channels, 1); if (!overlay) { fprintf(stderr, "Failed to load overlay image.\n"); free(data); return 1; } // calculate pixel count and res int pixel_count = (int)ceil(data_size / 3.0); float pixel_root = sqrt((float)pixel_count); float aspect = (float)overlay_w / overlay_h; float aspect_root = sqrtf(aspect); int width = (int)ceil(pixel_root * aspect_root); int height = (int)ceil(pixel_root / aspect_root); int padded_size = width * height * 3; uint8_t *rgb_data = calloc(padded_size, 1); memcpy(rgb_data, data, data_size); free(data); // resize overlay png to match res uint8_t *resized_overlay = malloc(width * height); for (int y = 0; y < height; ++y) { int src_y = y * overlay_h / height; for (int x = 0; x < width; ++x) { int src_x = x * overlay_w / width; resized_overlay[y * width + x] = overlay[src_y * overlay_w + src_x]; } } free(overlay); for (int i = 0; i < width * height; ++i) { if (resized_overlay[i] == 0) resized_overlay[i] = 1; } // RGB+A uint8_t *rgba_data = malloc(width * height * 4); for (int i = 0; i < width * height; ++i) { rgba_data[4 * i + 0] = rgb_data[3 * i + 0]; rgba_data[4 * i + 1] = rgb_data[3 * i + 1]; rgba_data[4 * i + 2] = rgb_data[3 * i + 2]; rgba_data[4 * i + 3] = resized_overlay[i]; } free(rgb_data); free(resized_overlay); if (!stbi_write_png(argv[3], width, height, 4, rgba_data, width * 4)) { fprintf(stderr, "Failed to write PNG.\n"); free(rgba_data); return 1; } free(rgba_data); printf("ffmpeg -i %s -pix_fmt rgb24 -f rawvideo - | mpv -\n", argv[3]); return 0; }