|
@ -4,8 +4,7 @@ |
|
|
#include <pngconf.h> |
|
|
#include <pngconf.h> |
|
|
#include <cairo.h> |
|
|
#include <cairo.h> |
|
|
#include <stdlib.h> |
|
|
#include <stdlib.h> |
|
|
|
|
|
#include "closure.h" |
|
|
#pragma once |
|
|
|
|
|
|
|
|
|
|
|
#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) |
|
|
#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) |
|
|
#define likely(expr) (__builtin_expect (!!(expr), 1)) |
|
|
#define likely(expr) (__builtin_expect (!!(expr), 1)) |
|
@ -16,7 +15,139 @@ |
|
|
#endif |
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 pngtest_flush(png_structp png_ptr) { |
|
|
|
|
|
// fprintf(stderr, "Pngtest_flush called");
|
|
|
/* Do nothing; fflush() is said to be just a waste of energy. */ |
|
|
/* Do nothing; fflush() is said to be just a waste of energy. */ |
|
|
(void) png_ptr; /* Stifle compiler warning */ |
|
|
(void) png_ptr; /* Stifle compiler warning */ |
|
|
} |
|
|
} |
|
@ -60,6 +191,11 @@ static void unpremultiply_data(png_structp png, png_row_infop row_info, png_byte |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
struct png_write_closure_t { |
|
|
|
|
|
cairo_write_func_t write_func; |
|
|
|
|
|
void *closure; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
static cairo_status_t canvas_write_png(cairo_surface_t *surface, png_rw_ptr write_func, void *closure) { |
|
|
static cairo_status_t canvas_write_png(cairo_surface_t *surface, png_rw_ptr write_func, void *closure) { |
|
|
unsigned int i; |
|
|
unsigned int i; |
|
|
cairo_status_t status = CAIRO_STATUS_SUCCESS; |
|
|
cairo_status_t status = CAIRO_STATUS_SUCCESS; |
|
@ -97,7 +233,8 @@ static cairo_status_t canvas_write_png(cairo_surface_t *surface, png_rw_ptr writ |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#ifdef PNG_USER_MEM_SUPPORTED |
|
|
#ifdef PNG_USER_MEM_SUPPORTED |
|
|
png = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL, NULL, NULL, NULL); |
|
|
// 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 |
|
|
#else |
|
|
png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); |
|
|
png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); |
|
|
#endif |
|
|
#endif |
|
@ -126,6 +263,9 @@ static cairo_status_t canvas_write_png(cairo_surface_t *surface, png_rw_ptr writ |
|
|
#endif |
|
|
#endif |
|
|
|
|
|
|
|
|
png_set_write_fn(png, closure, write_func, pngtest_flush); |
|
|
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); |
|
|
|
|
|
|
|
|
switch (cairo_image_surface_get_format(surface)) { |
|
|
switch (cairo_image_surface_get_format(surface)) { |
|
|
case CAIRO_FORMAT_ARGB32: |
|
|
case CAIRO_FORMAT_ARGB32: |
|
@ -178,19 +318,14 @@ static cairo_status_t canvas_write_png(cairo_surface_t *surface, png_rw_ptr writ |
|
|
png_set_filler(png, 0, PNG_FILLER_AFTER); |
|
|
png_set_filler(png, 0, PNG_FILLER_AFTER); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
png_write_image (png, rows); |
|
|
png_write_image(png, rows); |
|
|
png_write_end (png, info); |
|
|
png_write_end(png, info); |
|
|
|
|
|
|
|
|
png_destroy_write_struct (&png, &info); |
|
|
png_destroy_write_struct(&png, &info); |
|
|
free(rows); |
|
|
free(rows); |
|
|
return status; |
|
|
return status; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
struct png_write_closure_t { |
|
|
|
|
|
cairo_write_func_t write_func; |
|
|
|
|
|
void *closure; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
static void stream_write_func(png_structp png, png_bytep data, png_size_t size) { |
|
|
static void stream_write_func(png_structp png, png_bytep data, png_size_t size) { |
|
|
cairo_status_t status; |
|
|
cairo_status_t status; |
|
|
struct png_write_closure_t *png_closure; |
|
|
struct png_write_closure_t *png_closure; |
|
@ -213,10 +348,6 @@ static cairo_status_t canvas_write_to_png_stream(cairo_surface_t *surface, cairo |
|
|
return cairo_surface_status(surface); |
|
|
return cairo_surface_status(surface); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// if (surface->finished) {
|
|
|
|
|
|
// return CAIRO_STATUS_SURFACE_FINISHED;
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
png_closure.write_func = write_func; |
|
|
png_closure.write_func = write_func; |
|
|
png_closure.closure = closure; |
|
|
png_closure.closure = closure; |
|
|
|
|
|
|
|
|