Downloading a qrcode.js-generated QR code - javascript

I've searched the web countless times trying to find a way to solve this but I've come up empty-handed every time. I have been using qrcode.js to generate QR codes for a website, but I haven't figured out how to download the image once it's been generated. The code I use to generate the QR code looks like this:
var myQR = new QRCode(document.getElementById("qrcode"), {
text: "Made with QR Generator",
width: 128,
height: 128,
colorDark : qrdarkcolor,
colorLight : qrlightcolor,
correctLevel : QRCode.CorrectLevel.H
});
myQR.makeCode(qrdata);
I am trying to find a way to either download the QR code within the div or find the source and create a button that users can click on to download the image. I apologize if this is a commonly asked question, but I've searched many other questions that are similar to this and haven't found a clear answer. I would prefer to keep this site with only HTML, CSS, and Javascript if possible.
Thanks!

The image is generated through the plugin and takes a moment to render, so the method needs to be done with setTimeout. After that, we grab the src of the image and apply it to a download link (a link that has the attribute download in it)
Note this won't work in the snippet sandbox, but it's been tested on a normal web page and works great.
const makeQR = (url, filename) => {
var qrcode = new QRCode("qrcode", {
text: "http://jindo.dev.naver.com/collie",
width: 128,
height: 128,
colorDark: "#000000",
colorLight: "#ffffff",
correctLevel: QRCode.CorrectLevel.H
});
qrcode.makeCode(url);
setTimeout(() => {
let qelem = document.querySelector('#qrcode img')
let dlink = document.querySelector('#qrdl')
let qr = qelem.getAttribute('src');
dlink.setAttribute('href', qr);
dlink.setAttribute('download', 'filename');
dlink.removeAttribute('hidden');
}, 500);
}
makeQR(document.querySelector('#text').value, 'qr-code.png')
#qrcode {
width: 160px;
height: 160px;
margin-top: 15px;
}
<script src="https://cdn.jsdelivr.net/npm/davidshimjs-qrcodejs#0.0.2/qrcode.min.js"></script>
<input id="text" type="text" value="https://stackoverflow.com" style="width:80%" /><br />
<div id="qrcode"></div>
<a id='qrdl' hidden>Download</a>

