From fc02c58ddbeb0f737663a9d6ea6af9f7354444b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Tue, 3 Dec 2013 23:07:54 +0100 Subject: [PATCH] Implement asynchronously loading Rasters from disk and remote locations for Node.js Closes #328. --- examples/Node.js/RemoteRaster.js | 25 ++++++++++++++++++ node_modules/.gitignore | 1 + package.json | 3 ++- src/dom/node.js | 9 +++---- src/item/Raster.js | 45 ++++++++++++++++++++++++-------- 5 files changed, 66 insertions(+), 17 deletions(-) create mode 100644 examples/Node.js/RemoteRaster.js diff --git a/examples/Node.js/RemoteRaster.js b/examples/Node.js/RemoteRaster.js new file mode 100644 index 00000000..426013a6 --- /dev/null +++ b/examples/Node.js/RemoteRaster.js @@ -0,0 +1,25 @@ +var paper = require('paper'); +var fs = require('fs'); + +var canvas = new paper.Canvas(800, 600); +paper.setup(canvas); + +var url = 'http://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png'; +var raster = new paper.Raster(url); +raster.position = paper.view.center; + +raster.onLoad = function() { + console.log('The image has loaded:' + raster.bounds); + + // Saving the canvas to a file. + out = fs.createWriteStream(__dirname + '/canvas.png'); + stream = canvas.pngStream(); + + stream.on('data', function(chunk){ + out.write(chunk); + }); + + stream.on('end', function() { + console.log('saved png'); + }); +}; diff --git a/node_modules/.gitignore b/node_modules/.gitignore index 9cdda2da..f03c65d0 100644 --- a/node_modules/.gitignore +++ b/node_modules/.gitignore @@ -1,6 +1,7 @@ .bin canvas jsdom +request uglify-js prepro grunt* diff --git a/package.json b/package.json index 3cbd6e80..44a6995c 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,8 @@ }, "dependencies": { "canvas": ">= 0.7.0", - "jsdom": ">= 0.6.0" + "jsdom": ">= 0.6.0", + "request": "~2.27.0" }, "devDependencies": { "uglify-js": "~2.3.6", diff --git a/src/dom/node.js b/src/dom/node.js index b7bbaf25..4b391ba9 100644 --- a/src/dom/node.js +++ b/src/dom/node.js @@ -18,11 +18,10 @@ var jsdom = require('jsdom'), domToHtml = require('jsdom/lib/jsdom/browser/domtohtml').domToHtml, // Node Canvas library: https://github.com/learnboost/node-canvas - Canvas = require('canvas'); - -// Expose global browser variables and create a document and a window using -// jsdom, e.g. for import/exportSVG() -var document = jsdom.jsdom(''), + Canvas = require('canvas'), + // Expose global browser variables and create a document and a window using + // jsdom, e.g. for import/exportSVG() + document = jsdom.jsdom(''), window = document.createWindow(), navigator = window.navigator, HTMLCanvasElement = Canvas, diff --git a/src/item/Raster.js b/src/item/Raster.js index d621d9a1..50a4be11 100644 --- a/src/item/Raster.js +++ b/src/item/Raster.js @@ -291,20 +291,23 @@ var Raster = Item.extend(/** @lends Raster# */{ }, setSource: function(src) { -/*#*/ if (__options.environment == 'browser') { var that = this, - // src can be an URL or a DOM ID to load the image from - image = document.getElementById(src) || new Image(); + image; function loaded() { var view = that._project.view; if (view) paper = view._scope; + that.setImage(image); that.fire('load'); if (view) view.draw(true); } +/*#*/ if (__options.environment == 'browser') { + // src can be an URL or a DOM ID to load the image from + image = document.getElementById(src) || new Image(); + // IE has naturalWidth / Height defined, but width / height set to 0 // when the image is invisible in the document. if (image.naturalWidth && image.naturalHeight) { @@ -314,10 +317,7 @@ var Raster = Item.extend(/** @lends Raster# */{ } else { // Trigger the onLoad event on the image once it's loaded DomEvent.add(image, { - load: function() { - that.setImage(image); - loaded(); - } + load: loaded }); // A new image created above? Set the source now. if (!image.src) @@ -325,17 +325,37 @@ var Raster = Item.extend(/** @lends Raster# */{ } this.setImage(image); /*#*/ } else if (__options.environment == 'node') { - var image = new Image(); + image = new Image(); // If we're running on the server and it's a string, // check if it is a data URL if (/^data:/.test(src)) { // Preserve the data in this._data since canvas-node eats it. // TODO: Fix canvas-node instead image.src = this._data = src; + // Fire load event delayed, so behavior is the same as when it's + // actually loaded and we give the code time to install event + setTimeout(loaded, 0); + } else if (/^https?:\/\//.test(src)) { + // Load it from remote location: + require('request').get({ + url: src, + encoding: null // So the response data is a Buffer + }, function (err, response, data) { + if (err) + throw err; + if (response.statusCode == 200) { + image.src = this._data = data; + loaded(); + } + }); } else { // Load it from disk: - // TODO: load images async, calling setImage once loaded as above. - image.src = fs.readFileSync(src); + require('fs').readFile(src, function (err, data) { + if (err) + throw err; + image.src = this._data = data; + loaded(); + }); } this.setImage(image); /*#*/ } // __options.environment == 'node' @@ -393,8 +413,11 @@ var Raster = Item.extend(/** @lends Raster# */{ // See if the linked image is base64 encoded already, if so reuse it, // otherwise try using canvas.toDataURL() /*#*/ if (__options.environment == 'node') { - if (this._data) + if (this._data) { + if (this._data instanceof Buffer) + this._data = this._data.toString('base64'); return this._data; + } /*#*/ } else { var src = this._image && this._image.src; if (/^data:/.test(src))