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>
Related
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)
I have a very simple svg
<div id="printId">
test
<svg height="100" width="100">
<circle cx="50" cy="50" r="40" />
</svg>
</div>
and trying to print it with html2canvas and jspdf. But whatever I do I get an error
Error loading svg data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20height%3D%22100%22%20width%3D%22100%22%20style%3D%22-webkit-writing-mode%3A%20horizontal-tb%3B%20-webkit-user-modify%3A%20read-only%3B%20-webkit-user-drag%3A%20auto%3B%20-web
Oe.error # html2canvas-1.1.2.min.js:20
and test.pdf file with just word test in it.
I googled this for about 3 hours, and in every place people recommend settings width/height atributes. Which, as you can see, doesn't help in my case.
I've simplified it as much as I could. Here is the full index.html I use:
<!DOCTYPE html>
<html>
<head></head>
<body>
<div id="printId">
test
<svg height="100" width="100">
<circle cx="50" cy="50" r="40" />
</svg>
</div>
<script src="../../../script/jsPDF/jspdf-2.3.1.umd.min.js" defer></script>
<script src="../../../script/jsPDF/html2canvas-1.1.2.min.js" defer></script>
<script>
function saveAsPDF(divId, usersName, certNumber = '', type = 'old')
{
const { jsPDF } = window.jspdf;
const pdf = new jsPDF();
var source = document.getElementById("printId");
pdf.html(
source, {
callback: function (pdf) {
pdf.save("test.pdf");
},
});
}
</script>
<input type='submit'
onclick='saveAsPDF();'
value='save'>
</body>
</html>
I also tried all possible versions of html2canvas:
1.1.2
1.1.5
1.2.2
1.3.2
and two versions of jspdf:
2.1.1
2.3.1
And two browsers: Chrome and Opera.
What can be my issue?
Edit:
I managed to make html2canvas work on it's own with the document below. Now the question is how to make it work with jspdf together:
<html>
<head></head>
<body>
<div id="printId">
this is circle:
<svg height="100" width="100">
<circle cx="50" cy="50" r="40" />
</svg>
</div>
<hr>
<h4>Image of above HTML content...</h4>
<div id="canvasImg"></div>
<script src="../../../script/jsPDF/html2canvas-1.3.2.min.js"></script>
<script>
html2canvas(document.getElementById('printId')).then(function(canvas) {
var canvasImg = canvas.toDataURL("image/jpg");
document.getElementById('canvasImg').innerHTML = '<img src="'+canvasImg+'" alt="">';
});
</script>
</body>
</html>
It looks like jspdf is not able to add svg as vector graphic to a page. There are three options:
Use svg2pdf instead of jspdf to convert svg to pdf on it's own.
Use addSvgAsImage function of jspdf to place an svg in the pdf page manually.
Convert svg to jpg first, then use jspdf.
I've chosen the 3rd option and wrote a function, which I run before saving canvas as pdf:
htmlToJpg: function()
{
var canvas = document.querySelector('.to-print');
screenWidth = parseFloat(window.getComputedStyle(canvas).width);
var problematic = document.querySelectorAll('.convert-to-jpg');
problematic.forEach(function(el) {
html2canvas(el,
{
scale: 2480/screenWidth // 2480px - size for A4 paper, 300 dpi
}
)
.then(function(canvas) {
var img = canvas.toDataURL("image/jpeg");
el.innerHTML = '<img src="' + img + '" class="img">';
});
});
}
import html2canvas from 'html2canvas';
import { jsPDF as JsPDF } from 'jspdf';
import { useCallback, useEffect } from 'react';
export const useDownloadPdf = (name: string, isReady: boolean) => {
useEffect(() => {
if (isReady) {
const fileName = `${name}.pdf`;
const pdf = new JsPDF({
orientation: 'p',
unit: 'mm',
format: 'a4',
putOnlyUsedFonts: true,
});
const convertElements = document.querySelectorAll('.convert-on-pdf');
const elements = Array.from(convertElements) as HTMLElement[];
if (elements.length > 0) {
Promise.all(
elements.map(async (element) => {
const canvas = await html2canvas(element);
element.replaceWith(canvas);
}),
).then(() => {
pdf.html(document.body, {
callback: (generatedPdf) => {
generatedPdf.save(fileName)
},
});
});
} else {
pdf.html(document.body, {
callback: (generatedPdf) => {
generatedPdf
.save(fileName)
},
});
}
}
}, [isReady, name, setAtribute]);}
I'm developing part of application in which i need to generate reports on some user athletes and preview on chart following:
dates and number of exposures to certain lift
Here is the html and javascript:
<div class="chart" id="bar-chart-#exposureReport.AthleteId" style="height: 300px; -webkit-tap-highlight-color: rgba(0, 0, 0, 0);">
<script>
drawChart('#exposureReport.CoachId', '#exposureReport.AthleteId');
function drawChart(coachId, athleteId) {
//debugger;
$.getJSON('#Url.Action("FetchAthleteChartData", "Reports")?coachId=' + coachId + '&athleteId=' + athleteId,
function (data) {
var datax = JSON.stringify(data);
alert(datax);
Morris.Bar({
element: 'bar-chart-' + athleteId,
resize: true,
barSizeRatio: 0.12,
barGap: 3,
data: $.parseJSON(datax),
barColors: ['#ff0000'],
xkey: ['exposures'],
ykeys: ['dates'],
labels: ['Times exposed'],
hideHover: 'auto'
});
}
);
}
</script>
</div>
I foreach all the reports i have on current view and preview them. I want to show a chart for each report.
I call the javascript function and pass the coachId and athleteId values and let server fetch the data for me:
[HttpGet]
public JsonResult FetchAthleteChartData(string coachId, string athleteId)
{
var exerciseReport =
_applicationUserOperations.GetAllExposureReportsForCoachByAthleteId(coachId, athleteId);
var filteredDates = exerciseReport.Exposures.Select(x => x.ExposureDate).ToList();
var filteredExposures = exerciseReport.Exposures.Select(x => x.NumberOfLifts).ToList();
var result = new
{
Dates = filteredDates,
Exposures = filteredExposures
};
return Json(result);
}
When my alert(datax) triggers it shows (I have only one training/exercise/lift entry atm):
{"dates":["2018-06-01T00:00:00"],"exposures":[5]}
Is this correct format to parse ? How do I parse it so the chart data can understand it and display it.
I am converting an HTML string into a pdf document using following code.
It converts the HTML to pdf well enough, but when I add the an img tag to the HTML it does not render the image in the pdf.
Here is the code I am using.
var htmlString="<H1>Hello This is Text</H1> <img src='zid.png'>";
function generatePDF(htmlString) {
if(htmlString!=null) {
alert("Html String: "+htmlString);
Ti.App.fireEvent("generatePDFfromString",{
"htmlString":htmlString,
"fileName":'MyFileName.pdf'
});
}
};
function gotPDF(filePath){
alert("Html String: "+filePath);
Ti.App.fireEvent("sendEmail",{
"fileURL":filePath,"subject":'My File Subject',
"messageBody":"",
"toReceipients":[""]
});
}
Try this:
Before
var htmlString="<H1>Hello This is Text</H1> <img src='zid.png'>";
After
var htmlString="<H1>Hello This is Text</H1> <img src='zid.png'/>";
I have a php-file that sends an SVG header and draws itself partly with JavaScript. Everything works fine when I show the SVG directly in the browser. However, when I embed it in an <img>, then the JavaScript seems not to be executed. Maybe I am doing something wrong?
Here is the php-file (testsvg.php):
<?php
header('Content-type: image/svg+xml');
?>
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width="800"
height="600"
id="example_text">
<g id="layer1">
<text
x="100"
y="100"
id="text_holder">
<?php echo filter_input(INPUT_GET, 'text'); ?>
</text>
</g>
<script type="text/javascript">
function create_from_rect (client_rect, offset_px) {
if (! offset_px) {
offset_px=0;
}
var box = document.createElementNS(
document.rootElement.namespaceURI,
'rect'
);
if (client_rect) {
box.setAttribute('x', client_rect.left - offset_px);
box.setAttribute('y', client_rect.top - offset_px);
box.setAttribute('width', client_rect.width + offset_px * 2);
box.setAttribute('height', client_rect.height + offset_px * 2);
}
return box;
}
function add_bounding_box (text_id, padding) {
var text_elem = document.getElementById(text_id);
if (text_elem) {
var f = text_elem.getClientRects();
if (f) {
var bbox = create_from_rect(f[0], padding);
bbox.setAttribute(
'style',
'fill: none;'+
'stroke: black;'+
'stroke-width: 0.5px;'
);
text_elem.parentNode.appendChild(bbox);
}
}
}
add_bounding_box('text_holder', 10);
</script>
</svg>
(The SVG/JavaScript is mostly taken from How can I draw a box around text with SVG?.)
When I open this file directly in the browser, e.g. with http://localhost/testsvg.php?text=Test it draws a proper box around the text Test.
However, when I embed it with an <img>, e.g. with <img src="testsvg.php?text=Test" alt="">, it does not show the box.
To protect user's privacy, script is not run in images. There are other restrictions.
When thinking of an image it helps to have the mental model "could I do this if I used a raster image"? If you bear that in mind you won't go far wrong as that's basically the model the browsers implement.
Your alternatives are to use <object> or <iframe> tags instead of <img> as they do allow scripting.