Giter VIP home page Giter VIP logo

canvas2svg's Introduction

Canvas2Svg Build Status

This library turns your Canvas into SVG using javascript. In other words, this library lets you build an SVG document using the canvas api. Why use it?

  • You have a canvas drawing you want to persist as an SVG file.
  • You like exporting things.
  • Because you didn't want to transform your custom file format to SVG.

Demo

http://gliffy.github.io/canvas2svg/

How it works

We create a mock 2d canvas context. Use the canvas context like you would on a normal canvas. As you call methods, we build up a scene graph in SVG. Yay!

Usage

//Create a new mock canvas context. Pass in your desired width and height for your svg document.
var ctx = new C2S(500,500);

//draw your canvas like you would normally
ctx.fillStyle="red";
ctx.fillRect(100,100,100,100);
//etc...

//serialize your SVG
var mySerializedSVG = ctx.getSerializedSvg(); //true here, if you need to convert named to numbered entities.

//If you really need to you can access the shadow inline SVG created by calling:
var svg = ctx.getSvg();

Tests

To run tests:

npm install
npm test

To run tests against Chrome and Firefox, call karma directly. This is not the default npm test due to the limited browser selection in travis.

npm install karma-cli -g
karma start

Debug

Play with canvas2svg in the provided test/playground.html or run test locally in your browser in test/testrunner.html

Add An Example Case

Add a test file to the test/example folder. In your file make sure to add the drawing function to the global C2S_EXAMPLES, with your filename as a key. For example test\example\linewidth.js should look something like:

window.C2S_EXAMPLES['linewidth'] = function(ctx) {
    for (var i = 0; i < 10; i++){
        ctx.lineWidth = 1+i;
        ctx.beginPath();
        ctx.moveTo(5+i*14,5);
        ctx.lineTo(5+i*14,140);
        ctx.stroke();
    }
};

install gulp globally if you haven't done so already

npm install -g gulp

Then run the following to update playground.html and testrunner.html

gulp

You should now be able to select your new example from playground.html or see it run in testrunner.html

If you find a bug, or want to add functionality, please add a new test case and include it with your pull request.

Using with node.js

You can use canvas2svg with node.js using jsdom with node-canvas. To do this first create a new document object, and then create a new instance of C2S based on that document:

var canvas = require('canvas'),
    jsdom = require('jsdom'),
    C2S = require('canvas2svg');

var document = jsdom.jsdom();
var ctx = new C2S({document: document});

// ... drawing code goes here ...

N.B. You may not need node-canvas for some simple operations when using jsdom >= 6.3.0, but it's still recommended that you install it.

Updates

  • v1.0.19 Fix __parseFont to not crash
  • v1.0.18 clip was not working, the path never made it to the clip area
  • v1.0.17 Fix bug with drawing in an empty context. Fix image translation problem. Fix globalAlpha issue.
  • v1.0.16 Add npm publishing support, bower file and optimize for arcs with no angles.
  • v1.0.15 Setup travis, add testharness and debug playground, and fix regression for __createElement refactor
  • v1.0.14 bugfix for gradients, move __createElement to scoped createElement function, so all classes have access.
  • v1.0.13 set paint order before stroke and fill to make them behavior like canvas
  • v1.0.12 Implementation of ctx.prototype.arcTo.
  • v1.0.11 call lineTo instead moveTo in ctx.arc, fixes closePath issue and straight line issue
  • v1.0.10 when lineTo called, use M instead of L unless subpath exists
  • v1.0.9 use currentDefaultPath instead of 's d attribute, fixes stroke's different behavior in SVG and canvas.
  • v1.0.8 reusing __createElement and adding a properties undefined check
  • v1.0.7 fixes for multiple transforms and fills and better text support from stafyniaksacha
  • v1.0.6 basic support for text baseline (contribution from KoKuToru)
  • v1.0.5 fixes for #5 and #6 (with contributions from KoKuToru)
  • v1.0.4 generate ids that start with a letter
  • v1.0.3 fixed #4 where largeArcFlag was set incorrectly in some cases
  • v1.0.2 Split up rgba values set in fill/stroke to allow illustrator import support.
  • v1.0.1 Allow C2S to be called as a function. #2
  • v1.0.0 Initial release

