From 79f1d42fb5df5e75667acf6950b53d13e8f78a13 Mon Sep 17 00:00:00 2001 From: Thaddee Tyl Date: Fri, 29 Aug 2014 08:56:57 +0200 Subject: [PATCH] Offer SVG output. --- .gitignore | 1 + Readme.md | 11 +++++++++++ examples/small-svg.js | 22 ++++++++++++++++++++++ src/Canvas.cc | 37 +++++++++++++++++++++++++++++++++---- src/Canvas.h | 4 +++- test/canvas.test.js | 2 ++ 6 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 examples/small-svg.js diff --git a/.gitignore b/.gitignore index 6e9fcd3..1308944 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ examples/*.jpg testing out.png out.pdf +out.svg .pomo node_modules diff --git a/Readme.md b/Readme.md index 4447aca..7e851d4 100644 --- a/Readme.md +++ b/Readme.md @@ -250,6 +250,17 @@ ctx.fillText('Hello World 3', 50, 80); ctx.addPage(); ``` +## SVG support + + Just like PDF support, make sure to install cairo with `--enable-svg=yes`. + You also need to tell node-canvas that it is working on SVG upon its initialization: + +```js +var canvas = new Canvas(200, 500, 'svg'); +// Use the normal primitives. +fs.writeFile('out.svg', canvas.toBuffer()); +``` + ## Benchmarks Although node-canvas is extremely new, and we have not even begun optimization yet it is already quite fast. For benchmarks vs other node canvas implementations view this [gist](https://gist.github.com/664922), or update the submodules and run `$ make benchmark` yourself. diff --git a/examples/small-svg.js b/examples/small-svg.js new file mode 100644 index 0000000..574c258 --- /dev/null +++ b/examples/small-svg.js @@ -0,0 +1,22 @@ + +var Canvas = require('../') + , canvas = new Canvas(400, 200, 'svg') + , ctx = canvas.getContext('2d') + , fs = require('fs'); + +var y = 80 + , x = 50; + +ctx.font = '22px Helvetica'; +ctx.fillText('node-canvas SVG', x, y); + +ctx.font = '10px Arial'; +ctx.fillText('Just a quick example of SVGs with node-canvas', x, y += 20); + +ctx.globalAlpha = .5; +ctx.fillRect(x, y += 20, 10, 10); +ctx.fillRect(x += 20, y, 10, 10); +ctx.fillRect(x += 20, y, 10, 10); + +fs.writeFile('out.svg', canvas.toBuffer()); +console.log('created out.svg'); diff --git a/src/Canvas.cc b/src/Canvas.cc index 2aabf1d..01d3363 100644 --- a/src/Canvas.cc +++ b/src/Canvas.cc @@ -13,6 +13,7 @@ #include #include #include +#include #include "closure.h" #ifdef HAVE_JPEG @@ -69,7 +70,9 @@ NAN_METHOD(Canvas::New) { if (args[1]->IsNumber()) height = args[1]->Uint32Value(); if (args[2]->IsString()) type = !strcmp("pdf", *String::Utf8Value(args[2])) ? CANVAS_TYPE_PDF - : CANVAS_TYPE_IMAGE; + : !strcmp("svg", *String::Utf8Value(args[2])) + ? CANVAS_TYPE_SVG + : CANVAS_TYPE_IMAGE; Canvas *canvas = new Canvas(width, height, type); canvas->Wrap(args.This()); NanReturnValue(args.This()); @@ -82,7 +85,7 @@ NAN_METHOD(Canvas::New) { NAN_GETTER(Canvas::GetType) { NanScope(); Canvas *canvas = ObjectWrap::Unwrap(args.This()); - NanReturnValue(NanNew(canvas->isPDF() ? "pdf" : "image")); + NanReturnValue(NanNew(canvas->isPDF() ? "pdf" : canvas->isSVG() ? "svg" : "image")); } /* @@ -238,7 +241,7 @@ NAN_METHOD(Canvas::ToBuffer) { Canvas *canvas = ObjectWrap::Unwrap(args.This()); // TODO: async / move this out - if (canvas->isPDF()) { + if (canvas->isPDF() || canvas->isSVG()) { cairo_surface_finish(canvas->surface()); closure_t *closure = (closure_t *) canvas->closure(); @@ -480,6 +483,12 @@ Canvas::Canvas(int w, int h, canvas_type_t t): ObjectWrap() { cairo_status_t status = closure_init((closure_t *) _closure, this, 0, PNG_NO_FILTERS); assert(status == CAIRO_STATUS_SUCCESS); _surface = cairo_pdf_surface_create_for_stream(toBuffer, _closure, w, h); + } else if (CANVAS_TYPE_SVG == t) { + _closure = malloc(sizeof(closure_t)); + assert(_closure); + cairo_status_t status = closure_init((closure_t *) _closure, this, 0, PNG_NO_FILTERS); + assert(status == CAIRO_STATUS_SUCCESS); + _surface = cairo_svg_surface_create_for_stream(toBuffer, _closure, w, h); } else { _surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h); assert(_surface); @@ -494,6 +503,7 @@ Canvas::Canvas(int w, int h, canvas_type_t t): ObjectWrap() { Canvas::~Canvas() { switch (type) { case CANVAS_TYPE_PDF: + case CANVAS_TYPE_SVG: cairo_surface_finish(_surface); closure_destroy((closure_t *) _closure); free(_closure); @@ -512,10 +522,29 @@ Canvas::~Canvas() { void Canvas::resurface(Handle canvas) { + NanScope(); + Handle context; switch (type) { case CANVAS_TYPE_PDF: cairo_pdf_surface_set_size(_surface, width, height); break; + case CANVAS_TYPE_SVG: + // Re-surface + cairo_surface_finish(_surface); + closure_destroy((closure_t *) _closure); + cairo_surface_destroy(_surface); + closure_init((closure_t *) _closure, this, 0, PNG_NO_FILTERS); + _surface = cairo_svg_surface_create_for_stream(toBuffer, _closure, width, height); + + // Reset context + context = canvas->Get(NanNew("context")); + if (!context->IsUndefined()) { + Context2d *context2d = ObjectWrap::Unwrap(context->ToObject()); + cairo_t *prev = context2d->context(); + context2d->setContext(cairo_create(surface())); + cairo_destroy(prev); + } + break; case CANVAS_TYPE_IMAGE: // Re-surface int old_width = cairo_image_surface_get_width(_surface); @@ -525,7 +554,7 @@ Canvas::resurface(Handle canvas) { NanAdjustExternalMemory(4 * (width * height - old_width * old_height)); // Reset context - Handle context = canvas->Get(NanNew("context")); + context = canvas->Get(NanNew("context")); if (!context->IsUndefined()) { Context2d *context2d = ObjectWrap::Unwrap(context->ToObject()); cairo_t *prev = context2d->context(); diff --git a/src/Canvas.h b/src/Canvas.h index 1dae9b1..90ef1e5 100644 --- a/src/Canvas.h +++ b/src/Canvas.h @@ -39,7 +39,8 @@ using namespace node; typedef enum { CANVAS_TYPE_IMAGE, - CANVAS_TYPE_PDF + CANVAS_TYPE_PDF, + CANVAS_TYPE_SVG } canvas_type_t; /* @@ -78,6 +79,7 @@ class Canvas: public node::ObjectWrap { #endif inline bool isPDF(){ return CANVAS_TYPE_PDF == type; } + inline bool isSVG(){ return CANVAS_TYPE_SVG == type; } inline cairo_surface_t *surface(){ return _surface; } inline void *closure(){ return _closure; } inline uint8_t *data(){ return cairo_image_surface_get_data(_surface); } diff --git a/test/canvas.test.js b/test/canvas.test.js index 9b3d247..c3861db 100644 --- a/test/canvas.test.js +++ b/test/canvas.test.js @@ -165,6 +165,8 @@ module.exports = { assert('image' == canvas.type); var canvas = new Canvas(10, 10, 'pdf'); assert('pdf' == canvas.type); + var canvas = new Canvas(10, 10, 'svg'); + assert('svg' == canvas.type); var canvas = new Canvas(10, 10, 'hey'); assert('image' == canvas.type); },