diff --git a/src/Canvas.h b/src/Canvas.h index 3cc83e3..e4bce77 100644 --- a/src/Canvas.h +++ b/src/Canvas.h @@ -60,6 +60,8 @@ class Canvas: public node::ObjectWrap { static Handle StreamPNGSync(const Arguments &args); static Local Error(cairo_status_t status); inline cairo_surface_t *surface(){ return _surface; } + inline uint8_t *data(){ return cairo_image_surface_get_data(_surface); } + inline int stride(){ return cairo_image_surface_get_stride(_surface); } Canvas(int width, int height); void resurface(); diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index 3a5ca8f..5a2f92c 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -9,6 +9,7 @@ #include #include #include "Canvas.h" +#include "Image.h" #include "CanvasRenderingContext2d.h" #include "CanvasGradient.h" @@ -66,6 +67,7 @@ Context2d::Initialize(Handle target) { // Prototype Local proto = t->PrototypeTemplate(); + NODE_SET_PROTOTYPE_METHOD(t, "drawImage", DrawImage); NODE_SET_PROTOTYPE_METHOD(t, "save", Save); NODE_SET_PROTOTYPE_METHOD(t, "restore", Restore); NODE_SET_PROTOTYPE_METHOD(t, "rotate", Rotate); @@ -112,19 +114,6 @@ Context2d::Initialize(Handle target) { target->Set(String::NewSymbol("CanvasRenderingContext2d"), t->GetFunction()); } -/* - * Initialize a new Context2d with the given canvas. - */ - -Handle -Context2d::New(const Arguments &args) { - HandleScope scope; - Canvas *canvas = ObjectWrap::Unwrap(args[0]->ToObject()); - Context2d *context = new Context2d(canvas); - context->Wrap(args.This()); - return args.This(); -} - /* * Create a cairo context. */ @@ -382,6 +371,109 @@ Context2d::blur(cairo_surface_t *surface, int radius) { free( precalc ); } +/* + * Initialize a new Context2d with the given canvas. + */ + +Handle +Context2d::New(const Arguments &args) { + HandleScope scope; + Canvas *canvas = ObjectWrap::Unwrap(args[0]->ToObject()); + Context2d *context = new Context2d(canvas); + context->Wrap(args.This()); + return args.This(); +} + +/* + * Draw image src image to the destination (context). + * + * - dx, dy + * - dx, dy, dw, dh + * - sx, sy, sw, sh, dx, dy, dw, dh + * + */ + +Handle +Context2d::DrawImage(const Arguments &args) { + HandleScope scope; + + if (args.Length() < 3) + return ThrowException(Exception::TypeError(String::New("invalid arguments"))); + + // TODO: instanceof + // TODO: arg handling / boundaries + Image *img = ObjectWrap::Unwrap(args[0]->ToObject()); + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + + int sx = 0 + , sy = 0 + , sw = img->width + , sh = img->height + , dx, dy, dw, dh; + + // Arguments + switch (args.Length()) { + // img, sx, sy, sw, sh, dx, dy, dw, dh + case 9: + sx = args[1]->NumberValue(); + sy = args[2]->NumberValue(); + sw = args[3]->NumberValue(); + sh = args[4]->NumberValue(); + dx = args[5]->NumberValue(); + dy = args[6]->NumberValue(); + dw = args[7]->NumberValue(); + dh = args[8]->NumberValue(); + break; + // img, dx, dy, dw, dh + case 5: + dx = args[1]->NumberValue(); + dy = args[2]->NumberValue(); + dw = args[3]->NumberValue(); + dh = args[4]->NumberValue(); + break; + // img, dx, dy + case 3: + dx = args[1]->NumberValue(); + dy = args[2]->NumberValue(); + dw = img->width; + dh = img->height; + break; + default: + // TODO: throw + return ThrowException(Exception::TypeError(String::New("invalid arguments"))); + } + + // Start draw + cairo_save(ctx); + + // Source surface + cairo_surface_t *src = cairo_surface_create_for_rectangle( + img->surface() + , sx + , sy + , sw + , sh); + + // Scale src + if (dw != sw || dh != sh) { + double fx = (double) dw / sw; + double fy = (double) dh / sh; + cairo_scale(ctx, fx, fy); + dx /= fx; + dy /= fy; + } + + // Paint + cairo_set_source_surface(ctx, src, dx, dy); + cairo_paint_with_alpha(ctx, context->state->globalAlpha); + + cairo_restore(ctx); + cairo_surface_destroy(src); + + return Undefined(); +} + /* * Get global alpha. */ diff --git a/src/CanvasRenderingContext2d.h b/src/CanvasRenderingContext2d.h index be85cb3..f8f413b 100644 --- a/src/CanvasRenderingContext2d.h +++ b/src/CanvasRenderingContext2d.h @@ -47,6 +47,7 @@ class Context2d: public node::ObjectWrap { canvas_state_t *state; static void Initialize(Handle target); static Handle New(const Arguments &args); + static Handle DrawImage(const Arguments &args); static Handle Save(const Arguments &args); static Handle Restore(const Arguments &args); static Handle Rotate(const Arguments &args); diff --git a/src/Image.h b/src/Image.h index 24ff841..f20dd49 100644 --- a/src/Image.h +++ b/src/Image.h @@ -31,6 +31,8 @@ class Image: public node::ObjectWrap { static void SetOnload(Local prop, Local val, const AccessorInfo &info); static void SetOnerror(Local prop, Local val, const AccessorInfo &info); inline cairo_surface_t *surface(){ return _surface; } + inline uint8_t *data(){ return cairo_image_surface_get_data(_surface); } + inline int stride(){ return cairo_image_surface_get_stride(_surface); } cairo_status_t loadSurface(); void error(Local); void loaded();