Misc

Some canvas 2d context methods are not implemented yet. Watch out for setTransform and arcTo.

Releasing

To release a new version:

  • Run gulp bump to update the version number
  • Add a new entry to the Updates table
  • git commit -am v1.0.xx
  • git push
  • npm publish

License

This library is licensed under the MIT license.

canvas2svg's People

Contributors

conradirwin avatar fuzhenn avatar gwwar avatar janpot avatar kokutoru avatar lemonpi avatar mudcube avatar spanktar avatar stafyniaksacha avatar watcherdm avatar zenozeng avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

canvas2svg's Issues

getImageData() Support?

Does this support getImageData() function?

This line of text is returning undefined...

var imageData = ctx.getImageData(0, 0, width, height);

Font parsing fails on "normal 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"

Seen on v1.0.15.

Sorry to tell but I gave up understanding this regex :
regex = /^\s*(?=(?:(?:[-a-z]+\s*){0,2}(italic|oblique))?)(?=(?:(?:[-a-z]+\s*){0,2}(small-caps))?)(?=(?:(?:[-a-z]+\s*){0,2}(bold(?:er)?|lighter|[1-9]00))?)(?:(?:normal|\1|\2|\3)\s*){0,3}((?:xx?-)?(?:small|large)|medium|smaller|larger|[.\d]+(?:%|in|[cem]m|ex|p[ctx]))(?:\s*/\s*(normal|[.\d]+(?:%|in|[cem]m|ex|p[ctx])))?\s*([-,"\sa-z]+?)\s*$/i;

Shouldn't "normal 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif" be parseable ?

Chrome console shows as follows :
ERROR TypeError: Cannot read property '1' of null
at ctx.push../node_modules/canvas2svg/canvas2svg.js.ctx.__parseFont (VM9279 vendor.js:90992)
at ctx.push../node_modules/canvas2svg/canvas2svg.js.ctx.__applyText (VM9279 vendor.js:91039)
at ctx.push../node_modules/canvas2svg/canvas2svg.js.ctx.fillText (VM9279 vendor.js:91066)
at fillText (VM9279 vendor.js:106831)

Cannot export to svg

Here's my code that I need to export to svg:

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.stroke();
ctx.fill('evenodd')
	
let region = new Path2D();


var h1 = document.getElementById("myCanvas1");
var ctx = c.getContext("2d");
ctx.strokeStyle = "#7AD7F0";
ctx.lineWidth = 30;
ctx.beginPath();
ctx.rotate(10 * Math.PI / 360);
ctx.arc(41,288,55,25,3);
ctx.stroke();
    
	
	
var h2 = document.getElementById("myCanvas2");
var ctx = c.getContext("2d");
ctx.strokeStyle = "#7AD7F0";
ctx.lineWidth = 30;
ctx.beginPath();
ctx.rotate(0 * Math.PI / 360);
ctx.arc(151,278,55,25,3);
ctx.stroke();
ctx.closePath();
	
var h3 = document.getElementById("myCanvas3");
var ctx = c.getContext("2d");
ctx.strokeStyle = "#7AD7F0";
ctx.lineWidth = 30;
ctx.beginPath();
ctx.rotate(15 * Math.PI / 360);
ctx.arc(293,232,55,25,3);
ctx.stroke();
ctx.closePath();
    
var h4 = document.getElementById("myCanvas4");
var ctx = c.getContext("2d");
ctx.strokeStyle = "#7AD7F0";
ctx.lineWidth = 30;
ctx.beginPath();
ctx.rotate(-8 * Math.PI / 360);
ctx.arc(385,240,55,25,3);
ctx.stroke();
    
var h5 = document.getElementById("myCanvas5");
var ctx = c.getContext("2d");
ctx.strokeStyle = "#7AD7F0";
ctx.lineWidth = 30;
ctx.beginPath();
ctx.rotate(-5 * Math.PI / 360);
ctx.arc(485,245,55,25,3);
ctx.stroke();
ctx.closePath();
    
var h6 = document.getElementById("myCanvas6");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.rotate(-12 * Math.PI / 360);
ctx.rect(0, 349, 550, 0);
ctx.stroke();
ctx.closePath();
	
var paat = document.getElementById("myCanvas7");
var ctx = c.getContext("2d");
ctx.fillStyle="#654321";
ctx.translate(40, 60);
ctx.beginPath();
ctx.moveTo(350,150);
ctx.lineTo(300,300);
ctx.lineTo(100,300);
ctx.lineTo(50,150);
ctx.lineTo(120,150);
ctx.bezierCurveTo(
  120, 220, 
  220, 220, 
  220, 150
);
ctx.fill();
ctx.closePath();
	
var h8 = document.getElementById("myCanvas8");
var ctx = c.getContext("2d");
ctx.strokeStyle="#101";
ctx.lineWidth = 4;
ctx.beginPath();
ctx.moveTo(170, 130);
ctx.lineTo(170, 205);
ctx.stroke();
ctx.closePath();
	
var h9 = document.getElementById("myCanvas9");
var ctx = c.getContext("2d");
ctx.strokeStyle="#101";
ctx.lineWidth = 4;
ctx.translate(145, -120);
ctx.beginPath();
ctx.rotate(160 * Math.PI / 360);
ctx.arc(130,0,120,25,13);
ctx.stroke();
ctx.closePath();
	
var h10 = document.getElementById("myCanvas10");
var ctx = c.getContext("2d");
ctx.strokeStyle="#101";
ctx.lineWidth = 4;
ctx.translate(280, -180);
ctx.beginPath();
ctx.rotate(280 * Math.PI / 360);
ctx.arc(125,23,130,55,18);
ctx.stroke();
ctx.translate(83, 5);
ctx.moveTo(165, -35);
ctx.lineTo(125, -85);
ctx.stroke();
ctx.closePath();

var h11 = document.getElementById("myCanvas11");
var ctx = c.getContext("2d");
ctx.strokeStyle="#101";
ctx.lineWidth = 4;
ctx.beginPath();
ctx.rotate(90 * Math.PI / 360);
ctx.arc(-45,-55,120,55,18);
ctx.stroke();
ctx.closePath();
    

	
var bob = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.strokeStyle = "black";
ctx.lineWidth = 2;
ctx.translate(43, -295);
ctx.rotate(910 * Math.PI / 360);
ctx.beginPath();
ctx.arc(60,40,13,0,10);
ctx.stroke();
	
var bobsilm1 = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.strokeStyle = "black";
ctx.lineWidth = 1;
ctx.beginPath();
ctx.arc(60,35,4,0,10);
ctx.stroke();
    
var bobsilm2 = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.strokeStyle = "black";
ctx.lineWidth = 1;
ctx.beginPath();
ctx.arc(59,36,1,0,10);
ctx.fillStyle = "#101";
ctx.fill();
ctx.stroke();
	
var bobkeha = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.strokeStyle = "black";
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(60, 54);
ctx.lineTo(60, 80);
ctx.stroke();
	
var bobkehajalg1 = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.strokeStyle = "black";
ctx.lineWidth = 3;
ctx.moveTo(60, 80);
ctx.lineTo(50, 100);
ctx.stroke();
	
var bobkehajalg2 = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.moveTo(60, 80);
ctx.lineTo(70, 100);
ctx.stroke();
	
var bobkehakasi1 = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.moveTo(60, 60);
ctx.lineTo(19, 60);
ctx.stroke();
	
var bobkehakasi2 = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.moveTo(60, 60);
ctx.lineTo(70, 80);
ctx.stroke();
	
var bobsuu = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.strokeStyle = "black";
ctx.lineWidth = 2;
ctx.beginPath();
ctx.arc(55,45,2,0,3);
ctx.stroke();
	
var ruupur = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.strokeStyle = "black";
ctx.lineWidth = 2;
ctx.translate(10, 32);
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(0, 35);
ctx.moveTo(0, 0);
ctx.lineTo(25, 3);
ctx.moveTo(25, 3);
ctx.lineTo(37, 11);
ctx.moveTo(0, 35);
ctx.lineTo(37, 11);
ctx.stroke();
	
var tutt1 = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.strokeStyle = "black";
ctx.lineWidth = 2;
ctx.rotate(280 * Math.PI / 360);
ctx.beginPath();
ctx.arc(-51,-27,12,0,1);
ctx.stroke();

	
var tutt2 = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.strokeStyle = "black";
ctx.lineWidth = 2;
ctx.rotate(50 * Math.PI / 360);
ctx.translate(8, 8);
ctx.beginPath();
ctx.arc(-71,-15,12,0,1);
ctx.stroke();
	
var tutt3 = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.strokeStyle = "black";
ctx.lineWidth = 2;
ctx.rotate(50 * Math.PI / 360);
ctx.translate(-5, 10);
ctx.beginPath();
ctx.arc(-71,0,12,0,1);
ctx.stroke();
	
var paadinina = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.strokeStyle = "black";
ctx.lineWidth = 3;
ctx.rotate(-190 * Math.PI / 360);
ctx.beginPath();
ctx.arc(31,-42,50,0,1);
ctx.stroke();
	
var heli1 = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.strokeStyle = "black";
ctx.lineWidth = 2;
ctx.translate(-5, 35);
ctx.rotate(-50 * Math.PI / 360);
ctx.beginPath();
ctx.arc(18,-18,20,0,1);
ctx.arc(15,8,15,0,1);
ctx.stroke();
	
var heli2 = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.strokeStyle = "black";
ctx.lineWidth = 2;
ctx.translate(-15, 37);
ctx.beginPath();
ctx.arc(18,-18,20,0,1);
ctx.arc(15,8,15,0,1);
ctx.stroke();
	
var heli3 = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.strokeStyle = "black";
ctx.lineWidth = 2;
ctx.translate(25, -28);
ctx.beginPath();
ctx.arc(18,-23,20,0,1);
ctx.arc(15,8,15,0,1);
ctx.stroke();
	
var heli4 = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.strokeStyle = "black";
ctx.lineWidth = 2;
ctx.translate(-15, 37);
ctx.beginPath();
ctx.arc(18,-18,20,0,1);
ctx.arc(15,8,15,0,1);
ctx.stroke();

Can this be used with chart.js ? [question]

Hi. I am trying to use this library to export a chart created with chart.js to SVG, but it seems that chart.js can't use 'fake' context created by C2S. I am getting error_: "Failed to create chart: can't acquire context from the given item"_ when I try to draw a chart in C2S context.

See Codepen here for full example.

My Stackoverflow question is here.

Is there a way around this?
Or am I missing something?
Thanks.

Support AMD loader

Add UMD support so this can be used in a node context or browser context using the module import pattern.

Using with Node.JS

I faced problem with missed XMLSerializer.

(node:19466) UnhandledPromiseRejectionWarning: ReferenceError: XMLSerializer is not defined
    at ctx.getSerializedSvg (/home/work/schema-docs/node_modules/canvas2svg/canvas2svg.js:396:26)
    at ERDGenerator.asSvg (/home/work/schema-docs/src/ERDGenerator.ts:184:29)
    at /home/liteman/work/schema-docs/src/DocsGenerator.ts:75:42
    at DocsGenerator.generate (/home/work/schema-docs/src/DocsGenerator.ts:42:21)
(node:19466) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:19466) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code
```.

Publish to npm?

Any chance you could put this up on NPM? Should just be a case of running npm publish. That would let me use it easily from webpack :).

Supporting textBaseline

I have a working textBaselinein 5031052 and 51a1860

But with some problems..
5031052 uses dominant-baseline which isn't supported in IE
51a1860 shifts y-coordiantes based on the font.size which works in IE, but does same strong assumptions fontEmSize = fontEmSize / 1.25; and fontSize = fontEmSize / 1.25;

http://www.w3.org/TR/2014/CR-2dcontext-20140821/#text-styles see graph,
too bad it's not possible to access the font metrics directly..

Any idea how to tackle this nicely ?

Transformed Text coming Plain

I have transformed text to look it like slant using the below code but it is being exported plain (Non Slant)

Is there a way to export it with applied transformations???

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");

ctx.font = "20px Georgia";
//Slant LEFT
ctx.setTransform(1, 0, -0.3, 1, 0, 0);

can't parse bold fonts

Uncaught TypeError: Cannot read property '1' of null
canvas2svg:886 (in 6983b3d).

The problem was with a ctx.font = 'bold 270px sans-serif'; -- apparently, the 'bold' was the problem.

Transformation order

Although this is valid Canvas operation the following results in the error "Attempted to apply path command to node g":

var ctx = new C2S()
ctx.rect(0, 0, 100, 100)
ctx.scale(2, 2)
ctx.fill()
ctx.getSerializedSvg()

I'll investigate into why this is happening.

support for putImageData needed

I would like to save an already created canvas as SVG. My plan was to use getImageData to get the data from the canvas, and then use putImageData to create the SVG file. Unfortunately, canvas2svg does not support putImageData yet. Will this be implemented in the future, or does anyone know another solution?

image opacity + fix

Image opacity can be easily supported by adding the last line here:

       } else if (image.nodeName === "CANVAS" || image.nodeName === "IMG") {
            //canvas or image
            svgImage = this.__createElement("image");
            svgImage.setAttribute("opacity", this.globalAlpha || 1);

typo Inavlid -> Invalid

throw new Error("Inavlid number of arguments passed to drawImage: " + arguments.length);
should be
"Invalid"

x and y of drawImage missing in getSerializedSvg?

My code calls ctx.drawImage(img, startX, startY, width, height) on the C2S object I maintain for my canvas, but when I serialize and download the SVG, the x and y attributes are missing from the <image> tag. Width and height are preserved, but the image is at (0, 0)

Direct conversion from canvas to svg?

Rather than just taking an existing canvas and using drawImage to insert an image tag inside of an svg tag, I was expecting a direct translation of each node into a path or text or other valid svg options.

Is this something that is planned, rather than having to use the mock canvas?

The reason I ask is that I am currently prototyping html2canvas.js in an attempt to get a screenshot on the client-side to be persisted for auditing purposes. This does work, but I was wondering about a side-by-side comparison and svg would also give event options too.

Thanks

shadowColor method missing

Looks like ctx.shadowColor isn't implemented in the latest version of the library. If anyone wants to add this, I'll pay a bounty.

Endless loop when copying over defs

Hi, I am using the library to render OpenStreetMap data with kothic.js to svg and I encountered this potential endless loop when trying to fill a polygon with an svg as fill image.

code snipped

//copy over defs
while(value.__ctx.__defs.childNodes.length) {
    id = value.__ctx.__defs.childNodes[0].getAttribute("id");
    this.__ids[id] = id;
    this.__defs.appendChild(value.__ctx.__defs.childNodes[0]);
}

I logged the condition of the while loop and it didn't change, therefore resulting in an endless loop. Looking at the code, I cannot see how this would stop in any case, as the childNodes are not removed anywhere.

Am I overlooking something? I fixed the issue for me by changing the code to a for loop, Ill be happy to make a pull request, just thought id check if I am missing something here first.

clearRect is drawing white instead of clearing to transparent

A clear HTML5 canvas should have nothing on it. In my usage, calling ```ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)

