Save canvas as file? (and open file again) (without loosing quality) - svg

The program I'm using is this
var canvas = this.__canvas = new fabric.Canvas('c');
canvas.setHeight(300);
canvas.setWidth(500);
function AddCircle() {
canvas.add(new fabric.Circle({
left: 230/canvas.getZoom(),
top: 140/canvas.getZoom(),
radius: 75/canvas.getZoom(),
fill: 'green',
}));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
<button onclick="AddCircle()">Add Circles</button>
<br>
<br>
<button onclick="Saveas()">Save as</button>
<button onclick="Openfile()">Open file</button>
<div class="box">
<canvas id="c"></canvas>
So now. I want to save the canvas (all the content/all the circles or objects) as a file. At this point I have seen that there are a few ways to save, for example, as png. But The problem is that I don't want to loose quality of the work inside of canvas.
I have seen libraries like jason. But I really don't know to implement them.
Also I have seen that working with svg for saving as files is easier since it can be saved/open as .xhml file without loosing quality.
My other question is:
Is there a easy way to convert the canvas to xhml, so when you click save button, you save the file as xhml, once saved back to use it by clicking "open file button" to open the .xhml file and conver it to canvas again (to show the content in the workspace)?
This are just my thinkings, any suggestions, libraries you recommend more or demo snippets for solving this would be very appreciated.
My last is. What do you recommend more, working with canvas libraries or svg libraries?. Im planning to make a very basic app like Prezi.com is (create objects) Online saving files and so... (also I plan to insert svg and maybe animations to the work space)
As you see, now I'm using canvas libraries ( in particular fabric.js). But since I'm starting it'd be easier for me to change if I'm not using the best alternative.

I am not sure that is possible,
HTML Canvas it's a Bitmap, that you draw in with Javascript.
SVG embedded in an HTML document, It's just like a subtree of the DOM, that still has a valid XML representation that any (not sure if any but most), SVG editors and viewers will understand.
You can "emulate" a canvas with SVG, easily by setting a svg or div + svg and then appending all the childs to this svg and because the geometric ideas of drawing in canvas and doing vector graphics are not that different, you could "migrate" to it.
The tip here is to define a viewbox on the SVG as you would define the canvas dimensions, and then, you can preserve your units. (just be careful with the numbers)
Plus it would be easier to attach events to the SVG elements.
To be honest the w3schools tutorial on SVG it's comprehensive enough, the rest from that it's just a good use case and use their building blocks (with javascript)
This is how you would create an SVG element for the DOM.
const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
circle.setAttributeNS(null, 'x', 5);
circle.setAttributeNS(null, 'y', 15);
# more code...

I think saving the image as a png file should be just fine. Png compression is lossless and supports transparent images, so drawing a previously saved png file to the canvas should perfectly restore the content without any changes.
Also, I'm not sure if storing it as a svg file would work that well, since svg is a vector graphics format and the canvas is a bitmap. I know it is possible to embed bitmap images in an svg file, but that requires it to be stored in a bitmap format in the first place.

Related

Possible to use SVG sprites without needing <svg> for each instance?

I'm attempting to move from font icons (icomoon.io) to SVG sprites. Is it possible to use SVG sprites without needing < svg > markup for each icon instance?
What I really liked about the font icons was that I didn't have to clutter my HTML with any additional elements to get the icon to display. I usually just targeted a simple class on whatever element I wanted the icon to display and then used pseudo selectors to display the icon, e.g.:
<h1 class="news">News</h1>
h1.user:before {
font-family: 'icons';
content: '\news';
}
That made a lot of sense to me, and all of my icons were easily managed almost completely in CSS. I rarely had to touch my HTML as long as my markup contained appropriate classes.
I've since switched my build system to Grunt and thought I'd give SVG sprites a try. Almost every1 article2 I3 can4 find5 on the subject says you need to add an additional SVG element to your markup wherever you want each instance to display, e.g.:
<h1>
<svg class="icon">
<use xlink:href="#icon-news">
</svg>
News
</h1>
That seems like a step backwards to me, at least in the management of markup. To me, an icon is usually presentation that should be separate from document structure. Are we doing it this way simply because of the state of SVG support in browsers?
Ideally, I'd love to be able to do something like this:
<h1 class="news">News</h1>
h1.news:before {
display: inline-block;
width: px;
height: px;
background: url(icons.svg#news) no-repeat;
}
This post seems to be closer to what I'm looking for, but I'm not sure of browser support and how to do it automatically in a build system like Grunt.
SVGs can be loaded as files exactly the same way as other images using <img> tags or CSS background, and can be used as sprites exactly the same way too. The only difference is that you have to specify the size you want it (because it's scalable, so the browser doesn't automatically know how big it is like it does with PNGs).
Depending on how you want to use the image, loading them this way may or may not be suitable as some SVG features aren't available, but it can be done.

Creating an SVG Document in SVG.js issue?

I am new to SVG.js and javascript in general, and I was going over the documentation here http://documentup.com/wout/svg.js#usage/svg-document and was having some issues.
Usage
Create a SVG document
Use the SVG() function to create a SVG document within a given html element:
var draw = SVG('drawing').size(300, 300)
var rect = draw.rect(100, 100).attr({ fill: '#f06' })
so I was assuming from this they want us to call a function so what I've gathered from messing around a little in Three.js is that I need to do
<script>
function SVG()
{
//Use the SVG() function to create a SVG document within a given html
var draw = SVG('drawing').size(300, 300)
var rect = draw.rect(100, 100).attr({ fill: '#f06' })
}
</script>
within the body tag. This doesn't work however. When calling SVG(); I get an error
Uncaught RangeError: Maximum call stack size exceeded (15:22:47:898 | error, javascript)
at SVG (:18:13)
at SVG (:20:12)
at SVG (:20:12)
at SVG (:20:12)
at SVG (:20:12)
at SVG (:20:12)
There are other ways I can do it as mentioned, but it seems that the easiest method would be to call a function, but again I'm not sure if I'm doing this correctly.
I have a background in Java, just getting off of a project with JMonkeyEngine, so I'm not new to programming, but confused with what exactly I need to do with this, since the documentation is extremely vague and seems to suggest that you need to understand their terminology as to where to put the code.
I have also found a few other librarieslike snap.svg, d3, and raphael
http://d3js.org/
raphaeljs.com/
snapsvg.io/
I'm really just trying to create a bunch of pictures/colored boxes (interchangable so essentially a box with an image that can then be turned off and be displayed as a color) with borders, that can respond to mouse even of clicking and dragging around on desktop and mobile browsers. Essentially not much, but it seems like these all have similar features just a different coding feel.
Any advice?
Thank you everyone!
As said by Nils, there is a Hello World example here: https://stackoverflow.com/tags/svg.js/info
You also find plenty of documentation and examples to see what you have to do.
//Use the SVG() function to create a SVG document within a given html
var canvas = SVG(idOfElement)
// now an svg was created in the element with the id
// draw a rectangle
canvas.rect(100,100)

SVG fill transition doesn't work when embeded by using <img> tag

I defined CSS transition rules in my svg. It's something like:
#mark #bg {
transition: fill 200ms;
fill: #245575;
}
#mark:hover #bg {
fill: #ff5c26;
}
When I drag it into browser's blank page and test it, the transition works fine. But if I embed the svg into my website using <img src="images/mark.svg" alt="">, the transition doesn't work.
Did I miss something?
Images either via <img> tags of via the CSS background-image image property cannot be interactive and have other restrictions in order to maintain user's privacy and security.
If you ask yourself "could I do this if the image was a .png or a .gif?" then you'll be on the right lines. Browsers have deliberately chosen to keep to the same mental model for SVG files so that the capability of images is easy to understand.
If you want transitions to work you'll need to use an <object> or <iframe> tag or embed the SVG inline in the html document.

