The simplest image format you can use is in PGM format. Short for Portable GrayMap format, it's a simple image format where the pixel values are stored raw, great for readily writing values into a file and representing them as they are!
A .pgm file has the below form:
P5
width height
max value
{{data}}
next of width ROW = 128 and height COL = 128 into an image by simply writing
P5
128 128
255
{{all array values here!}}
Below I'll provide a simple function that creates a frame pgm image and writes data on it from an array. Note, I'm using an integer passed by reference, in order to have a frame counter that is dynamically incremented.
#include <stdio.h>
#define ROW 128
#define COL 128
#define SIZE ROW*COL
#define EXP 12
#define ONE 0x1000
int mulf(int a, int b) {
int res = a * b;
//for a right bit shift, you have to handle the cases where result is negative
if (res < 0) return -(-res >> EXP);
return res >> EXP;
}
const int c2 = 0x110;
void compute_next(int *next, int *curr, int *prev) {
for (int x=ROW; x<SIZE-ROW; x+=ROW) {
for (int y=1; y<ROW-1; y++) {
int dt = 2*curr[x+y] - prev[x+y];
int ds = 4*curr[x+y] - curr[(x+1)+y] - curr[(x-1)+y] - curr[x+(y+ROW)] - curr[x+(y-ROW)];
next[x+y] = dt - mulf(ds, c2);
}
}
//edge along y=0
for (int x=0; x<SIZE; x+=ROW) next[x] = 0;
//edge along y=ROW-1
for (int x=ROW-1; x<SIZE; x+=ROW) next[x] = 0;
//edge along x=0
for (int y=0; y<ROW; y++) next[y] = 0;
//edge along x=SIZE-ROW
for (int y=SIZE-ROW; y<SIZE; y++) next[y] = 0;
}
void generate_pgm(int *array, int *pgmidx) {
char filename[16];
sprintf(filename, "./frames/frame%03d.pgm", *pgmidx);
FILE *fd = fopen(filename, "wb+);
fprintf(fd, "P5\n%d %d\n255\n", ROW, COL);
for (int i=0; i<SIZE; i++) {
int temp = 0x7f + mulf(0x7f, array[i]);
if(temp > 0xff) temp = 0xff;
if(temp < 0) temp = 0;
fputc(temp, fd);
}
*pgmidx = *pgmidx + 1;
fclose(fd);
}
Now finally in the next page, we're gonna put everything together!