Download Image by clicking on button using JavaScript - javascript

I have this image with a data URL and a button.
Now, I want to download that image using JavaScript. So far I got this code but after download the image its saying: It looks like we don't support this format.
<img src="data:image/png;base64,iVBORw0KGgoA....." class="filterImage">
<input type="button" name="button" value="Save" id="saveImg" class="btn btn-primary float-right">
function saveImage() {
let image = document.querySelector(".filterImage");
var img = new Image();
img.onload = function() {
let canvas = document.createElement("canvas");
let width = canvas.width;
let height = canvas.height;
let context = canvas.getContext("2d");
context.drawImage( image, 0, 0, width, height );
}
img.src = image.src;
let link = document.createElement('a');
link.download = "image.png";
link.style.opacity = "0";
link.href = image.src;
document.body.append(link);
link.click();
link.remove();
}
saveImage(); // For testing purpose I am directly calling this function
Is there anything I am wrong? How can I solve it?

Some browsers do not allow links to be clicked programmatically (by way of ~link.click()); for example, when I try to do so, Chrome navigates to "#blocked".

Related

Download svg as png in react js

I tried to download the svg tag element, actually the image that the svg renders using the next function:
// Get the SVG element
const svg = document.getElementsByTagName('svg')[0];
const canvas = document.createElement('canvas');
canvas.width = svg.clientWidth;
canvas.height = svg.clientHeight;
const img = new Image();
img.src = `data:image/svg+xml;utf8,${new XMLSerializer().serializeToString(
svg,
)}`;
img.onload = function() {
console.log(img)
canvas.getContext('2d')?.drawImage(img, 0, 0);
};
const a = document.createElement('a');
a.download = 'my-image.png';
a.href = canvas.toDataURL();
a.click();
When i click on the dowsnload buttoon, the image is downloaded but it is black without any character. Why it is hapening and how to get a valid image?
PS: i investigated a lot of answer on the site but they don;t help. If someone will help with my example it will help me a lot.
The error occurs because you bring in an asynchronous context and don't wait for that and directly downloading the image.
You can avoid it by moving the "download part" (see example 1) into the onload function or by packing away the onload and hoping that it will load fast enough (example 2).
Example 1:
//...
img.onload = function() {
console.log(img)
canvas.getContext('2d')?.drawImage(img, 0, 0);
const a = document.createElement('a');
a.download = 'my-image.png';
a.href = canvas.toDataURL();
a.click();
};
Example 2:
//...
canvas.getContext('2d')?.drawImage(img, 0, 0);
const a = document.createElement('a');
a.download = 'my-image.png';
a.href = canvas.toDataURL();
a.click();

Signature pad doesn't draw on mobile