and then drawing new stuff on the canvas still results in a #FFF rect being put in the resulting SVG. Is there a way to clear the canvas that's to spec with HTML5 canvas?

Incorrectly setting large-arc-flag

I'm trying to render a text balloon using lines and arcs, the first arc looks correct using canvas in multiple browsers (Chrome, FF, IE), after the conversion to SVG the arc is rendered incorrectly, for all other arcs large-arc-flag is not set, and editing the SVG manually fixes the issue.

Code:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <script src="canvas2svg.js" type="text/javascript"></script>
    </head>
    <body>
        <canvas id="testCanvas"></canvas>
        <div id="svgImage"></div>
        <p id="svgText"></p>
        <script>
            function drawBalloon(_drawingContext) {
                _drawingContext.beginPath();
                _drawingContext.lineWidth = 4;

                _drawingContext.moveTo(19, 10);
                _drawingContext.lineTo(110, 10);
                _drawingContext.arc(110, 20, 10, 1.5*Math.PI, 0);
                _drawingContext.lineTo(120, 50);
                _drawingContext.arc(110, 50, 10, 0, 0.5*Math.PI);
                _drawingContext.lineTo(90, 60);
                _drawingContext.lineTo(100, 80);
                _drawingContext.lineTo(70, 60);
                _drawingContext.lineTo(20, 60);
                _drawingContext.arc(20, 50, 10, 0.5*Math.PI, Math.PI);
                _drawingContext.lineTo(10, 20);
                _drawingContext.arc(20, 20, 10, Math.PI, 1.5*Math.PI);

                _drawingContext.stroke();
            }
            var canvas = document.querySelector("#testCanvas");
            canvas.width = 130;
            canvas.height = 85;
            var canvasContext  = canvas.getContext("2d");
            drawBalloon(canvasContext);

            var SVGContext = C2S(130, 85);
            drawBalloon(SVGContext);
            document.querySelector("#svgImage").appendChild(SVGContext.getSvg());
            document.querySelector("#svgText").textContent =
                    SVGContext.getSerializedSvg(true);
        </script>
    </body>
