From 36e31eb2502dc83f3a2bf101f3914b69b889ac12 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=BCrg=20Lehni?= <juerg@scratchdisk.com>
Date: Fri, 22 Jan 2016 17:05:50 +0100
Subject: [PATCH] Implement better handling of Raster#source and
 Raster#toDataURL() on Node.js

Closes #914
---
 package.json       |  5 +++--
 src/item/Raster.js | 51 +++++++++++++++++++++++++++++++++-------------
 2 files changed, 40 insertions(+), 16 deletions(-)

diff --git a/package.json b/package.json
index cabdb5bc..194893eb 100644
--- a/package.json
+++ b/package.json
@@ -30,10 +30,11 @@
   },
   "dependencies": {
     "jsdom": ">=3.1.2 <8.0.0",
-    "request": "~2.61.0"
+    "mime": "^1.3.0",
+    "request": "^2.61.0"
   },
   "optionalDependencies": {
-    "canvas": ">=1.2.9 <2.0.0"
+    "canvas": "^1.2.9"
   },
   "devDependencies": {
     "del": "^2.2.0",
diff --git a/src/item/Raster.js b/src/item/Raster.js
index 38891ad5..c0a60db2 100644
--- a/src/item/Raster.js
+++ b/src/item/Raster.js
@@ -323,7 +323,12 @@ var Raster = Item.extend(/** @lends Raster# */{
      * });
      */
     getSource: function() {
-        return this._image && this._image.src || this.toDataURL();
+        var image = this._image;
+/*#*/ if (__options.environment == 'node') {
+        // See #toDataURL()
+        image = image && this._src;
+/*#*/ } // __options.environment == 'node'
+        return image && image.src || this.toDataURL();
     },
 
     setSource: function(src) {
@@ -367,9 +372,9 @@ var Raster = Item.extend(/** @lends Raster# */{
         // 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;
+            // Preserve the data in this._src since canvas-node eats it.
+            image.src = src;
+            this._src = { src: src, data: src };
             // Emit load event with a delay, so behavior is the same as when
             // it's actually loaded and we give the code time to install event.
             setTimeout(loaded, 0);
@@ -378,20 +383,31 @@ var Raster = Item.extend(/** @lends Raster# */{
             require('request').get({
                 url: src,
                 encoding: null // So the response data is a Buffer
-            }, function (err, response, data) {
+            }, function (err, response, buffer) {
                 if (err)
                     throw err;
                 if (response.statusCode == 200) {
-                    image.src = this._data = data;
+                    image.src = buffer;
+                    that._src = {
+                        src: src,
+                        buffer: buffer,
+                        type: response.headers['content-type']
+                    };
                     loaded();
                 }
             });
         } else {
             // Load it from disk:
-            require('fs').readFile(src, function (err, data) {
+            src = (src.match(/^file:\/\/(.*)$/) || [null, src])[1];
+            require('fs').readFile(src, function (err, buffer) {
                 if (err)
                     throw err;
-                image.src = this._data = data;
+                image.src = buffer;
+                that._src = {
+                    src: 'file://' + src,
+                    buffer: buffer,
+                    type: require('mime').lookup(src)
+                };
                 loaded();
             });
         }
@@ -483,17 +499,24 @@ var Raster = Item.extend(/** @lends Raster# */{
     toDataURL: function() {
         // See if the linked image is base64 encoded already, if so reuse it,
         // otherwise try using canvas.toDataURL()
+        var image = this._image,
+            src;
 /*#*/ if (__options.environment == 'node') {
-        if (this._data) {
-            if (this._data instanceof Buffer)
-                this._data = this._data.toString('base64');
-            return this._data;
+        // Only use the information stored in _src if we still use the _image
+        // that goes with it.
+        var obj = image && this._src;
+        if (obj) {
+            if (!obj.data) {
+                obj.data = 'data:' + obj.type + ';base64,' +
+                    obj.buffer.toString('base64');
+            }
+            src = obj.data;
         }
 /*#*/ } else {
-        var src = this._image && this._image.src;
+         src = image && image.src;
+/*#*/ } // __options.environment == 'node'
         if (/^data:/.test(src))
             return src;
-/*#*/ }
         var canvas = this.getCanvas();
         return canvas ? canvas.toDataURL.apply(canvas, arguments) : null;
     },