From 8085395acc28d8c77901615f8862ceeda5773b09 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Sat, 4 Jul 2009 21:53:55 +0000 Subject: New interface for optimizing canvas conversions by registering dmnsn_set_pixel() callbacks. --- libdimension/png.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 96 insertions(+), 2 deletions(-) (limited to 'libdimension/png.c') diff --git a/libdimension/png.c b/libdimension/png.c index 6bb1f13..c8ffc62 100644 --- a/libdimension/png.c +++ b/libdimension/png.c @@ -24,6 +24,82 @@ #include #include #include +#include + +/* PNG optimizer callback */ +static void dmnsn_png_optimizer_fn(dmnsn_canvas *canvas, + dmnsn_canvas_optimizer optimizer, + unsigned int x, unsigned int y); + +/* Optimize canvas for PNG exporting */ +int +dmnsn_png_optimize_canvas(dmnsn_canvas *canvas) +{ + dmnsn_canvas_optimizer optimizer; + unsigned int i; + + /* Check if we've already optimized this canvas */ + for (i = 0; i < dmnsn_array_size(canvas->optimizers); ++i) { + dmnsn_array_get(canvas->optimizers, i, &optimizer); + if (optimizer.optimizer_fn == &dmnsn_png_optimizer_fn) { + return 0; + } + } + + optimizer.optimizer_fn = &dmnsn_png_optimizer_fn; + optimizer.free_fn = &free; + + optimizer.ptr = malloc(4*canvas->x*canvas->y*sizeof(uint16_t)); + if (!optimizer.ptr) { + return 1; + } + + dmnsn_optimize_canvas(canvas, optimizer); + + return 0; +} + +/* PNG optimizer callback */ +static void +dmnsn_png_optimizer_fn(dmnsn_canvas *canvas, dmnsn_canvas_optimizer optimizer, + unsigned int x, unsigned int y) +{ + dmnsn_color color; + dmnsn_sRGB sRGB; + uint16_t *pixel = (uint16_t *)optimizer.ptr + 4*(y*canvas->x + x); + + color = dmnsn_get_pixel(canvas, x, y); + sRGB = dmnsn_sRGB_from_color(color); + + /* Saturate R, G, and B to [0, UINT16_MAX] */ + + if (sRGB.R <= 0.0) { + pixel[0] = 0; + } else if (sRGB.R >= 1.0) { + pixel[0] = UINT16_MAX; + } else { + pixel[0] = sRGB.R*UINT16_MAX; + } + + if (sRGB.G <= 0.0) { + pixel[1] = 0; + } else if (sRGB.G >= 1.0) { + pixel[1] = UINT16_MAX; + } else { + pixel[1] = sRGB.G*UINT16_MAX; + } + + if (sRGB.B <= 0.0) { + pixel[2] = 0; + } else if (sRGB.B >= 1.0) { + pixel[2] = UINT16_MAX; + } else { + pixel[2] = sRGB.B*UINT16_MAX; + } + + /* color.filter + color.trans is in [0.0, 1.0] by definition */ + pixel[3] = (color.filter + color.trans)*UINT16_MAX; +} /* Payload to store function arguments for thread callbacks */ @@ -154,7 +230,7 @@ dmnsn_png_read_canvas_thread(void *ptr) if (retval) { *payload->canvas = dmnsn_png_read_canvas_impl(payload->progress, payload->file); - *retval = payload->canvas ? 0 : 1; /* Fail if it returned NULL */ + *retval = *payload->canvas ? 0 : 1; /* Fail if it returned NULL */ } dmnsn_done_progress(payload->progress); free(payload); @@ -166,10 +242,11 @@ static int dmnsn_png_write_canvas_impl(dmnsn_progress *progress, const dmnsn_canvas *canvas, FILE *file) { + dmnsn_canvas_optimizer optimizer; png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; - unsigned int x, y; + unsigned int i, x, y; uint16_t *row = NULL; dmnsn_color color; dmnsn_sRGB sRGB; @@ -219,6 +296,23 @@ dmnsn_png_write_canvas_impl(dmnsn_progress *progress, png_set_swap(png_ptr); } + /* Check if we can optimize this */ + for (i = 0; i < dmnsn_array_size(canvas->optimizers); ++i) { + dmnsn_array_get(canvas->optimizers, i, &optimizer); + if (optimizer.optimizer_fn == &dmnsn_png_optimizer_fn) { + for (y = 0; y < height; ++y) { + png_write_row(png_ptr, + (png_bytep)((uint16_t *)optimizer.ptr + 4*y*width)); + dmnsn_increment_progress(progress); + } + + /* Finish the PNG file */ + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); + return 0; + } + } + /* Allocate the temporary row of RGBA values */ row = malloc(4*sizeof(uint16_t)*width); if (!row) { -- cgit v1.2.3