</html>

Export Canvas Image to SVG

Hi thank you for this great plugin its very useful for me in my project but I'm unable to find how to convert a rendered canvas image to SVG can you help me how to do this.

When new keyword is missing, unhelpful error is thrown

When this line of code is called...

var ctx = C2S(304.797, 26.109);

... then it gets the error...

Cannot set property 'width' of undefined

When I set a breakpoint in canvas2svg on line 196 in Chrome, sure enough "this" is undefined.

Sometimes if I step through it slowly enough though, "this" will be "Window". And even in that circumstance, I get this error...

Object [object global] has no method '__setDefaultStyles'

on line 202...

this.__setDefaultStyles();

ctx.createPattern(img, 'repeat'); doesn't work

See attached SVG (zipped) - SVG patterns don't repeat when the pattern is a PNG so the following doesn't work:

var pattern = ctx.createPattern(img, 'repeat');
ctx.fillStyle = pattern;

Possible workarounds:

  • the calling program needs to tile with a large enough bitmap
  • canvas2svg could extend the bitmap and embed a larger version

noTilingWithPng.zip

svg not parsable into svg editor

Dear all

I used following code (sample)

var ctx = new C2S(500,500);
ctx.font = "normal 36px Times";
ctx.fillStyle = "#000000";
ctx.fillText("A Text Example", 50, 50);
ctx.font = "normal 36px Arial";
ctx.strokeStyle = "#000000";
ctx.strokeText("A Text Example", 50, 90);
var svg = ctx.getSvg();
console.log(svg);

