Browse Source

Added compression level argument to Canvas::toBuffer

v1.x
King Koopa 12 years ago
committed by TJ Holowaychuk
parent
commit
50d0c5c55f
  1. 20
      src/Canvas.cc
  2. 161
      src/PNG.h
  3. 4
      src/closure.h

20
src/Canvas.cc

@ -166,7 +166,7 @@ Canvas::EIO_ToBuffer(eio_req *req) {
#endif
closure_t *closure = (closure_t *) req->data;
closure->status = cairo_surface_write_to_png_stream(
closure->status = canvas_write_to_png_stream(
closure->canvas->surface()
, toBuffer
, closure);
@ -224,6 +224,7 @@ Canvas::EIO_AfterToBuffer(eio_req *req) {
NAN_METHOD(Canvas::ToBuffer) {
NanScope();
cairo_status_t status;
uint32_t compression_level = 6;
Canvas *canvas = ObjectWrap::Unwrap<Canvas>(args.This());
// TODO: async / move this out
@ -235,10 +236,21 @@ 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.");
}
}
// Async
if (args[0]->IsFunction()) {
closure_t *closure = (closure_t *) malloc(sizeof(closure_t));
status = closure_init(closure, canvas);
status = closure_init(closure, canvas, compression_level);
// ensure closure is ok
if (status) {
@ -264,7 +276,7 @@ NAN_METHOD(Canvas::ToBuffer) {
// Sync
} else {
closure_t closure;
status = closure_init(&closure, canvas);
status = closure_init(&closure, canvas, compression_level);
// ensure closure is ok
if (status) {
@ -384,7 +396,7 @@ Canvas::Canvas(int w, int h, canvas_type_t t): ObjectWrap() {
if (CANVAS_TYPE_PDF == t) {
_closure = malloc(sizeof(closure_t));
assert(_closure);
cairo_status_t status = closure_init((closure_t *) _closure, this);
cairo_status_t status = closure_init((closure_t *) _closure, this, 0);
assert(status == CAIRO_STATUS_SUCCESS);
_surface = cairo_pdf_surface_create_for_stream(toBuffer, _closure, w, h);
} else {

161
src/PNG.h

@ -4,8 +4,7 @@
#include <pngconf.h>
#include <cairo.h>
#include <stdlib.h>
#pragma once
#include "closure.h"
#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
#define likely(expr) (__builtin_expect (!!(expr), 1))
@ -16,7 +15,139 @@
#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) {
// fprintf(stderr, "Pngtest_flush called");
/* Do nothing; fflush() is said to be just a waste of energy. */
(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) {
unsigned int i;
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
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
png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
#endif
@ -126,6 +263,9 @@ 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);
switch (cairo_image_surface_get_format(surface)) {
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_write_image (png, rows);
png_write_end (png, info);
png_write_image(png, rows);
png_write_end(png, info);
png_destroy_write_struct (&png, &info);
png_destroy_write_struct(&png, &info);
free(rows);
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) {
cairo_status_t status;
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);
}
// if (surface->finished) {
// return CAIRO_STATUS_SURFACE_FINISHED;
// }
png_closure.write_func = write_func;
png_closure.closure = closure;

4
src/closure.h

@ -30,6 +30,7 @@ typedef struct {
uint8_t *data;
Canvas *canvas;
cairo_status_t status;
unsigned int compression_level;
} closure_t;
/*
@ -37,11 +38,12 @@ typedef struct {
*/
cairo_status_t
closure_init(closure_t *closure, Canvas *canvas) {
closure_init(closure_t *closure, Canvas *canvas, unsigned int compression_level) {
closure->len = 0;
closure->canvas = canvas;
closure->data = (uint8_t *) malloc(closure->max_len = PAGE_SIZE);
if (!closure->data) return CAIRO_STATUS_NO_MEMORY;
closure->compression_level = compression_level;
return CAIRO_STATUS_SUCCESS;
}

Loading…
Cancel
Save