Browse Source

Cleaned up code and added the same fix to Canvas::StreamPngSync

v1.x
King Koopa 12 years ago
committed by TJ Holowaychuk
parent
commit
e2a5ed2b05
  1. 67
      src/Canvas.cc
  2. 159
      src/PNG.h

67
src/Canvas.cc

@ -236,15 +236,32 @@ NAN_METHOD(Canvas::ToBuffer) {
NanReturnValue(buf);
}
if (args.Length() == 2) {
if(args[1]->IsUint32()) {
compression_level = args[1]->Uint32Value();
if (compression_level > 9) {
return NanThrowRangeError("Allowed compression levels lie in the range [0, 9].");
}
} else {
return NanThrowTypeError("Compression level has to be an unsigned integer.");
}
if (args.Length() == 2 && !args[1]->StrictEquals(Undefined())) {
bool good = true;
if (args[1]->IsNumber()) {
compression_level = args[1]->Uint32Value();
} else if (args[1]->IsString()) {
if (args[1]->StrictEquals(String::New("0"))) {
compression_level = 0;
} else {
uint32_t tmp = args[1]->Uint32Value();
if (tmp == 0) {
good = false;
} else {
compression_level = tmp;
}
}
} else {
good = false;
}
if (good) {
if (compression_level > 9) {
return NanThrowRangeError("Allowed compression levels lie in the range [0, 9].");
}
} else {
return NanThrowTypeError("Compression level must be a number.");
}
}
// Async
@ -324,17 +341,47 @@ streamPNG(void *c, const uint8_t *data, unsigned len) {
NAN_METHOD(Canvas::StreamPNGSync) {
NanScope();
uint32_t compression_level = 6;
// TODO: async as well
if (!args[0]->IsFunction())
return NanThrowTypeError("callback function required");
if (args.Length() == 2 && !args[1]->StrictEquals(Undefined())) {
bool good = true;
if (args[1]->IsNumber()) {
compression_level = args[1]->Uint32Value();
} else if (args[1]->IsString()) {
if (args[1]->StrictEquals(String::New("0"))) {
compression_level = 0;
} else {
uint32_t tmp = args[1]->Uint32Value();
if (tmp == 0) {
good = false;
} else {
compression_level = tmp;
}
}
} else {
good = false;
}
if (good) {
if (compression_level > 9) {
return NanThrowRangeError("Allowed compression levels lie in the range [0, 9].");
}
} else {
return NanThrowTypeError("Compression level must be a number.");
}
}
Canvas *canvas = ObjectWrap::Unwrap<Canvas>(args.This());
closure_t closure;
closure.fn = Handle<Function>::Cast(args[0]);
closure.compression_level = compression_level;
TryCatch try_catch;
//TODO: use libpng directly
cairo_status_t status = canvas_write_to_png_stream(canvas->surface(), streamPNG, &closure);
if (try_catch.HasCaught()) {

159
src/PNG.h

@ -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

Loading…
Cancel
Save