I have a signature pad in a laravel project that work in desktop but when I test in mobile it doesn't work.
I search a lot about this problem, I tried from another ways...
I check meta tags, I check cdnjs link, I create a new view to put just this peace of code and don't work. I don't know what is the problem.
If I go to demo page(http://szimek.github.io/signature_pad/) and try run this on mobile works!
So, I found an example and I tried to do this exactly in my laravel project and doesn't work. After that I put the same code in jsfiddle and works (https://jsfiddle.net/6brfy7gq/1/).
It works in desktop, I can draw, save image, all things but when I try mobile don't work. But as you can check the same code in jsfiddle works in mobile. I noticed that I can't scroll the page above canvas in jsfiddle mobile but in my laravel project it scrolls. Maybe this is the problem.
I don't know what to try more!
So, what is the diferences between my code and this?
In js file I have the code inside document ready like this:
$(document).ready(function ()
{
var wrapper = document.getElementById("signature-pad");
var clearButton = wrapper.querySelector("[data-action=clear]");
var savePNGButton = wrapper.querySelector("[data-action=save-png]");
var canvas = document.getElementById('signature-canvas');
// Adjust canvas coordinate space taking into account pixel ratio,
// to make it look crisp on mobile devices.
// This also causes canvas to be cleared.
function resizeCanvas() {
var ratio = Math.max(window.devicePixelRatio || 1, 1);
canvas.width = canvas.offsetWidth * ratio;
canvas.height = canvas.offsetHeight * ratio;
canvas.getContext("2d").scale(ratio, ratio);
}
// On mobile devices it might make more sense to listen to orientation change,
// rather than window resize events.
window.onresize = resizeCanvas;
resizeCanvas();
var signaturePad = new SignaturePad(canvas);
function download(dataURL, filename) {
var blob = dataURLToBlob(dataURL);
var url = window.URL.createObjectURL(blob);
var a = document.createElement("a");
a.style = "display: none";
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
}
// One could simply use Canvas#toBlob method instead, but it's just to show
// that it can be done using result of SignaturePad#toDataURL.
function dataURLToBlob(dataURL) {
// Code taken from https://github.com/ebidel/filer.js
var parts = dataURL.split(';base64,');
var contentType = parts[0].split(":")[1];
var raw = window.atob(parts[1]);
var rawLength = raw.length;
var uInt8Array = new Uint8Array(rawLength);
for (var i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
return new Blob([uInt8Array], { type: contentType });
}
clearButton.addEventListener("click", function (event) {
signaturePad.clear();
});
savePNGButton.addEventListener("click", function (event) {
var dataUrl = signaturePad.toDataURL();
//document.getElementById('imagen_firma').src = dataUrl;
var image = dataUrl.replace(/^data:image\/(png|jpg);base64,/, "");
$('input[name=signatureImage]').val(image);
//download(dataURL, "signature.png");
});
});
And html was loaded to a blade view like this:
<div class="sub-title">
<span>Signature</span>
</div>
<div class="data new" >
<div id="signature-pad" class="signature-pad">
<div class="signature-pad--body">
<canvas id="signature-canvas" style="width:650px;height:420px;max-width:100%;border:8px #CCC solid;background-color: white;"></canvas>
</div>
<div class="signature-pad--footer">
<div class="description">Sign above</div>
<div class="signature-pad--actions">
<div>
<i class="button clear icon-cancel" data-action="clear" style="font-size:2em;" title="Clear"></i>
<button type="button" class="button save" data-action="save-png" style="visibility:hidden">Save as PNG</button>
</div>
</div>
</div>
</div>
</div>
{{ Form::hidden('signatureImage', old('signatureImage')) }}
I can try anything...
Thank you a lot

Can't save an image inside <canvas>

I'm still new to this whole canvas things and there's something I have a problem with, namely, saving the content inside the canvas as image. Here's my fiddle
var img = new Image();
img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
img.onload = function() {
ctx.drawImage(img, 0, 0);
img.style.display = 'none';
};
var link = document.createElement('a');
link.innerHTML = 'Save';
link.href = document.getElementById('canvas').toDataURL();
link.addEventListener('click', function(e) {
link.download = "imagename.png";
}, false);
document.body.appendChild(link);
<canvas id="canvas" width="300" height="300"></canvas>
While the save dialog appears just fine, the saved image is empty, like it doesn't capture the content at all.
Any help is appreciated, moreso if it's accompanied by on how/why my code doesn't work and your code will. Thanks.
Edit: Forgot to link the fiddle I base my code from here The difference is that that fiddle saves the drawing in the canvas while what I wrote is merely saving a static image from another source.
You need to set image href inside of onload and use img.crossOrigin = "anonymous" just to avoid cross origin error.
var img = new Image();
img.crossOrigin = "anonymous";
img.src = 'http://farm5.static.flickr.com/4005/4706825697_c0367e6dee_b.jpg';
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
img.onload = function() {
ctx.drawImage(img, 0, 0, 300, 300);
link.href = document.getElementById('canvas').toDataURL();
};
var link = document.createElement('a');
link.innerHTML = 'Save';
//link.href = document.getElementById('canvas').toDataURL();
link.addEventListener('click', function(e) {
link.download = "imagename.png";
}, false);
document.body.appendChild(link);
<canvas id="canvas" width="300" height="300"></canvas>
There are two issues.
The first is the image's origin. On JSFiddle you'll get an Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
As mentioned in another answer, Base64 encoding the image then setting img.src = 'data:image/jpeg;base64,/...'; resolves this problem.
Another solution: run a web server locally, and source the image by its location on the server, e.g. img.src = './rhino.jpg';.
Even after that's handled, the downloaded image will be "empty," as before. This is because of the order of execution of your code. link.href = canvas.toDataURL(); executes before the image's 'load' event fires, so the canvas is empty at the point you're setting the data.
Placing that line inside the img.onload function ensures that the link's download data is set only after the image has loaded. This approach is convenient, because it allows for the <a> tag to behave with default behavior once the href attribute is set (e.g. pointer on hover, underlined text by default).
Placing that line, instead, inside the link's 'click' event handler incidentally works, but you lose the default link behavior mentioned above.
Here's an example of the working JS, assuming the image file is on the server:
var img = new Image();
img.src = './rhino.jpg';
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var link = document.createElement('a');
link.innerHTML = 'Save';
img.onload = function() {
ctx.drawImage(img, 0, 0);
img.style.display = 'none';
link.href = canvas.toDataURL();
};
link.addEventListener('click', function(e) {
link.download = "imagename.png";
}, false);
document.body.appendChild(link);
And a JSFiddle, using the Base-64 encoded image.

save and display image captured from input type=file

I have a webpage with capture image from the Available camera feature. For the web version it simply places the video capture onto a canvas. However for a phone, I am using <input class="btn btn-info" type="file" accept="image/*" id="cameraCapture" capture="camera"> to capture a picture. It asks the user to either capture the image using the phone's camera or upload from its filesystem/gallery etc. Once the image is clicked it simply places the image's name next to the button.
Is there a way to access this image and display it in the same page.
Thanks in advance
You can do that with JS using FileReader object.
Take a look at this answer: preview-an-image-before-it-is-uploaded
I hope it helps
var input = document.querySelector('input[type=file]');
input.onchange = function () {
var file = input.files[0];
drawOnCanvas(file);
};
function drawOnCanvas(file) {
var reader = new FileReader();
reader.onload = function (e) {
var dataURL = e.target.result,
c = document.querySelector('canvas'),
ctx = c.getContext('2d'),
img = new Image();
img.onload = function() {
c.width = img.width;
c.height = img.height;
ctx.drawImage(img, 0, 0);
};
img.src = dataURL;
};
reader.readAsDataURL(file);
}

jQuery, captured Image download

I'm using an ip camera.
For live stream:
<img id="ip-camera-frame" src="http://192.168.1.10/GetData.cgi?CH=1"></img>
I take a snapshot from camera with link "/GetImage.cgi?CH=0" and i can set "img" tag in modalbox.
This snapshot is OK, I want to download captured image but all download methots getting an new capture and download.
<div id="snapshot" class="modal-demo">
<div class="custom-modal-text">
<img id="snapshot-frame" width="100%"></img >
</div>
<div class="modal-footer">
<button type="button" id="save-snapshot">Download Snapshot</button>
</div>
You can try to copy image data from already loaded and displayed image.
as it describe here:
Get image data in JavaScript?
and download it like it described here:
Browser/HTML Force download of image from src="data:image/jpeg;base64..."
so you should have something like:
document.getElementById('save-snapshot').addEventListener("click", function(e) {
var img = new Image();
img.setAttribute('crossOrigin', 'anonymous');
img.onload = function() {
var canvas = document.createElement("canvas");
canvas.width = this.width;
canvas.height = this.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
// guess the original format, maybe "image/jpg"
var dataURL = canvas.toDataURL("image/png");
window.open(dataURL.replace(/^data:image\/(png|jpg);base64,/, ""));
};
img.src = document.getElementById("ip-camera-frame").src;
}, false);

Categories

Resources