Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allows embedding of images as Data URLs #71

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 98 additions & 5 deletions canvas2svg.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,11 +215,11 @@
* ctx - existing Context2D to wrap around
* width - width of your canvas (defaults to 500)
* height - height of your canvas (defaults to 500)
* enableMirroring - enables canvas mirroring (get image data) (defaults to false)
* embedImages - enables embedding images as data URLs (defaults to false)
* document - the document object (defaults to the current document)
*/
ctx = function (o) {
var defaultOptions = { width:500, height:500, enableMirroring : false}, options;
var defaultOptions = { width:500, height:500, embedImages : false}, options;

//keep support for this way of calling C2S: new C2S(width,height)
if (arguments.length > 1) {
Expand All @@ -240,7 +240,7 @@
//setup options
this.width = options.width || defaultOptions.width;
this.height = options.height || defaultOptions.height;
this.enableMirroring = options.enableMirroring !== undefined ? options.enableMirroring : defaultOptions.enableMirroring;
this.embedImages = options.embedImages !== undefined ? options.embedImages : defaultOptions.embedImages;

this.canvas = this; ///point back to this instance!
this.__document = options.document || document;
Expand Down Expand Up @@ -422,6 +422,70 @@
}
};

function startRequest()
{
outstandingRequests++;
}

function completeRequest()
{
outstandingRequests--;
if(outstandingRequests == 0)
{
completeCallbacks.forEach(function(callback)
{
callback();
});
completeCallbacks = [];
}
}

var outstandingRequests = 0;
var completeCallbacks = [];

function toDataUrl(url, callback){
var xhr = new XMLHttpRequest();
xhr.open('get', url);
xhr.responseType = 'blob';
xhr.onload = function(){
var fr = new FileReader();

fr.onload = function()
{
callback(this.result);
completeRequest();
};

fr.onerror = function(e)
{
console.error("error reading image " + url, e);
completeRequest();
};

fr.readAsDataURL(xhr.response); // async call
};
xhr.onerror = function(e){
console.error("error loading image " + url + " status " + e.target.status);
completeRequest();
};
startRequest();
xhr.send();
}

/**
* Waits for all outstanding asyc calls such as image download
* @param callback - will be called when complete
*/
ctx.prototype.waitForComplete = function (callback)
{
if(outstandingRequests > 0)
{
completeCallbacks.push(callback);
return;
}
callback();
};

/**
* Returns the serialized value of the svg so far
* @param fixNamedEntities - Standalone SVG doesn't support named entities, which document.createTextNode encodes.
Expand Down Expand Up @@ -1152,9 +1216,38 @@
context.drawImage(image, sx, sy, sw, sh, 0, 0, dw, dh);
image = canvas;
}

if (image.nodeName === "CANVAS") {
svgImage.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", image.toDataURL());
}
else if(this.embedImages)
{
var orgSvgImage = svgImage;
svgImage = this.__createElement("use");
svgImage.setAttribute("width", dw);
svgImage.setAttribute("height", dh);
var imageUrl = image.getAttribute("src");
svgImage.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", "#" + imageUrl);
//if the image has not been dseen before download and add to defs for reuse
if(!this.__ids[imageUrl])
{
this.__ids[imageUrl] = imageUrl;
orgSvgImage.setAttribute("id", imageUrl);
this.__defs.appendChild(orgSvgImage);
toDataUrl(image.getAttribute("src"),
function(dataUrl)
{
orgSvgImage.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", dataUrl);
});
}
}
else
{
svgImage.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", image.getAttribute("src"));
}

svgImage.setAttribute("transform", translateDirective);
svgImage.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href",
image.nodeName === "CANVAS" ? image.toDataURL() : image.getAttribute("src"));

parent.appendChild(svgImage);
}
};
Expand Down
Binary file added test/example/tiger.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 24 additions & 8 deletions test/unit.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,46 @@ describe('canvas2svg', function() {
describe('it can be created', function(){

it("with options", function() {
var ctx = new C2S({width:100, height:200, enableMirroring:true});
var ctx = new C2S({width:100, height:200, embedImages:true});
expect(ctx instanceof C2S).to.equal(true);
expect(ctx.width).to.equal(100);
expect(ctx.height).to.equal(200);
expect(ctx.enableMirroring).to.equal(true);
expect(ctx.embedImages).to.equal(true);

var ctx2 = new C2S(300,400);
expect(ctx2 instanceof C2S).to.equal(true);
expect(ctx2.width).to.equal(300);
expect(ctx2.height).to.equal(400);
expect(ctx2.enableMirroring).to.equal(false);
expect(ctx2.embedImages).to.equal(false);
});

it("with no options and have defaults", function() {
var ctx = new C2S();
expect(ctx instanceof C2S).to.equal(true);
expect(ctx.width).to.equal(500);
expect(ctx.height).to.equal(500);
expect(ctx.enableMirroring).to.equal(false);
expect(ctx.embedImages).to.equal(false);
});

it("even if it's called as a function", function() {
//notice the lack of new!
var ctx = C2S({width:100, height:200, enableMirroring:true});
var ctx = C2S({width:100, height:200, embedImages:true});
expect(ctx instanceof C2S).to.equal(true);
expect(ctx.width).to.equal(100);
expect(ctx.height).to.equal(200);
expect(ctx.enableMirroring).to.equal(true);
expect(ctx.embedImages).to.equal(true);

var ctx2 = C2S(300,400);
expect(ctx2 instanceof C2S).to.equal(true);
expect(ctx2.width).to.equal(300);
expect(ctx2.height).to.equal(400);
expect(ctx2.enableMirroring).to.equal(false);
expect(ctx2.embedImages).to.equal(false);

var ctx3 = C2S();
expect(ctx3 instanceof C2S).to.equal(true);
expect(ctx3.width).to.equal(500);
expect(ctx3.height).to.equal(500);
expect(ctx3.enableMirroring).to.equal(false);
expect(ctx3.embedImages).to.equal(false);

});

Expand Down Expand Up @@ -357,4 +357,20 @@ describe('canvas2svg', function() {
expect(svg.querySelector("clipPath > path").getAttribute("d")).to.not.equal(null);
});
});

describe("supports embedded images", function() {
it("adds image", function(done) {
var ctx = new C2S({embedImages:true});
var img = new Image;
img.src = "./example/tiger.jpg";
ctx.drawImage(img, 0, 0);
ctx.waitForComplete(function()
{
var svg = ctx.getSvg();
expect(svg.querySelector("image").getAttribute("xlink:href")).to.not.equal(null);
done();
});
});
});

});