9. Writing a PNG file

PNG files are written to disk using the very portable lodepng library, included with monolith.

<<gfx_aux_includes>>=
#include "lodepng/lodepng.h"

A framebuffer is written to a PNG file using the function monolith_framebuffer_write_png.

<<gfx_function_declarations>>=
void monolith_framebuffer_write_png(monolith_framebuffer *fb,
                                    const char *filename);

Pixels are copied to a an allocated "zoom buffer", which is then written to a PNG file via lodepng. This is done regardless of whether or not there a zoom because it also ensures proper byte order.

<<gfx_functions>>=
void monolith_framebuffer_write_png(monolith_framebuffer *fb,
                                    const char *filename)
{
    unsigned char *zbuf;
    unsigned int x, y, xi, yi;
    unsigned int pos;
    unsigned int pos_zoom;
    unsigned int zoom;
    monolith_pixel *pix;

    zbuf = NULL;
    if(fb == NULL) return;

    zoom = monolith_framebuffer_zoom_get(fb);

    zbuf = calloc(1, 4 * monolith_gfx_width(fb) *
                    zoom * monolith_gfx_height(fb) * zoom);
    pix = monolith_framebuffer_pix(fb);

    for(y = 0; y < monolith_gfx_height(fb); y++) {
        for(x = 0; x < monolith_gfx_width(fb); x++) {
            pos = y * monolith_gfx_width(fb) + x;
            for(yi = 0; yi < zoom; yi++) {
                for(xi = 0; xi < zoom; xi++) {
                    pos_zoom =
                        y * zoom * monolith_gfx_width(fb) * zoom +
                        x * zoom +
                        yi * monolith_gfx_width(fb) * zoom +
                        xi;
                    pos_zoom *= 4;
                    zbuf[pos_zoom] = pix[pos].r;
                    zbuf[pos_zoom + 1] = pix[pos].g;
                    zbuf[pos_zoom + 2] = pix[pos].b;
                    zbuf[pos_zoom + 3] = pix[pos].a;
                }
            }
        }
    }
    lodepng_encode32_file(filename,
                            zbuf,
                            monolith_gfx_width(fb) * zoom,
                            monolith_gfx_height(fb) * zoom);
    if(zbuf != NULL) free(zbuf);
}

This function can be called using the function monolith:gfx-write-png. It will use the global monolith framebuffer, if it exists.

<<gfx_scheme_entries>>=
{"monolith:gfx-write-png", pp_write_png, 1, 1, {STR,___,___}},
<<gfx_scheme_functions>>=
static cell pp_write_png(cell p)
{
    monolith_d *m;
    monolith_framebuffer *fb;
    const char *filename;
    m = monolith_data_get();
    filename = string(car(p));

    fb = monolith_fb_get(m);
    monolith_framebuffer_write_png(fb, filename);
    return UNSPECIFIC;
}

Similar functionality is done with Janet using the function monolith/gfx-write-png.

<<gfx_janet>>=
static Janet j_gfx_write_png(int32_t argc, Janet *argv)
{
    monolith_framebuffer *fb;
    monolith_d *m;
    const char *filename;

    janet_fixarity(argc, 1);
    m = monolith_data_get();
    fb = monolith_fb_get(m);
    filename = (const char *)janet_unwrap_string(argv[0]);

    if(fb != NULL) {
        monolith_framebuffer_write_png(fb, filename);
    }

    return janet_wrap_nil();
}
<<gfx_janet_entries>>=
{
"monolith/gfx-write-png",
j_gfx_write_png,
"Writes framebuffer to disk."
},



prev | home | next