then I copy/paste the result below :

<svg version=​"1.1" xmlns=​"http:​/​/​www.w3.org/​2000/​svg" xmlns:xlink=​"http:​/​/​www.w3.org/​1999/​xlink" width=​"500" height=​"500">​​​​<text fill=​"#000000" stroke=​"none" font-family=​"Times" font-size=​"36px" font-style=​"normal" font-weight=​"normal" text-decoration=​"none" x=​"50" y=​"50" text-anchor=​"start" dominant-baseline=​"alphabetic">​A Text Example​​<text fill=​"none" stroke=​"#000000" font-family=​"Arial" font-size=​"36px" font-style=​"normal" font-weight=​"normal" text-decoration=​"none" x=​"50" y=​"90" text-anchor=​"start" dominant-baseline=​"alphabetic" stroke-miterlimit=​"10">​A Text Example​​​​

-> First of all, I do not get the same show in page http://gliffy.github.io/canvas2svg/ for simple example.
-> My output does not work when i copy/paste into SVG editor,

Could you please help me

Calling ctx.save does not always entail writing to a new group element

I am attempting to snapshot canvas renders as SVGs from points in time of playback of a CreateJS timeline. So I want set the timeline to a certain frame and snapshot the EaselJS submodule output which writes to the canvas object.