You can use Qurious to generate QR code in canvas and then download it. Qurious has also its own padding option (it makes white borders around the qr code so it's possible to scan it after download).
Add this at the <head> part:
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrious/4.0.2/qrious.min.js"></script>
Html body:
<canvas id="qrcode"></canvas>
Script:
const makeQR = (your_data) => {
let qrcodeContainer = document.getElementById("qrcode");
qrcodeContainer.innerHTML = "";
new QRious({
element: qrcodeContainer,
value: your_data,
size: 600,
padding:50,
}); // generate QR code in canvas
downloadQR(); // function to download the image
}
function downloadQR() {
var link = document.createElement('a');
link.download = 'filename.png';
link.href = document.getElementById('qrcode').toDataURL()
link.click();
}
makeQR("Your value")

I noticed that the 'qrcodejs' is returning img with blank src on mobile device browsers(Android -> Chrome), whereas it returns an img with valid src (data URI) when you request from mobile as a 'desktop agent'.
You could able to test it by debugging the mobile.

Related

How to save current page as PDF using frontend JavaScript? [duplicate]

I have the following html code:
<!DOCTYPE html>
<html>
<body>
<p>don't print this to pdf</p>
<div id="pdf">
<p><font size="3" color="red">print this to pdf</font></p>
</div>
</body>
</html>
All I want to do is to print to pdf whatever is found in the div with an id of "pdf". This must be done using JavaScript. The "pdf" document should then be automatically downloaded with a filename of "foobar.pdf"
I've been using jspdf to do this, but the only function it has is "text" which accepts only string values. I want to submit HTML to jspdf, not text.
jsPDF is able to use plugins. In order to enable it to print HTML, you have to include certain plugins and therefore have to do the following:
Go to https://github.com/MrRio/jsPDF and download the latest Version.
Include the following Scripts in your project:
jspdf.js
jspdf.plugin.from_html.js
jspdf.plugin.split_text_to_size.js
jspdf.plugin.standard_fonts_metrics.js
If you want to ignore certain elements, you have to mark them with an ID, which you can then ignore in a special element handler of jsPDF. Therefore your HTML should look like this:
<!DOCTYPE html>
<html>
<body>
<p id="ignorePDF">don't print this to pdf</p>
<div>
<p><font size="3" color="red">print this to pdf</font></p>
</div>
</body>
</html>
Then you use the following JavaScript code to open the created PDF in a PopUp:
var doc = new jsPDF();
var elementHandler = {
'#ignorePDF': function (element, renderer) {
return true;
}
};
var source = window.document.getElementsByTagName("body")[0];
doc.fromHTML(
source,
15,
15,
{
'width': 180,'elementHandlers': elementHandler
});
doc.output("dataurlnewwindow");
For me this created a nice and tidy PDF that only included the line 'print this to pdf'.
Please note that the special element handlers only deal with IDs in the current version, which is also stated in a GitHub Issue. It states:
Because the matching is done against every element in the node tree, my desire was to make it as fast as possible. In that case, it meant "Only element IDs are matched" The element IDs are still done in jQuery style "#id", but it does not mean that all jQuery selectors are supported.
Therefore replacing '#ignorePDF' with class selectors like '.ignorePDF' did not work for me. Instead you will have to add the same handler for each and every element, which you want to ignore like:
var elementHandler = {
'#ignoreElement': function (element, renderer) {
return true;
},
'#anotherIdToBeIgnored': function (element, renderer) {
return true;
}
};
From the examples it is also stated that it is possible to select tags like 'a' or 'li'. That might be a little bit to unrestrictive for the most usecases though:
We support special element handlers. Register them with jQuery-style
ID selector for either ID or node name. ("#iAmID", "div", "span" etc.)
There is no support for any other type of selectors (class, of
compound) at this time.
One very important thing to add is that you lose all your style information (CSS). Luckily jsPDF is able to nicely format h1, h2, h3 etc., which was enough for my purposes. Additionally it will only print text within text nodes, which means that it will not print the values of textareas and the like. Example:
<body>
<ul>
<!-- This is printed as the element contains a textnode -->
<li>Print me!</li>
</ul>
<div>
<!-- This is not printed because jsPDF doesn't deal with the value attribute -->
<input type="textarea" value="Please print me, too!">
</div>
</body>
This is the simple solution. This works for me. You can use the javascript print concept and simple save this as pdf.
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script type="text/javascript">
$("#btnPrint").live("click", function () {
var divContents = $("#dvContainer").html();
var printWindow = window.open('', '', 'height=400,width=800');
printWindow.document.write('<html><head><title>DIV Contents</title>');
printWindow.document.write('</head><body >');
printWindow.document.write(divContents);
printWindow.document.write('</body></html>');
printWindow.document.close();
printWindow.print();
});
</script>
</head>
<body>
<form id="form1">
<div id="dvContainer">
This content needs to be printed.
</div>
<input type="button" value="Print Div Contents" id="btnPrint" />
</form>
</body>
</html>
No depenencies, pure JS
To add CSS or images - do not use relative URLs, use full URLs http://...domain.../path.css or so. It creates separate HTML document and it has no context of main thing.
you can also embed images as base64
This served me for years now:
export default function printDiv({divId, title}) {
let mywindow = window.open('', 'PRINT', 'height=650,width=900,top=100,left=150');
mywindow.document.write(`<html><head><title>${title}</title>`);
mywindow.document.write('</head><body >');
mywindow.document.write(document.getElementById(divId).innerHTML);
mywindow.document.write('</body></html>');
mywindow.document.close(); // necessary for IE >= 10
mywindow.focus(); // necessary for IE >= 10*/
mywindow.print();
mywindow.close();
return true;
}
Of course this will open print dialog and user will have to know she/he can select print to pdf option, to get pdf. There may be printer pre-selected and if user confirms may get this document actually printed. To avoid such situation and to provide PDF without any extras, you need to make PDF file. Probably on the server side. You could have tiny html page with invoice only and convert it to PDF file with headless chrome. It's super easy with puppeteer. No need to install/config chrome, just install npm package puppeteer (managed by chrome team) and run it. Keep in mind this will actually launch real chrome just w/o GUI, so you need to have some RAM & CPU for this. Most servers will be fine with low enough traffic. Here is code sample but this must run on the BACKEND. Nodejs. Also it's slow call, it's resources intensive call. You should run it NOT on api call but e.g. after invoice was created - create pdf for it and store, if pdf was not generated yet, just show message to try again in couple minutes.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://your-domain.com/path-to-invoice', {
waitUntil: 'networkidle2',
});
await page.pdf({ path: 'invoice-file-path.pdf', format: 'a4' });
await browser.close();
})();
Learn more here: https://pptr.dev/
if you need to downloadable pdf of a specific page just add button like this
<h4 onclick="window.print();"> Print </h4>
use window.print() to print your all page not just a div
You can use autoPrint() and set output to 'dataurlnewwindow' like this:
function printPDF() {
var printDoc = new jsPDF();
printDoc.fromHTML($('#pdf').get(0), 10, 10, {'width': 180});
printDoc.autoPrint();
printDoc.output("dataurlnewwindow"); // this opens a new popup, after this the PDF opens the print window view but there are browser inconsistencies with how this is handled
}
As mentioned, you should use jsPDF and html2canvas. I've also found a function inside issues of jsPDF which splits automatically your pdf into multiple pages (sources)
function makePDF() {
var quotes = document.getElementById('container-fluid');
html2canvas(quotes, {
onrendered: function(canvas) {
//! MAKE YOUR PDF
var pdf = new jsPDF('p', 'pt', 'letter');
for (var i = 0; i <= quotes.clientHeight/980; i++) {
//! This is all just html2canvas stuff
var srcImg = canvas;
var sX = 0;
var sY = 980*i; // start 980 pixels down for every new page
var sWidth = 900;
var sHeight = 980;
var dX = 0;
var dY = 0;
var dWidth = 900;
var dHeight = 980;
window.onePageCanvas = document.createElement("canvas");
onePageCanvas.setAttribute('width', 900);
onePageCanvas.setAttribute('height', 980);
var ctx = onePageCanvas.getContext('2d');
// details on this usage of this function:
// https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Using_images#Slicing
ctx.drawImage(srcImg,sX,sY,sWidth,sHeight,dX,dY,dWidth,dHeight);
// document.body.appendChild(canvas);
var canvasDataURL = onePageCanvas.toDataURL("image/png", 1.0);
var width = onePageCanvas.width;
var height = onePageCanvas.clientHeight;
//! If we're on anything other than the first page,
// add another page
if (i > 0) {
pdf.addPage(612, 791); //8.5" x 11" in pts (in*72)
}
//! now we declare that we're working on that page
pdf.setPage(i+1);
//! now we add content to that page!
pdf.addImage(canvasDataURL, 'PNG', 20, 40, (width*.62), (height*.62));
}
//! after the for loop is finished running, we save the pdf.
pdf.save('test.pdf');
}
});
}
i use jspdf and html2canvas for css rendering and i export content of specific div as this is my code
$(document).ready(function () {
let btn=$('#c-oreder-preview');
btn.text('download');
btn.on('click',()=> {
$('#c-invoice').modal('show');
setTimeout(function () {
html2canvas(document.querySelector("#c-print")).then(canvas => {
//$("#previewBeforeDownload").html(canvas);
var imgData = canvas.toDataURL("image/jpeg",1);
var pdf = new jsPDF("p", "mm", "a4");
var pageWidth = pdf.internal.pageSize.getWidth();
var pageHeight = pdf.internal.pageSize.getHeight();
var imageWidth = canvas.width;
var imageHeight = canvas.height;
var ratio = imageWidth/imageHeight >= pageWidth/pageHeight ? pageWidth/imageWidth : pageHeight/imageHeight;
//pdf = new jsPDF(this.state.orientation, undefined, format);
pdf.addImage(imgData, 'JPEG', 0, 0, imageWidth * ratio, imageHeight * ratio);
pdf.save("invoice.pdf");
//$("#previewBeforeDownload").hide();
$('#c-invoice').modal('hide');
});
},500);
});
});
One way is to use window.print() function. Which does not require any library
Pros
1.No external library require.
2.We can print only selected parts of body also.
3.No css conflicts and js issues.
4.Core html/js functionality
---Simply add below code
CSS to
#media print {
body * {
visibility: hidden; // part to hide at the time of print
-webkit-print-color-adjust: exact !important; // not necessary use
if colors not visible
}
#printBtn {
visibility: hidden !important; // To hide
}
#page-wrapper * {
visibility: visible; // Print only required part
text-align: left;
-webkit-print-color-adjust: exact !important;
}
}
JS code - Call bewlow function on btn click
$scope.printWindow = function () {
window.print()
}
Note: Use !important in every css object
Example -
.legend {
background: #9DD2E2 !important;
}
Use pdfMake.js and this Gist.
(I found the Gist here along with a link to the package html-to-pdfmake, which I end up not using for now.)
After npm install pdfmake and saving the Gist in htmlToPdf.js I use it like this:
const pdfMakeX = require('pdfmake/build/pdfmake.js');
const pdfFontsX = require('pdfmake-unicode/dist/pdfmake-unicode.js');
pdfMakeX.vfs = pdfFontsX.pdfMake.vfs;
import * as pdfMake from 'pdfmake/build/pdfmake';
import htmlToPdf from './htmlToPdf.js';
var docDef = htmlToPdf(`<b>Sample</b>`);
pdfMake.createPdf({content:docDef}).download('sample.pdf');
Remarks:
My use case is to create the relevant html from a markdown document (with markdown-it) and subsequently generating the pdf, and uploading its binary content (which I can get with pdfMake's getBuffer() function), all from the browser. The generated pdf turns out to be nicer for this kind of html than with other solutions I have tried.
I am dissatisfied with the results I got from jsPDF.fromHTML() suggested in the accepted answer, as that solution gets easily confused by special characters in my HTML that apparently are interpreted as a sort of markup and totally mess up the resulting PDF.
Using canvas based solutions (like the deprecated jsPDF.from_html() function, not to be confused with the one from the accepted answer) is not an option for me since I want the text in the generated PDF to be pasteable, whereas canvas based solutions generate bitmap based PDFs.
Direct markdown to pdf converters like md-to-pdf are server side only and would not work for me.
Using the printing functionality of the browser would not work for me as I do not want to display the generated PDF but upload its binary content.
I was able to get jsPDF to print dynamically created tables from a div.
$(document).ready(function() {
$("#pdfDiv").click(function() {
var pdf = new jsPDF('p','pt','letter');
var specialElementHandlers = {
'#rentalListCan': function (element, renderer) {
return true;
}
};
pdf.addHTML($('#rentalListCan').first(), function() {
pdf.save("caravan.pdf");
});
});
});
Works great with Chrome and Firefox... formatting is all blown up in IE.
I also included these:
<script src="js/jspdf.js"></script>
<script src="js/jspdf.plugin.from_html.js"></script>
<script src="js/jspdf.plugin.addhtml.js"></script>
<script src="//mrrio.github.io/jsPDF/dist/jspdf.debug.js"></script>
<script src="http://html2canvas.hertzen.com/build/html2canvas.js"></script>
<script type="text/javascript" src="./libs/FileSaver.js/FileSaver.js"></script>
<script type="text/javascript" src="./libs/Blob.js/Blob.js"></script>
<script type="text/javascript" src="./libs/deflate.js"></script>
<script type="text/javascript" src="./libs/adler32cs.js/adler32cs.js"></script>
<script type="text/javascript" src="js/jspdf.plugin.addimage.js"></script>
<script type="text/javascript" src="js/jspdf.plugin.sillysvgrenderer.js"></script>
<script type="text/javascript" src="js/jspdf.plugin.split_text_to_size.js"></script>
<script type="text/javascript" src="js/jspdf.plugin.standard_fonts_metrics.js"></script>
If you want to export a table, you can take a look at this export sample provided by the Shield UI Grid widget.
It is done by extending the configuration like this:
...
exportOptions: {
proxy: "/filesaver/save",
pdf: {
fileName: "shieldui-export",
author: "John Smith",
dataSource: {
data: gridData
},
readDataSource: true,
header: {
cells: [
{ field: "id", title: "ID", width: 50 },
{ field: "name", title: "Person Name", width: 100 },
{ field: "company", title: "Company Name", width: 100 },
{ field: "email", title: "Email Address" }
]
}
}
}
...
This example works great.
<button onclick="genPDF()">Generate PDF</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.min.js"></script>
<script>
function genPDF() {
var doc = new jsPDF();
doc.text(20, 20, 'Hello world!');
doc.text(20, 30, 'This is client-side Javascript, pumping out a PDF.');
doc.addPage();
doc.text(20, 20, 'Do you like that?');
doc.save('Test.pdf');
}
</script>
Dissatisfied with the rendering of html2canvas and lack of modern CSS3/JS and print specific CSS support of pdfMake's outdated version of WebKit...
Here's a theoretical solution, it's headless and can render pages faithfully, supports page breaks, margins, different page sizes and can be automated. You can even render WebGl to PDF.
Chrome has a devtools protocol... which has a printtoPDF function
Excerpt: https://gitlab.com/-/snippets/new
Official 20k-SLOC spec: https://github.com/ChromeDevTools/devtools-protocol/blob/master/json/browser_protocol.json
You can use node and https://github.com/GoogleChrome/chrome-launcher to run chrome headless... wait for it to render.
Profit
printToPDF command you'd run on chrome_devtools protocol:
printToPDF({
printBackground: false,
pageWidth: 8.5,
pageHeight: 11,
transferMode: "ReturnAsStream" // or ReturnAsBase64
})
2022 Answer:
To generate PDF from HTML Element and prompt to save file:
import { jsPDF } from "jsPDF"
function generatePDF() {
const doc = new jsPDF({ unit: 'pt' }) // create jsPDF object
const pdfElement = document.getElementById('pdf') // HTML element to be converted to PDF
doc.html(pdfElement, {
callback: (pdf) => {
pdf.save('MyPdfFile.pdf')
},
margin: 32, // optional: page margin
// optional: other HTMLOptions
})
}
<button onclick="generatePDF()">Save PDF</button>
...
To preview PDF without printing:
doc.html(pdfElement, {
callback: (pdf) => {
const myPdfData = pdf.output('datauristring')
}
})
<embed type="application/pdf" src={myPdfData} />
...
For more HTMLOptions:
https://github.com/parallax/jsPDF/blob/master/types/index.d.ts
To capture div as PDF you can use https://grabz.it solution. It's got a JavaScript API which is easy and flexible and will allow you to capture the contents of a single HTML element such as a div or a span
In order to implement it you will need to first get an app key and secret and download the (free) SDK.
And now an example.
Let's say you have the HTML:
<div id="features">
<h4>Acme Camera</h4>
<label>Price</label>$399<br />
<label>Rating</label>4.5 out of 5
</div>
<p>Cras ut velit sed purus porttitor aliquam. Nulla tristique magna ac libero tempor, ac vestibulum felisvulput ate. Nam ut velit eget
risus porttitor tristique at ac diam. Sed nisi risus, rutrum a metus suscipit, euismod tristique nulla. Etiam venenatis rutrum risus at
blandit. In hac habitasse platea dictumst. Suspendisse potenti. Phasellus eget vehicula felis.</p>
To capture what is under the features id you will need to:
//add the sdk
<script type="text/javascript" src="grabzit.min.js"></script>
<script type="text/javascript">
//login with your key and secret.
GrabzIt("KEY", "SECRET").ConvertURL("http://www.example.com/my-page.html",
{"target": "#features", "format": "pdf"}).Create();
</script>
Please note the target: #feature. #feature is you CSS selector, like in the previous example. Now, when the page is loaded an image screenshot will now be created in the same location as the script tag, which will contain all of the contents of the features div and nothing else.
The are other configuration and customization you can do to the div-screenshot mechanism, please check them out here
The following method works fine for my case.
Hide additional parts for a page like the following example
#media print{
body{
-webkit-print-color-adjust: exact; // if you want to enable graphics
color-adjust: exact !important; // if you want to enable graphics
print-color-adjust: exact !important; // if you want to enable graphics
* {
visibility: hidden;
margin:0;
padding:0
}
.print_area, .print_area *{
visibility: visible;
}
.print_area{
margin: 0;
align: center;
}
.pageBreak {
page-break-before : always; // If you want to skip next page
page-break-inside: avoid; // If you want to skip next page
}
}
#page {
size: A4; margin:0mm; // set page layout
background-color: #fff;
}
}
Use the javascript print function to print execution.
<button onclick="window.print()">Print</button>
any one try this
(function () {
var
form = $('.form'),
cache_width = form.width(),
a4 = [595.28, 841.89]; // for a4 size paper width and height
$('#create_pdf').on('click', function () {
$('body').scrollTop(0);
createPDF();
});
//create pdf
function createPDF() {
getCanvas().then(function (canvas) {
var
img = canvas.toDataURL("image/png"),
doc = new jsPDF({
unit: 'px',
format: 'a4'
});
doc.addImage(img, 'JPEG', 20, 20);
doc.save('Bhavdip-html-to-pdf.pdf');
form.width(cache_width);
});
}
// create canvas object
function getCanvas() {
form.width((a4[0] * 1.33333) - 80).css('max-width', 'none');
return html2canvas(form, {
imageTimeout: 2000,
removeContainer: true
});
}
}());