Scale an SVG (in Dart) using viewBox doesn't work

I recently started working with Google Dart (www.dartlang.org) and playing with SVG.
I am trying to scale a generated SVG to fit into a <div> using a viewBox.
People on StackOverflow already gave me a lot of help.
I am now able to scale paths like this: Dart create and transform an SVG path
But is seems that viewBox is made for scale-to-fit and using it would save me from scaling all paths in the svg separately. That is why I want to use a viewBox.
I tried the following:
// get bounding box of the created svg
Rect bb = path.getBBox();
// create a viewBox for the svg to fit in the div
var viewBox = svg.viewBox.baseVal
..x = bb.x
..y = bb.y
..width = bb.width
..height = bb.height;
// center the image inside the div
svg.preserveAspectRatio.baseVal
..meetOrSlice = PreserveAspectRatio.SVG_MEETORSLICE_MEET
..align = PreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID;
But no scaling happens.
How would I solve this?
While writing this question and retrying to make sure I tried anything before asking here, I found the following solution.
It seems like Dartium (Chrome with a native Dart VM) has a bug (issue 12224) where changes to the viewBox are not reflected directly.
Adding the following code after changes to the viewBox forces Dartium to somehow resize to the requested size:
// add an empty ```<g>``` element to force svg resize
SvgElement g = new SvgElement.tag('g');
svg.append(g);

wkhtmltopdf failure when embed an SVG

Has anyone in this vast space has ever had the luck to successfully create a PDF with an embedded SVG on an HTML? I've been receiving segmentation fault all the time.
Or perhaps is there any other way to embed an SVG into an HTML file and then export it to PDF instead of wkhtmltopdf?
I had similar problem. Seems like javascript embedded in SVG image can cause segmentation fault.
I was generating SVG graphs using pygal Python module. To successfully generate PDF from HTML with SVG graphs I had to do several things:
Remove reference to javascript. (In case of pygal add js=() key to a graph constructor).
Specify image size in svg tag, like
<svg ... width="300" height="200">
(In case of pygal use explicit_size keywoard)
Embed SVG image into img tag in base64 encoded form, like
<img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0...">
I was using 11th version of wkhtmltopdf.
If this fix doesn't work for others, here's what worked for me with chartist.js, and wkhtmltopdf 0.12.2.1 under Ubuntu 64. (Credit to Panokev)
Add this to your javascript before all other JS.
{
Function.prototype.bind = Function.prototype.bind || function (thisp) {
var fn = this;
return function () {
return fn.apply(thisp, arguments);
};
};
Definitively set width style for chart div, for example - style="width:950px;"
Right .. I managed to pull it off finally ... all needed was a bit of treatment on the original eps file. I opened the file with illustrator and chose to "flatten transparency" .. maybe what it does was to flatten the many layers of the file or something .. then save as svg .. and it rendered nicely in the PDF ..
Hopefully this helps if anyone out there would have the same issue as I did. Thank you! :D
We fixed this problem by adding a width and height attribute to the svg besides the viewbox attribute.

Resources