new: add write_png
This commit is contained in:
82
src/write_png.c
Normal file
82
src/write_png.c
Normal 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
6
src/write_png.h
Normal 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);
|
||||
Reference in New Issue
Block a user