Adding base64 encoded PNG to PDF is not working

I'm trying to embedd an image into a PDF with jsPDF. For some reason this is not working . This is the Code when I create my PDF:
exportPDF () {
const doc = new jsPDF('p', 'pt')
var footer = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAC...'
var header = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgA...'
/* Some other stuff */
doc.addImage(this.output, 'PNG', 400, 400, 500, 500) #This does not work
doc.addImage(header, 'PNG', 0, 0, 600, 139.86) #For some reason these images work
doc.addImage(footer, 'PNG', 0, 800, 600, 54.68)
/* Some other stuff */
doc.save('Containertreppen Teileliste.pdf')
}
The Variable output is passed from another page and therefore not created in the method (I'm using vuejs). In this Variable the Screenshot of a Babylonjs Scene is stored, encoded in base64.
This is the Code when a take the Screenshot:
printDiv() {
this.scene.render();
const self = this
const options = {
type: "dataURL",
};
this.$html2canvas(document.getElementById("renderCanvas"), options).then(function(canvas){
self.output = canvas
})
},
I'm able to display the screenshot in an HTML-element and I can download it as a normal png but for some reason when I try to add it to my PDF the following error occurs in my console:
Error in v-on handler: "Error: Supplied Data is not a valid base64-String jsPDF.convertStringToImageData"
I also tried to put the String as src for an HTML-image-element but it changed nothing.
This is the beginning of the Variable output:
"data:image/png;base64,iVBORw..."
Can someone help me with this?

Ionic 4 html2canvas

I'm trying to capture HTML to image in an Ionic 4 app.
I tried using html2canvas, however, it doesn't work and shows this output in the console:
This is my code:
var element = document.getElementById('capture');
html2canvas(element).then(canvas => {
var imgData = canvas.toDataURL("image/png");
this.socialSharing.share(null, null, imgData);
});
I'm having the same issue. I managed to "fix" it by putting my code out of the <ion-content> tag. My guess is that html2canvas doesn't render shadow DOM elements (which is the case of <ion-content>, as of Ionic 4).
For instance this outputs an empty canvas:
<ion-content>
<div id="capture">
<h1>Test</h1>
</div>
</ion-content>
But the following works:
<div id="capture">
<h1>Test</h1>
</div>
This is not really a solution, but it's good enough for my use...
I was trying this component too but it does not work. The solution I found was to use the dom-to-image library. I attached an example of what I did. You just have to put the file extension you want to convert.
https://www.npmjs.com/package/jspdf
https://www.npmjs.com/package/dom-to-image
import * as jsPDF from 'jspdf';
import domtoimage from 'dom-to-image';
exportPdf(){
const div = document.getElementById('pdf');
const options = { background: 'white', height: 845, width: 595 };
domtoimage.toPng(div, options).then((dataUrl) => {
//Initialize JSPDF
const doc = new jsPDF('p', 'mm', 'a4');
//Add image Url to PDF
doc.addImage(dataUrl, 'PNG', 0, 0, 210, 340);
doc.save('pdfDocument.pdf');
}
}
The latest html2canvas supports shadow dom, like https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js

Browse Image and Insert into Iframe

I was wondering if this is possible.
I want to create a function to retrieve an image and insert into an iframe. The user must be able to choose a file (image/video) and it will be inserted into an iframe.
main.html
<input type="file" id="addImage"> I have used this for the user to choose a file.
<iframe class="frame" id="frame" src="insert.html"></iframe> And this for the iframe. The iframe src is another html document.
insert.html
<span id="edit"></span> is within the insert.html where the image needs to be inserted to.
I don't quite understand how javascript can be used to retrieve the image from the users selection and insert into the iframe.
Is this possible?
Yes, here is an example. The key is to hook onto the iframe and then use its contentWindow.
EDIT
Additionally, I don't know if you meant the browse for file or the drag'n'drop API so I implemented both.
Lots of help from these sources:
file-api : How to interact with the file-api
drag-drop events : Events to key off of when dragging and dropping
And here is a fiddle:
JSFiddle
CSS
*{
font-family: Arial;
}
.section{
width: 400px;
padding: 20px;
margin: auto;
}
#dragDiv{
background-color: #ffffcc;
}
#browseDiv{
background-color: #ccffcc;
}
#iframeDiv{
background-color: #ffcccc;
}
#dropTarget{
width: 300px;
height: 300px;
border-style: dashed;
border-width: 5px;
}
.dropEnabled{
border-color: #999999;
}
.dropEnabled:hover{
border-color: #ff9933;
}
.dropMe{
border-color: #99ff99;
}
JS
/**
* I set up the listeners for dragging and dropping as well
* as creating an iFrame for holding dragged in images
* #returns {undefined}
*/
function main() {
// The div that receives drops and the new iFrame
var targetDiv = document.getElementById("dropTarget"),
iframe = document.createElement("iframe");
// Set the iframe to a blank page
iframe.src = "about:blank";
// Append it to the target
document.getElementById("iframeTarget").appendChild(iframe);
// Drag over is when an object is hovering over the div
// e.preventDefault keeps the page from changing
targetDiv.addEventListener("dragover", function(e) {
e.preventDefault();
this.className = "dropMe";
}, false);
// Drag leave is when the object leaves the div but isn't dropped
targetDiv.addEventListener("dragleave", function(e) {
e.preventDefault();
this.className = "dropEnabled";
}, false);
// Drop is when the click is released
targetDiv.addEventListener("drop", function(e) {
e.preventDefault();
this.className = "dropEnabled";
loadFile(e.dataTransfer.files[0], iframe);
}, false);
document.getElementById("upload").addEventListener("click", function() {
var file = document.getElementById("browsedFile").files[0];
loadFile(file, iframe);
}, false);
}
/**
* Load a file and then put it on an ifrmae
* #param {Element} f The file that needs to get loaded
* #param {Element} destination The iframe that the file is appended to
* #returns {undefined}
*/
function loadFile(f, destination) {
// Make a file reader to interpret the file
var reader = new FileReader();
// When the reader is done reading,
// Make a new image tag and append it to the iFrame
reader.onload = function(event) {
var newImage = document.createElement("img");
newImage.src = event.target.result;
destination.contentWindow.document.getElementsByTagName("body")[0].appendChild(newImage);
};
// Tell the reader to start reading asynchrounously
reader.readAsDataURL(f);
}
// Run the main script
window.onload = main;
HTML
<!DOCTYPE html>
<html>
<head>
<title>I framed it</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
</head>
<body>
<div id="dragDiv" class="section">
<div>The div below receives dragged in files</div>
<div id="dropTarget" class="dropEnabled"></div>
</div>
<div id="browseDiv" class="section">
<div>I upload stuff the boring way</div>
<input type="file" id="browsedFile"><button id="upload">Upload</button>
</div>
<div id="iframeDiv" class="section">
<div>And below me, an iFrame gets created</div>
<div id="iframeTarget"></div>
</div>
</body>
</html>
And here is the result:
And the DOM:
EDIT
A comment was made about how to do this with videos as well. There are several ways to do it, but here is one way that I would do it using the HTML5 <vido> tag which you can find more information on here: HTML Videos.
One tricky thing that I'm sure is rather cludgy is how to say what kind of file you should be loading. I use a switch() on the file's type attribute which usually evaluates to something like: image/png or video/mp4 for MP4 videos. However, this ties you to a specific file format. A better way to do it would be to make a regular expression that figures out if it's just an image or a video and ignore the format since the process is rougly the same for all files of those types.
I added my own regular expression implementation. Probably, not the best, but it allows all appropriate image types to come through now.
Also, I tried using some sample videos from Apple which can be found here: Sample QuickTime Movies. However, those did not work for some reason. So after that, I just downloaded the sample videos that W3Schools uses in their tutorial. I'm telling you this so that in case you try it and it doesn't work, it might be the file itself and not your code.
Edited loadFile() Function
/**
* Load a file and then put it on an ifrmae
* #param {Element} f The file that needs to get loaded
* #param {Element} destination The iframe that the file is appended to
* #returns {undefined}
*/
function loadFile(f, destination) {
// Make a file reader to interpret the file
var reader = new FileReader(),
loaderFunc = null,
typeRegEx = /^(\w+)\//,
contentType = f.type.match(typeRegEx)[1];
// Figure out how to load the data
switch (contentType) {
case "video":
loaderFunc = function(event) {
var newVideo = document.createElement("video"),
newVideoSource = document.createElement("source");
newVideo.width = 300;
newVideo.height = 300;
newVideo.setAttribute("controls");
newVideoSource.src = event.target.result;
newVideoSource.type = f.type;
destination.contentWindow.document.getElementsByTagName("body")[0].appendChild(newVideo);
newVideo.appendChild(newVideoSource);
};
break;
case "image":
loaderFunc = function(event) {
var newImage = document.createElement("img");
newImage.src = event.target.result;
destination.contentWindow.document.getElementsByTagName("body")[0].appendChild(newImage);
};
break;
default:
console.log("Unknown file type");
return;
}
// We should have returned, but just make sure
if (loaderFunc) {
// When the reader is done reading,
// Make a new image tag and append it to the iFrame
reader.onload = loaderFunc;
// Tell the reader to start reading asynchrounously
reader.readAsDataURL(f);
}
}
You can manipulate directly an iframe from an other if they are from same domain.
See jQuery/JavaScript: accessing contents of an iframe
What you can do if this is not the case is :
Setting up a communication process between both pages (see How to communicate between iframe and the parent site?)
or
Uploading your file to a server, and refresh the "insert.html" page to display the uploaded image.

