|
|
@ -16,144 +16,14 @@ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef png_size_t png_alloc_size_t; |
|
|
|
|
|
|
|
/* Allocate memory. For reasonable files, size should never exceed
|
|
|
|
* 64K. However, zlib may allocate more then 64K if you don't tell |
|
|
|
* it not to. See zconf.h and png.h for more information. zlib does |
|
|
|
* need to allocate exactly 64K, so whatever you call here must |
|
|
|
* have the ability to do that. |
|
|
|
* |
|
|
|
* This piece of code can be compiled to validate max 64K allocations |
|
|
|
* by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K. |
|
|
|
*/ |
|
|
|
typedef struct memory_information |
|
|
|
{ |
|
|
|
png_alloc_size_t size; |
|
|
|
png_voidp pointer; |
|
|
|
struct memory_information *next; |
|
|
|
} memory_information; |
|
|
|
typedef memory_information *memory_infop; |
|
|
|
|
|
|
|
static memory_infop pinformation = NULL; |
|
|
|
static int current_allocation = 0; |
|
|
|
static int maximum_allocation = 0; |
|
|
|
static int total_allocation = 0; |
|
|
|
static int num_allocations = 0; |
|
|
|
|
|
|
|
png_voidp png_debug_malloc PNGARG((png_structp png_ptr,png_alloc_size_t size)); |
|
|
|
static void png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr)); |
|
|
|
|
|
|
|
png_voidp png_debug_malloc(png_structp png_ptr, png_alloc_size_t size) { |
|
|
|
/* png_malloc has already tested for NULL; png_create_struct calls
|
|
|
|
* png_debug_malloc directly, with png_ptr == NULL which is OK |
|
|
|
*/ |
|
|
|
|
|
|
|
if (size == 0) |
|
|
|
return (NULL); |
|
|
|
|
|
|
|
/* This calls the library allocator twice, once to get the requested
|
|
|
|
buffer and once to get a new free list entry. */ |
|
|
|
{ |
|
|
|
/* Disable malloc_fn and free_fn */ |
|
|
|
memory_infop pinfo; |
|
|
|
png_set_mem_fn(png_ptr, NULL, NULL, NULL); |
|
|
|
pinfo = (memory_infop)png_malloc(png_ptr, |
|
|
|
(sizeof *pinfo)); |
|
|
|
pinfo->size = size; |
|
|
|
current_allocation += size; |
|
|
|
total_allocation += size; |
|
|
|
num_allocations ++; |
|
|
|
|
|
|
|
if (current_allocation > maximum_allocation) { |
|
|
|
maximum_allocation = current_allocation; |
|
|
|
} |
|
|
|
|
|
|
|
pinfo->pointer = png_malloc(png_ptr, size); |
|
|
|
/* Restore malloc_fn and free_fn */ |
|
|
|
|
|
|
|
png_set_mem_fn(png_ptr, |
|
|
|
NULL, png_debug_malloc, png_debug_free); |
|
|
|
|
|
|
|
if (size != 0 && pinfo->pointer == NULL) { |
|
|
|
current_allocation -= size; |
|
|
|
total_allocation -= size; |
|
|
|
png_error(png_ptr, |
|
|
|
"out of memory in pngtest->png_debug_malloc"); |
|
|
|
} |
|
|
|
|
|
|
|
pinfo->next = pinformation; |
|
|
|
pinformation = pinfo; |
|
|
|
/* Make sure the caller isn't assuming zeroed memory. */ |
|
|
|
memset(pinfo->pointer, 0xdd, pinfo->size); |
|
|
|
|
|
|
|
printf("png_malloc %lu bytes at %p\n", (unsigned long)size, |
|
|
|
pinfo->pointer); |
|
|
|
|
|
|
|
return (png_voidp)(pinfo->pointer); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* Free a pointer. It is removed from the list at the same time. */ |
|
|
|
static void png_debug_free(png_structp png_ptr, png_voidp ptr) { |
|
|
|
if (png_ptr == NULL) |
|
|
|
fprintf(stderr, "NULL pointer to png_debug_free.\n"); |
|
|
|
|
|
|
|
if (ptr == 0) |
|
|
|
{ |
|
|
|
#if 0 /* This happens all the time. */
|
|
|
|
fprintf(stderr, "WARNING: freeing NULL pointer\n"); |
|
|
|
#endif |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
/* Unlink the element from the list. */ |
|
|
|
{ |
|
|
|
memory_infop *ppinfo = &pinformation; |
|
|
|
|
|
|
|
for (;;) |
|
|
|
{ |
|
|
|
memory_infop pinfo = *ppinfo; |
|
|
|
|
|
|
|
if (pinfo->pointer == ptr) |
|
|
|
{ |
|
|
|
*ppinfo = pinfo->next; |
|
|
|
current_allocation -= pinfo->size; |
|
|
|
if (current_allocation < 0) |
|
|
|
fprintf(stderr, "Duplicate free of memory\n"); |
|
|
|
/* We must free the list element too, but first kill
|
|
|
|
the memory that is to be freed. */ |
|
|
|
memset(ptr, 0x55, pinfo->size); |
|
|
|
png_free_default(png_ptr, pinfo); |
|
|
|
pinfo = NULL; |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
if (pinfo->next == NULL) |
|
|
|
{ |
|
|
|
fprintf(stderr, "Pointer %p not found\n", ptr); |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
ppinfo = &pinfo->next; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* Finally free the data. */ |
|
|
|
printf("Freeing %p\n", ptr); |
|
|
|
|
|
|
|
png_free_default(png_ptr, ptr); |
|
|
|
ptr = NULL; |
|
|
|
} |
|
|
|
|
|
|
|
static void pngtest_flush(png_structp png_ptr) { |
|
|
|
static void canvas_png_flush(png_structp png_ptr) { |
|
|
|
// fprintf(stderr, "Pngtest_flush called");
|
|
|
|
/* Do nothing; fflush() is said to be just a waste of energy. */ |
|
|
|
(void) png_ptr; /* Stifle compiler warning */ |
|
|
|
} |
|
|
|
|
|
|
|
/* Converts native endian xRGB => RGBx bytes */ |
|
|
|
static void convert_data_to_bytes (png_structp png, png_row_infop row_info, png_bytep data) { |
|
|
|
static void canvas_convert_data_to_bytes (png_structp png, png_row_infop row_info, png_bytep data) { |
|
|
|
unsigned int i; |
|
|
|
|
|
|
|
for (i = 0; i < row_info->rowbytes; i += 4) { |
|
|
@ -170,7 +40,7 @@ static void convert_data_to_bytes (png_structp png, png_row_infop row_info, png_ |
|
|
|
} |
|
|
|
|
|
|
|
/* Unpremultiplies data and converts native endian ARGB => RGBA bytes */ |
|
|
|
static void unpremultiply_data(png_structp png, png_row_infop row_info, png_bytep data) { |
|
|
|
static void canvas_unpremultiply_data(png_structp png, png_row_infop row_info, png_bytep data) { |
|
|
|
unsigned int i; |
|
|
|
|
|
|
|
for (i = 0; i < row_info->rowbytes; i += 4) { |
|
|
@ -191,7 +61,7 @@ static void unpremultiply_data(png_structp png, png_row_infop row_info, png_byte |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
struct png_write_closure_t { |
|
|
|
struct canvas_png_write_closure_t { |
|
|
|
cairo_write_func_t write_func; |
|
|
|
void *closure; |
|
|
|
}; |
|
|
@ -233,7 +103,6 @@ static cairo_status_t canvas_write_png(cairo_surface_t *surface, png_rw_ptr writ |
|
|
|
} |
|
|
|
|
|
|
|
#ifdef PNG_USER_MEM_SUPPORTED |
|
|
|
// png = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL, NULL, png_debug_malloc, png_debug_free);
|
|
|
|
png = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL, NULL, NULL, NULL); |
|
|
|
#else |
|
|
|
png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); |
|
|
@ -262,10 +131,8 @@ static cairo_status_t canvas_write_png(cairo_surface_t *surface, png_rw_ptr writ |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
png_set_write_fn(png, closure, write_func, pngtest_flush); |
|
|
|
// png_set_flush(png, 100);
|
|
|
|
// png_set_compression_buffer_size(png, 1024*1024);
|
|
|
|
png_set_compression_level(png, ((closure_t *) ((png_write_closure_t *) closure)->closure)->compression_level); |
|
|
|
png_set_write_fn(png, closure, write_func, canvas_png_flush); |
|
|
|
png_set_compression_level(png, ((closure_t *) ((canvas_png_write_closure_t *) closure)->closure)->compression_level); |
|
|
|
|
|
|
|
switch (cairo_image_surface_get_format(surface)) { |
|
|
|
case CAIRO_FORMAT_ARGB32: |
|
|
@ -312,9 +179,9 @@ static cairo_status_t canvas_write_png(cairo_surface_t *surface, png_rw_ptr writ |
|
|
|
*/ |
|
|
|
png_write_info(png, info); |
|
|
|
if (png_color_type == PNG_COLOR_TYPE_RGB_ALPHA) { |
|
|
|
png_set_write_user_transform_fn(png, unpremultiply_data); |
|
|
|
png_set_write_user_transform_fn(png, canvas_unpremultiply_data); |
|
|
|
} else if (png_color_type == PNG_COLOR_TYPE_RGB) { |
|
|
|
png_set_write_user_transform_fn(png, convert_data_to_bytes); |
|
|
|
png_set_write_user_transform_fn(png, canvas_convert_data_to_bytes); |
|
|
|
png_set_filler(png, 0, PNG_FILLER_AFTER); |
|
|
|
} |
|
|
|
|
|
|
@ -326,11 +193,11 @@ static cairo_status_t canvas_write_png(cairo_surface_t *surface, png_rw_ptr writ |
|
|
|
return status; |
|
|
|
} |
|
|
|
|
|
|
|
static void stream_write_func(png_structp png, png_bytep data, png_size_t size) { |
|
|
|
static void canvas_stream_write_func(png_structp png, png_bytep data, png_size_t size) { |
|
|
|
cairo_status_t status; |
|
|
|
struct png_write_closure_t *png_closure; |
|
|
|
struct canvas_png_write_closure_t *png_closure; |
|
|
|
|
|
|
|
png_closure = (struct png_write_closure_t *) png_get_io_ptr(png); |
|
|
|
png_closure = (struct canvas_png_write_closure_t *) png_get_io_ptr(png); |
|
|
|
status = png_closure->write_func(png_closure->closure, data, size); |
|
|
|
if (unlikely(status)) { |
|
|
|
cairo_status_t *error = (cairo_status_t *) png_get_error_ptr(png); |
|
|
@ -342,7 +209,7 @@ static void stream_write_func(png_structp png, png_bytep data, png_size_t size) |
|
|
|
} |
|
|
|
|
|
|
|
static cairo_status_t canvas_write_to_png_stream(cairo_surface_t *surface, cairo_write_func_t write_func, void *closure) { |
|
|
|
struct png_write_closure_t png_closure; |
|
|
|
struct canvas_png_write_closure_t png_closure; |
|
|
|
|
|
|
|
if (cairo_surface_status(surface)) { |
|
|
|
return cairo_surface_status(surface); |
|
|
@ -351,6 +218,6 @@ static cairo_status_t canvas_write_to_png_stream(cairo_surface_t *surface, cairo |
|
|
|
png_closure.write_func = write_func; |
|
|
|
png_closure.closure = closure; |
|
|
|
|
|
|
|
return canvas_write_png(surface, stream_write_func, &png_closure); |
|
|
|
return canvas_write_png(surface, canvas_stream_write_func, &png_closure); |
|
|
|
} |
|
|
|
#endif |
|
|
|