new: add write_png

This commit is contained in:
2025-12-07 04:55:16 -05:00
parent a17bff625c
commit 265cace593
2 changed files with 88 additions and 0 deletions

82
src/write_png.c Normal file
View File

@@ -0,0 +1,82 @@
#include "write_png.h"
static inline double linear_to_srgb(double x){
if (x <= 0.0) return 0.0;
if (x >= 1.0) return 1.0;
if (x <= 0.0031308) return 12.92 * x;
return 1.055 * pow(x, 1.0/2.4) - 0.055;
}
int buffer_normalize_srgb(double **buffer, int W, int H) {
double max = 0;
for (int j = 0; j < H; j++) {
for (int i = 0; i < W; i++) {
for (int c = 0; c < 3; c++) {
if (max < buffer[j*W + i][c]) max = buffer[j*W + i][c];
}
}
}
if (max == 0) return 1;
for (int j = 0; j < H; j++) {
for (int i = 0; i < W; i++) {
for (int c = 0; c < 3; c++) {
buffer[j*W + i][c] /= max;
buffer[j*W+i][c] = linear_to_srgb(buffer[j*W+i][c]);
}
}
}
return 0;
}
int write_png(char *filename, double **buffer, int W, int H) {
buffer_normalize_srgb(buffer, W, H);
size_t bufsize = W*H*3;
uint8_t *img = (uint8_t *)malloc(bufsize);
if (!img) {return 1;}
for (int j = 0; j < H; j++) {
for (int i = 0; i < W; i++) {
for (int c = 0; c < 3; c++) {
int v = (int)lrint(buffer[j*W*i][c]);
if (v < 0) v = 0;
if (v > 255) v = 255;
img[j*W*3+i*3+c] = (uint8_t) v;
}
}
}
int flag = 0;
spng_ctx *ctx = spng_ctx_new(SPNG_CTX_ENCODER);
if(!ctx){ fprintf(stderr, "spng_ctx_new failed\n"); free(img); return 1; }
FILE *f = fopen(filename, "wb");
if(!f){ fprintf(stderr, "fopen failed\n"); spng_ctx_free(ctx); free(img); return 1; }
spng_set_png_file(ctx, f);
struct spng_ihdr ihdr = {0};
ihdr.width = W;
ihdr.height = H;
ihdr.bit_depth = 8;
ihdr.color_type = SPNG_COLOR_TYPE_TRUECOLOR; // RGB
ihdr.interlace_method = SPNG_INTERLACE_NONE;
ihdr.compression_method = 0;
ihdr.filter_method = 0;
if( (flag= spng_set_ihdr(ctx, &ihdr)) ){
fprintf(stderr, "spng_set_ihdr: %s\n", spng_strerror(flag));
fclose(f); spng_ctx_free(ctx); free(img); return 1;
}
#ifndef SPNG_SRGB_INTENT_PERCEPTUAL
#define SPNG_SRGB_INTENT_PERCEPTUAL 0
#endif
spng_set_srgb(ctx, SPNG_SRGB_INTENT_PERCEPTUAL);
flag = spng_encode_image(ctx, img, bufsize, SPNG_FMT_PNG, SPNG_ENCODE_FINALIZE);
if(flag){
fprintf(stderr, "spng_encode_image: %s\n", spng_strerror(flag));
}
fclose(f);
spng_ctx_free(ctx);
free(img);
return flag? 1 : 0;
}

6
src/write_png.h Normal file
View File

@@ -0,0 +1,6 @@
#include <spng.h>
#include <math.h>
#include <stdint.h>
int write_png(char *filename, double **buffer, int W, int H);