terom@11: #include terom@11: terom@11: #include terom@11: terom@11: #include "common.h" terom@17: #include "render_struct.h" terom@17: #include "render_png_struct.h" terom@11: #include "render_png.h" terom@11: terom@11: terom@13: static void _render_png_write(png_structp png_ptr, png_bytep data, png_size_t length) { terom@11: struct render_png *ctx = png_get_io_ptr(png_ptr); terom@11: terom@13: if (ctx->io_write_fn) terom@13: if (ctx->io_write_fn(data, length, ctx->cb_arg)) { terom@11: // error, doesn't return terom@11: png_error(png_ptr, "_render_png_write: io_write_fn"); terom@11: } terom@11: } terom@11: terom@13: static void _render_png_flush(png_structp png_ptr) { terom@11: struct render_png *ctx = png_get_io_ptr(png_ptr); terom@11: terom@13: if (ctx->io_flush_fn) terom@13: if (ctx->io_flush_fn(ctx->cb_arg)) { terom@11: // error, doesn't return terom@11: png_error(png_ptr, "_render_png_flush: io_flush_fn"); terom@11: } terom@11: } terom@11: terom@13: static void _render_png_free (struct render_png *ctx) { terom@17: render_png_deinit(ctx); terom@17: terom@17: if (ctx->owned_by_me) terom@17: free(ctx); terom@11: } terom@11: terom@19: void render_png_deinit (struct render_png *ctx) { terom@19: // are we initialized? terom@19: if (ctx->png_ptr) { terom@19: // libpng error handling terom@19: if (setjmp(png_jmpbuf(ctx->png_ptr))) terom@19: ERROR("libpng"); terom@19: terom@19: png_destroy_write_struct(&ctx->png_ptr, &ctx->info_ptr); terom@19: } terom@11: terom@19: return; terom@11: terom@17: error: terom@19: WARNING("destroying our libpng structures failed, possible memory leak?"); terom@17: } terom@17: terom@17: /* terom@17: * Note that it's vitally important not to call any libpng functions directly, terom@17: * the error-handling setjmp will be invalid. terom@17: */ terom@17: terom@17: int render_png_init (struct render_png *ctx, struct render *render) { terom@13: // store some info from the struct render terom@13: ctx->io_write_fn = render->io_write_fn; terom@13: ctx->io_flush_fn = render->io_flush_fn; terom@13: ctx->cb_arg = render->cb_arg; terom@11: terom@11: // libpng initialization terom@11: if (!(ctx->png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) terom@11: ERROR("png_create_write_struct"); terom@11: terom@11: if (!(ctx->info_ptr = png_create_info_struct(ctx->png_ptr))) terom@11: ERROR("png_create_info_struct"); terom@11: terom@11: // libpng error handling terom@11: if (setjmp(png_jmpbuf(ctx->png_ptr))) terom@11: ERROR("libpng"); terom@11: terom@11: if (render->io_stream) { terom@11: // use normal libpng I/O terom@11: // XXX: who fcloses this? terom@11: png_init_io(ctx->png_ptr, render->io_stream); terom@11: } else { terom@11: // setup our custom I/O callbacks terom@11: png_set_write_fn(ctx->png_ptr, ctx, &_render_png_write, &_render_png_flush); terom@11: } terom@11: terom@11: // some PNG metadata terom@11: 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); terom@11: terom@11: // write out the PNG header terom@11: png_write_info(ctx->png_ptr, ctx->info_ptr); terom@17: terom@17: // success terom@17: return 0; terom@17: terom@17: error: terom@17: render_png_deinit(ctx); terom@17: return -1; terom@17: } terom@17: terom@17: struct render_png *render_png_alloc (struct render *render) { terom@17: struct render_png *ctx = NULL; terom@17: terom@17: // calloc the render_png terom@17: if (!(ctx = calloc(1, sizeof(struct render_png)))) terom@17: ERROR("calloc"); terom@17: terom@17: // I need to free it terom@17: ctx->owned_by_me = 1; terom@17: terom@17: // init it terom@17: if (render_png_init(ctx, render)) terom@17: goto error; terom@11: terom@11: // success terom@11: return ctx; terom@11: terom@11: error: terom@11: _render_png_free(ctx); terom@11: return NULL; terom@11: } terom@11: terom@11: int render_png_row (struct render_png *ctx, unsigned char *rowbuf) { terom@11: // libpng error handling terom@11: if (setjmp(png_jmpbuf(ctx->png_ptr))) terom@11: ERROR("libpng"); terom@11: terom@11: // write it in terom@11: png_write_row(ctx->png_ptr, rowbuf); terom@11: terom@11: // success terom@11: return 0; terom@11: terom@11: error: terom@15: // don't free it here, our user needs to do that terom@11: return -1; terom@11: } terom@11: terom@11: int render_png_done (struct render_png *ctx) { terom@11: // libpng error handling terom@11: if (setjmp(png_jmpbuf(ctx->png_ptr))) terom@11: ERROR("libpng"); terom@11: terom@11: // write end terom@11: png_write_end(ctx->png_ptr, ctx->info_ptr); terom@13: terom@13: // free everything terom@13: _render_png_free(ctx); terom@11: terom@11: // success terom@11: return 0; terom@11: terom@11: error: terom@11: _render_png_free(ctx); terom@11: return -1; terom@11: } terom@11: terom@11: int render_png_abort (struct render_png *ctx) { terom@13: // just free it terom@11: _render_png_free(ctx); terom@11: terom@11: // success terom@11: return 0; terom@11: } terom@11: