Using AJAX I send a svg image to Django using the following function:
function uploadSVG(){
var svgImage = document.getElementById("SVG");
var serializer = new XMLSerializer();
var svgStr = serializer.serializeToString(svgImage);
$(document).ready(function(){
$.post("ajax_upload_svg/",
{
csrfmiddlewaretoken: csrftoken,
svgImage: svgStr
},
function(){
console.log('Done')
});
});
}
In Django I end up with the svg image as a string using the following function:
def uploadSVG(request):
svgImg = request.POST.get('svgImage')
return HttpResponse('')
The string I get looks like this:
<svg xmlns="http://www.w3.org/2000/svg" id="SVG" width="460" height="300" style="border:2px solid #000000"><rect x="150" y="70" width="160" height="130" fill="#292b2c"/></svg>
How can I convert this svg string into a svg file?
The solution is:
with open("svgTest.svg", "w") as svg_file:
svg_file.write(svgImg)
Note: See the solution below!
The Problem
By default both JS and jQuery will remove closing tags for empty <foreignObject>'s. Normally this wouldn't be a problem. However, in IE11 the following warning will be thrown due to the self-closing elements.
HTML1500: Tag cannot be self-closing. Use an explicit closing tag.
Case Study
I'm attempting to utilize Gulp to add closing tags to a series of SVG files. SVG files are formatted as such initially:
Email.svg,
<svg width="24" height="24" viewBox="0 0 24 24">
<path fill="#AFAFB0" fill-rule="evenodd" d="M1,5 L23,5 C23.5522847,5 24,5.44771525 24,6 L24,18 C24,18.5522847 23.5522847,19 23,19 L1,19 C0.44771525,19 6.76353751e-17,18.5522847 0,18 L0,6 C-6.76353751e-17,5.44771525 0.44771525,5 1,5 Z M21.2034005,7.09747208 L12,13.8789251 L2.79659952,7.09747208 C2.57428949,6.93366469 2.26127947,6.98109045 2.09747208,7.20340048 C1.93366469,7.42571051 1.98109045,7.73872053 2.20340048,7.90252792 L11.7034005,14.9025279 C11.8797785,15.0324907 12.1202215,15.0324907 12.2965995,14.9025279 L21.7965995,7.90252792 C22.0189095,7.73872053 22.0663353,7.42571051 21.9025279,7.20340048 C21.7387205,6.98109045 21.4257105,6.93366469 21.2034005,7.09747208 Z"/>
</svg>
In my gulpfile I'm utilizing gulp-cheerio to attempt to manipulate the HTML by adding the closing tag to any self-closing elements.
gulpfile.js
const gulp = require('gulp');
const cheerio = require('gulp-cheerio');
const rootPath = './src/assets';
const paths = {
svg: {
in: `${rootPath}/icons/raw/**/*.svg`,
out: `${rootPath}/icons/svg`,
}
};
const svg = () => {
return gulp
.src(paths.svg.in)
.pipe(cheerio({
run: ($, file) => {
const updatedHtml = $.html().replace(/<\s*([^\s>]+)([^>]*)\/\s*>/g, '<$1$2></$1>');
// Update self-closing elements to have a closing tag
$('svg').replaceWith(updatedHtml);
}
}))
.pipe(gulp.dest(paths.svg.out));
};
If I console.log the updatedHtml it will have the closing tag. However, when I utilize .html() or .replaceWith() the output has a self-closing tag.
I have also tried the gulp-replace package. The below producse the same result as the above.
const svg = () => {
return gulp
.src(paths.svg.in)
.pipe(replace(/<\s*([^\s>]+)([^>]*)\/\s*>/g, '<$1$2></$1>'))
.pipe(gulp.dest(paths.svg.out));
};
Question
How do I get the output to include the closing tag? Is there a better package for this or is this not really possible?
Feels like a work-around but got the SVG saving by removing .pipe(gulp.dest(paths.svg.out)); and instead making use of fs.
const gulp = require('gulp');
const cheerio = require('gulp-cheerio');
const fs = require('fs');
const rename = require('gulp-rename');
const rootPath = './src/assets';
const paths = {
svg: {
in: `${rootPath}/icons/raw/**/*.svg`,
out: `${rootPath}/icons/svg`,
}
};
const svg = () => {
let dirName;
let fileName;
return gulp
.src(paths.svg.in)
.pipe(rename((path) => {
// Ensure the file name is kebob-case
path.basename = path.basename
.replace(/[^A-Za-z0-9\ ]/g, '')
.replace(/([a-z])([A-Z])/g, '$1-$2')
.replace(/\s+/g, '-')
.toLowerCase();
dirName = path.dirname;
fileName = path.basename;
}))
.pipe(cheerio({
run: ($, file) => {
$('svg').attr('class', `svg-${fileName}`);
const path = `${paths.svg.out.svg}/${dirName}/${fileName}.svg`;
const updatedHtml = $.html().replace(/<\s*([^\s>]+)([^>]*)\/\s*>/g, '<$1$2></$1>');
fs.writeFile(path, updatedHtml);
}
}))
};
which, based on the above SVG, returns
<svg width="24" height="24" viewbox="0 0 24 24" class="svg-email">
<path fill="#AFAFB0" fill-rule="evenodd" d="M1,5 L23,5 C23.5522847,5 24,5.44771525 24,6 L24,18 C24,18.5522847 23.5522847,19 23,19 L1,19 C0.44771525,19 6.76353751e-17,18.5522847 0,18 L0,6 C-6.76353751e-17,5.44771525 0.44771525,5 1,5 Z M21.2034005,7.09747208 L12,13.8789251 L2.79659952,7.09747208 C2.57428949,6.93366469 2.26127947,6.98109045 2.09747208,7.20340048 C1.93366469,7.42571051 1.98109045,7.73872053 2.20340048,7.90252792 L11.7034005,14.9025279 C11.8797785,15.0324907 12.1202215,15.0324907 12.2965995,14.9025279 L21.7965995,7.90252792 C22.0189095,7.73872053 22.0663353,7.42571051 21.9025279,7.20340048 C21.7387205,6.98109045 21.4257105,6.93366469 21.2034005,7.09747208 Z"></path>
</svg>
I am creating a project using angularjs. I have problem while converting html and svg to pdf. I am using the plugins:
Simple html is converted to pdf, but svg is not converting into pdf.
Here is my sample code which works only for html:
var html = document.getElementById('container_div');
html2canvas(html, {
useCORS: true,
allowTaint: true,
letterRendering: true,
onrendered: function (canvas) {
var data = canvas.toDataURL();
var docDefinition = {
content: [{
image: data,
width: 510,
}]
};
pdfMake.createPdf(docDefinition).download('price-calculation-' + $scope.getDateTimeFormat("YYYY-MM-DD-hh:mm:ss") + '.pdf');
$("#price-pdf-content").hide()
$('#export-pricing-model').modal('hide');
}
});
Here is html:
<div class="row" id="container_div">
here are some divs which is converted to pdf
-------
----------
<svg id="svg_0" width="262" height="33" style="z-index:201;position:absolute;left:209px;top:89px" source-endpoint="b0668836-0ffb-ac83-fed3-e6c0e7b708df" destination-endpoint="83669f6e-6d12-aa90-717d-1c5e1a509809"><line id="line_0" class="line" x1="252" y1="23" x2="10" y2="10" stroke="#99ca3c" stroke-width="3" linkuuid="2c03ba9a-4dbe-e4b9-51ac-8a4038012189"></line></svg>// this svg is not converted
</div>
I need to convert a svg into a png. I tried using this code
<!DOCTYPE html>
<meta charset="utf-8">
<style>
path {
stroke: #000;
fill-opacity: .8;
}
</style>
<body>
<div id="svg">
<?php include 'small.svg'; ?>
</div>
<button id="save">Save as Image</button>
<h2>SVG dataurl:</h2>
<div id="svgdataurl"></div>
<h2>SVG converted to PNG dataurl via HTML5 CANVAS:</h2>
<div id="pngdataurl"></div>
<canvas width="960" height="500" style="display:none"></canvas>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var svg = document.querySelector( "svg" );
var svgData = new XMLSerializer().serializeToString( svg );
var canvas = document.createElement( "canvas" );
var ctx = canvas.getContext( "2d" );
var img = document.createElement( "img" );
img.setAttribute( "src", "data:image/svg+xml;base64," + btoa( svgData ) );
img.onload = function() {
ctx.drawImage( img, 0, 0 );
// Now is done
console.log( canvas.toDataURL( "image/png" ) );
};
document.getElementById("pngdataurl").appendChild(img);
</script>
but it doenst work. im pretty sure it's because im using an image pattern, rect and a clip path to product my SVG. I say that because i tried this code with just the path object and it worked fine. I also tried using image magic with this code
<?php
error_reporting(E_ALL);
$svg ="small.svg";
$mask = new Imagick('mask.png');
$im = new Imagick();
//$im->setBackgroundColor(new ImagickPixel('transparent'));
$im->readImageBlob($svg);
$im->setImageFormat("png32");
$im->compositeImage( $mask, imagick::COMPOSITE_DEFAULT, 0, 0 );
header('Content-type: image/png');
echo $im;
?>
Fatal error: Uncaught exception 'ImagickException' with message 'no decode delegate for this image format `' # error/blob.c/BlobToImage/346' in /home/[path to file]:10 Stack trace: #0 /home/path to file: Imagick->readimageblob('small.svg') #1 {main} thrown in /home/[path to file] on line 10
i would rather do this with js if possible. please help...my boss really hates me right now. Here is my svg
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 3384.2 2608.6" enable-background="new 0 0 3384.2 2608.6" xml:space="preserve">
<defs>
<pattern id="img1" patternUnits="userSpaceOnUse" width="100%" height="100%">
<image xlink:href="https://upload.wikimedia.org/wikipedia/commons/7/71/Weaved_truncated_square_tiling.png" x="0" y="0" width="100%" height="100%" />
</pattern>
</defs>
<rect width="3384.2" height="2608.6" clip-path="url(#shirt)" fill="url(#img1)" />
<clipPath id="shirt">
<path fill-rule="evenodd" clip-rule="evenodd" fill="url(#img1)" d="[coordinates that are too long for this post ]"/>
</clipPath>
</svg>
I had this issue recently too, at least with the pattern fills - it seems to be an issue with remote images, so if you base64 encode them into a data URL, it works fine:
var img = new Image();
img.onload = function () {
var canvas = document.createElement('canvas');
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
canvas.getContext('2d').drawImage(img, 0, 0);
var patternImage = document.createElementNS('http://www.w3.org/2000/svg', 'image');
patternImage.setAttributeNS('http://www.w3.org/1999/xlink', 'href', canvas.toDataURL());
};
img.src = patternImageUrl;
You can then add/update this image in a pattern def (or do this once and hardcode the result of canvas.toDataURL() into the pattern image href).
I'm just curious - is it possible to send by SVG image code in the following way?
<original div with inline SVG> -> Input field -> <final DIV>
I want to use following code:
Copy-1
<div id="source-1">
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<rect x="10" y="10" height="100" width="100"
style="stroke:#ff0000; fill: #0000ff"/>
</svg>
</div>
<input name="dynamichidden-637" value="" id="pole" />
<br />
Copy-2
<div id="source-2"></div>
and Jquery:
jQuery( document ).ready(function( $ ) {
$('#copy-1').click(function() {
var value = $('#source-1').html();
var input = $('#pole');
input.val('')
input.val(input.val() + value);
return false;
});
$('#copy-2').click(function() {
$('#pole').appendTo('#source-2');
return false;
});
});
So my question is - is it possible to achieve it in that way? or using somehow other solution which will allow me to transfer svg code from one page to another without storing the data in Database? This is JSfiddle:
http://jsfiddle.net/v2br8/16/
You just need to create the copy using the value of the input:
var value = $('#pole').val();
var copy = $(value);
copy.appendTo('#source-2');
or simply:
$($('#pole').val()).appendTo('#source-2');
DEMO
Try: source-2.innerHTML=source_1.innerHTML