Recreate Fabric.js canvas and export as an image?

I have a canvas where the user can create a design using images in another div that they click, sending it to the Fabric.js canvas where it gets moved around and so on. Since the canvas's size is width="270"and height="519", smaller than what the finished product is, I need to recreate it with a canvas that has the size width="1001"and height="1920" and then screenshot it so that I get it all in 1 single image. How do I do this?
This is what my code looks like so far:
HTML
<div id="CanvasContainer">
<canvas id="Canvas" width="270" height="519"></canvas>
</div>
CSS
#CanvasContainer {
width: 270px;
height: 519px;
margin-left: 15px;
}
#Canvas {
overflow: hidden;
}
JAVASCRIPT
//Defining Canvas and object array
var canvas = new fabric.Canvas('Canvas');
//When clicked
$(document).ready(function () {
$("#Backgrounds img").click(function () {
var getId = $(this).attr("id");
//adding all clicked images
var imgElement = document.getElementById(getId);
var imgInstance = new fabric.Image(imgElement, {
left: 135,
top: 259,
width: 270,
height: 519
});
//Corner color for clicked images
imgInstance.set({
borderColor: 'white',
cornerColor: 'black',
transparentCorners: false,
cornerSize: 12
});
canvas.add(imgInstance);
});
});
Fabric has a built in function to convert to data urls. You can use the download property of a link to make the link a download link. Finally you can use the DOM click() function to emulate clicking the download link. The end result is:
function download(url,name){
// make the link. set the href and download. emulate dom click
$('<a>').attr({href:url,download:name})[0].click();
}
function downloadFabric(canvas,name){
// convert the canvas to a data url and download it.
download(canvas.toDataURL(),name+'.png');
}
now when you want to download the canvas call
downloadFabric(canvas,'<file name>');

Categories

Resources