render_png.c
author Tero Marttila <terom@fixme.fi>
Sat, 07 Jun 2008 05:05:18 +0300
changeset 13 ee426f453cf5
parent 11 082bfaf38cf0
child 15 e7f0697814dc
permissions -rw-r--r--
* fix some (of the) stupid things in Makefile
* increment remote_node->current_load in remote_pool_get
* re-add render_init
* add render_raw module to handle non-PNG rendering
* update render_local to support RENDER_RAW
* working (but limited and inefficient) implementation of render_multi
* fixes to render_png
* improve/clean up render_remote
* mark internal function static
* make web_main use render_multi
* random bugfixes (possibly due to vim acting weird re file recovery post-crash)

committer: Tero Marttila <terom@fixme.fi>
#include <stdlib.h>

#include <png.h>

#include "common.h"
#include "render_internal.h"
#include "render_png.h"

struct render_png {
    // libpng handles
    png_structp png_ptr;
    png_infop info_ptr;

    // some info that we need to keep from the struct render
    render_ctx_write_cb io_write_fn;
    render_ctx_flush_cb io_flush_fn;
    void *cb_arg;
};

static void _render_png_write(png_structp png_ptr, png_bytep data, png_size_t length) {
    struct render_png *ctx = png_get_io_ptr(png_ptr);

    if (ctx->io_write_fn)
        if (ctx->io_write_fn(data, length, ctx->cb_arg)) {
            // error, doesn't return
            png_error(png_ptr, "_render_png_write: io_write_fn");
        }
}

static void _render_png_flush(png_structp png_ptr) {
    struct render_png *ctx = png_get_io_ptr(png_ptr);
    
    if (ctx->io_flush_fn)
        if (ctx->io_flush_fn(ctx->cb_arg)) {
            // error, doesn't return
            png_error(png_ptr, "_render_png_flush: io_flush_fn");
        }
}

static void _render_png_free (struct render_png *ctx) {
    if (ctx)
        png_destroy_write_struct(&ctx->png_ptr, &ctx->info_ptr);

    free(ctx);
}


struct render_png *render_png_init (struct render *render) {

    struct render_png *ctx = NULL;

    // calloc the render_png
    if (!(ctx = calloc(1, sizeof(struct render_png))))
        ERROR("calloc");

    // store some info from the struct render
    ctx->io_write_fn = render->io_write_fn;
    ctx->io_flush_fn = render->io_flush_fn;
    ctx->cb_arg = render->cb_arg;

    // libpng initialization
    if (!(ctx->png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)))
        ERROR("png_create_write_struct");

    if (!(ctx->info_ptr = png_create_info_struct(ctx->png_ptr)))
        ERROR("png_create_info_struct");

    // libpng error handling
    if (setjmp(png_jmpbuf(ctx->png_ptr)))
        ERROR("libpng");
    
    if (render->io_stream) {
        // use normal libpng I/O
        // XXX: who fcloses this?
        png_init_io(ctx->png_ptr, render->io_stream);
    } else {
        // setup our custom I/O callbacks
        png_set_write_fn(ctx->png_ptr, ctx, &_render_png_write, &_render_png_flush);
    }

    // some PNG metadata
    png_set_IHDR(ctx->png_ptr, ctx->info_ptr, render->img_w, render->img_h, 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

    // write out the PNG header
    png_write_info(ctx->png_ptr, ctx->info_ptr);

    // success
    return ctx;

error:
    _render_png_free(ctx);
    return NULL;
}

int render_png_row (struct render_png *ctx, unsigned char *rowbuf) {
    // libpng error handling
    if (setjmp(png_jmpbuf(ctx->png_ptr)))
        ERROR("libpng");

    // write it in
    png_write_row(ctx->png_ptr, rowbuf);

    // success
    return 0;

error:
    _render_png_free(ctx);
    return -1;
}

int render_png_done (struct render_png *ctx) {
    // libpng error handling
    if (setjmp(png_jmpbuf(ctx->png_ptr)))
        ERROR("libpng");

    // write end
    png_write_end(ctx->png_ptr, ctx->info_ptr);
    
    // free everything
    _render_png_free(ctx);

    // success
    return 0;

error:
    _render_png_free(ctx);
    return -1;
}

int render_png_abort (struct render_png *ctx) {
    // libpng error handling
    if (setjmp(png_jmpbuf(ctx->png_ptr)))
        ERROR("libpng");
    
    // just free it
    _render_png_free(ctx);

    // success
    return 0;

error:
    return -1;
}