I have no control over the composition of the graphics I am working with in these timelines, so re-drawing the graphics to workaround this issue is not an option.

The issue is that the EaselJS module frequently applies the following sequence of commands while drawing path, at the point at which it wants to stroke the path and move on to the next graphic entity:

ctx.strokeStyle = this.style;
// this.ignoreScale is by default falsy
if (this.ignoreScale) { ctx.save(); ctx.setTransform(1,0,0,1,0,0); }
ctx.stroke();
if (this.ignoreScale) { ctx.restore(); }

The intent here is to re-use the current canvas state except for the transform. The problem is that the library interprets any call to ctx.save as not only stack push for the style state, but also calls for a new group element to be attached the SVG tree, I imagine, since SVG is declarative and has no state, to persist the state changes being called between ctx.save and ctx.restore, but this does not capture the range of intents in using ctx.save and ctx.restore.

So when its stroking a path, which is usually the last thing it calls for that path, this library changes elements and attempts to write a path to the newly create <g> instead of the path its supposed to write to. This creates incorrect output. I've attached a screenshot where the SVG output is to the left and the Canvas render to the right.
screen shot 2017-12-05 at 5 44 24 pm

The outlining paths used to "ink" the graphic as in the Canvas render all end up missing, and once can see multiple paths without a populated d attribute followed by an empty g peer.

Font parsing fails on eg 12px/12px

Solution from here looks better than the crazy regex
https://stackoverflow.com/questions/5618676/how-to-parse-css-font-shorthand-format

var parsedStyleForCSS = function(cssString){
    var el = document.createElement("span");
    el.setAttribute("style", cssString);

    return el.style; // CSSStyleDeclaration object
};

var parsedStyle = parsedStyleForCSS("font: bold italic small-caps 1em/1.5em verdana,sans-serif");

console.log(parsedStyle["fontWeight"]); // bold
console.log(parsedStyle["fontStyle"]); // italic
console.log(parsedStyle["fontVariant"]); // small-caps
console.log(parsedStyle["fontSize"]); // 1em
console.log(parsedStyle["lineHeight"]); // 1.5em
console.log(parsedStyle["fontFamily"]); // verdana, sans-serif

For the record, the original
var regex = /^\s*(?=(?:(?:[-a-z]+\s*){0,2}(italic|oblique))?)(?=(?:(?:[-a-z]+\s*){0,2}(small-caps))?)(?=(?:(?:[-a-z]+\s*){0,2}(bold(?:er)?|lighter|[1-9]00))?)(?:(?:normal|\1|\2|\3)\s*){0,3}((?:xx?-)?(?:small|large)|medium|smaller|larger|[.\d]+(?:\%|in|[cem]m|ex|p[ctx]))(?:\s*\/\s*(normal|[.\d]+(?:\%|in|[cem]m|ex|p[ctx])))?\s*([-_,\'\"\sa-z0-9]+?)\s*$/i;

has been slightly adapted from https://stackoverflow.com/questions/10135697/regex-to-parse-any-css-font

Exporting text as paths

Hello. Great job and idea. Is it possible to export a text from canvas as paths?
Thank you.

How to render text as vector?

Hi,

I'm using your script inside my whiteboard tool to create a preview image and I plan to use it for exporting the screen as well.
But in my tool I use different custom fonts (usual on whiteboards). Is it possible to render the text to vector in the SVG? Otherwise I see in the exported SVG only text with a Times font instead the selected one.

Thanks in advance
Frank

ctx.fill("evenodd") doesn't work + fix

ctx.fill("evenodd") doesn't take account of the parameter. Simple fix is to change method to

    ctx.prototype.fill = function (fillRule) {
        if (this.__currentElement.nodeName === "path") {
            this.__currentElement.setAttribute("paint-order", "stroke fill markers");
            if (fillRule == "evenodd") {
            	this.__currentElement.setAttribute("fill-rule", "evenodd");
            } 
        }
        this.__applyCurrentDefaultPath();
        this.__applyStyleToCurrentElement("fill");
    };

moveTo without beginPath

ctx.moveTo(150,20);
ctx.lineTo(150,170);
ctx.stroke();

first ctx.moveTo fails. Of course, because ctx.beginPath never got called.
Is it required to call ctx.beginPath(); ? I got here some internet examples that do not call it.

Chrome/Firefox accepts the above code and renders it correctly (when rendering into canvas).

Even if it's required by the canvas-standart... Any good idea how to support this case ?
I am thinking of adding a inexplicit ctx.beginPath() in ctx.prototype.__addPathCommand

Handling Decimal RGB values

I was getting constant errors until I realized that the code cannot handle decimal RGB values. In general, most places its integers but in applications with Color Picker where it has more precision, it can be decimal.
Here is the regex command to allow decimal RGB. I hope it helps others.

regex = /rgba\(\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\s*,\s*(\d?\.?\d*)\s*\)/gi;

Invalid value for <path> attribute d=" L 30 20 C 80 0 80 75 30 75 C 50 80 60 25 30 20"

Hey, thanks for your great work. But I have encountered a bug.

beginPath();
lineTo(30, 20);
bezierCurveTo(80, 0, 80, 75, 30, 75);
bezierCurveTo(50, 80, 60, 25, 30, 20);
fill();
stroke();
closePath();

The path generated is L 30 20 C 80 0 80 75 30 75 C 50 80 60 25 30 20, which actually should be M 30 20 C 80 0 80 75 30 75 C 50 80 60 25 30 20.

2015-05-29 20 17 05

According to W3's doc, Canvas's moveTo(x, y) method must create a new subpath with the specified point as its first (and only) point. And canvas's lineTo(x, y) method must ensure there is a subpath for (x, y) if the object's path has no subpaths. Otherwise, it must connect the last point in the subpath to the given point (x, y) using a straight line, and must then add the given point (x, y) to the subpath.

However, SVG's lineto only draw straight lines from the current point to a new point.

See also: http://www.w3.org/TR/2015/WD-2dcontext-20150514/#dom-context-2d-lineto

See also: http://www.w3.org/TR/SVG/paths.html#PathDataLinetoCommands

So in canvas2svg, when lineTo called, we should check if there is a subpath, and use M x y instead of L x y if the object's path has no subpaths.

This issue is fixed in zenozeng@1c49685. But this fix need #20 to be merged. I will pull a new request for this issue as soon as pull#20 merged.

See also: zenozeng/p5.js-svg#44

Multiple translates, rotations aren't right

What I get when I use canvas2svg:
001056-

What I get when I use canvas:
001055-

Code:

ctx.fillRect(0, 0, 10, 10)
ctx.translate(0, 20)
ctx.fillRect(0, 0, 10, 10)
ctx.translate(0, 20)
ctx.fillRect(0, 0, 10, 10)
ctx.translate(0, 20)

The generated svg is:
001057-ulamspiral html

I have this problem too when I use ctx.rotate()

Use on existing element?

Hey,

Great work. I'm just wondering if it's possible to use this plugin on an existing canvas element or if I have to create a new element and perform all of the drawing on the new element?

Cheers!

infinite loop with patterns on ctx.fill();

Minimal test case (hangs browser on "ctx.fill();")
http://test.geogebra.org/~mike/canvas2svgPatternBug/imageFill.html

Proof of concept for suggested fix:
http://test.geogebra.org/~mike/canvas2svgPatternBug/imageFill_fixed.html

Changing

while(value.__ctx.__defs.childNodes.length) {
id = value.__ctx.__defs.childNodes[0].getAttribute("id");
this.__ids[id] = id;
this.__defs.appendChild(value.__ctx.__defs.childNodes[0]);
}

to

var len = value.__ctx.__defs.childNodes.length;
for (var i = 0 ; i < len ; i++) {
id = value.__ctx.__defs.childNodes[i].getAttribute("id");
this.__ids[id] = id;
this.__defs.appendChild(value.__ctx.__defs.childNodes[i]);
}

seems to fix it although maybe removing the elements would be better (I guess there's a line of code missing to do that)

Opacity not working

OMG, thank you for such an awesome and helpful library! I'm connecting this with chart.js so the issue might be there, but I'm not getting opacity to carry through when exporting. For example, if I create a chart with semi-transparent bars, they show up onscreen correctly. But when exporting as an svg they come out opaque.

I am using these tweaks suggested on SO, so maybe the problem is coming from there too?

function tweakLib() {
	C2S.prototype.getContext = function(contextId) {
	    if (contextId === '2d' || contextId === '2D') {
	        return this;
	    }
	    return null;
	}
	C2S.prototype.style = function() {
	    return this.__canvas.style;
	}
	C2S.prototype.getAttribute = function(name) {
	    return this[name];
	}
	C2S.prototype.addEventListener = function(type, listener, eventListenerOptions) {
	    // nothing to do here, but we need this function :)
	}
}

Any pointers would be great – happy to fix and submit a PR!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.