This question already has answers here:
HTML5 Canvas toDataURL returns blank
(2 answers)
Closed 3 years ago.
Fetching a list of objects. I loop through the list to retrieve an image in each object and store it in the localStorage.
// storing images in localStorage
storeMovieImagesLocalStorage = (movieList) => {
movieList.map(movie => {
localStorage.setItem(movie.id, this.getBase64Image(movie.images[0].url))
})
};
// converting url to base64
getBase64Image = (img) => {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
// create new Image to assign image url
const image = new Image();
image.src = img;
image.onload = function() {
const canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
ctx.drawImage(image, 0, 0);
};
const dataURL = canvas.toDataURL("image/png");
return dataURL;
};
Then I apply the base64 code to my image.
this.setState({
movieUrl: localStorage.getItem(movie.id)
})
<MovieImg src={this.state.movieUrl} className="cursor-pointer" onClick={this.handleOpenVideo} />
My localStorage is storing the right information properly:
{ 2-guns: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAACWCAYAAABkW7XSAAAEYklEQVR4Xu3UAQkAAAwCwdm/9HI83BLIOdw5AgQIRAQWySkmAQIEzmB5AgIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlACBB1YxAJfjJb2jAAAAAElFTkSuQmCC" }
Here what I find the devTools/Elements:
<img class="Img-sc-10y4zbe-0 cursor-pointer sc-ifAKCX cmjWax" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAACWCAYAAABkW7XSAAAEYklEQVR4Xu3UAQkAAAwCwdm/9HI83BLIOdw5AgQIRAQWySkmAQIEzmB5AgIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlAABg+UHCBDICBisTFWCEiBgsPwAAQIZAYOVqUpQAgQMlh8gQCAjYLAyVQlKgIDB8gMECGQEDFamKkEJEDBYfoAAgYyAwcpUJSgBAgbLDxAgkBEwWJmqBCVAwGD5AQIEMgIGK1OVoAQIGCw/QIBARsBgZaoSlACBB1YxAJfjJb2jAAAAAElFTkSuQmCC">
All seems fine to me and I do not have any error in my console. However, my image is not displayed. and when I hover above the img[src], it shows me an invisible image, or and image that does not have content.
What have I done wrong?
i attempted to convert your base64 string back to an image again, the part between "iVBOR" and "SuQmCC". but that doesnt appear to be a valid image returned from that.
i tried with another base64 string representing an image using your exact html tag with attributes and that works just fine:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA
AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot" class="Img-sc-10y4zbe-0 cursor-pointer sc-ifAKCX cmjWax">
it seems the problem is that you have an incorrect base64 string of the image which is why nothing shows up. worth noting is that i have no idea what your specific classes do so i cant speak for their behavior.
Related
I have a canvas on which I draw pretty images!
Using .toDataURL('image/gif'), I save those images as image files. So far so good.
Thing is that I want to save a number of those images (I change parameters for each image to be saved.)
I would like to do it "silently", that is without having to click on "Save" on the modal window that pops up every time.
Is there a way to do that?
Thanks.
Using the download attribute of an <a> element, you can silently download the image data without needing to deal with any dialog windows. I should warn that this could be potentially dangerous as it is literally downloading a file to your computer without any direct confirmation.
Once you have your data URL from your canvas, the rest is pretty easy. You can create a new <a> element, set the href to your data URL, set the download attribute to the filename you wish to use, and then execute the click() event on this newly created element.
let dataURL
const _Base64Image = url => {
const img = new Image()
img.setAttribute('crossOrigin', 'anonymous')
img.onload = () => {
const canvas = document.createElement("canvas")
canvas.width = img.width
canvas.height = img.height
const ctx = canvas.getContext("2d")
ctx.drawImage(img, 0, 0)
dataURL = canvas.toDataURL("image/png")
_SetBG(document.querySelector("#imgTest"), dataURL, img.width, img.height)
}
img.src = url
}
const _SetBG = (el, data, w, h) => {
el.style.width = `${w}px`
el.style.height = `${h}px`
el.style.backgroundImage = `url("${data}")`
}
const _SaveImage = (data, filename) => {
const a = document.createElement("a")
a.href = data
a.download = filename
a.click()
}
_Base64Image('https://upload.wikimedia.org/wikipedia/commons/thumb/9/99/Unofficial_JavaScript_logo_2.svg/2048px-Unofficial_JavaScript_logo_2.svg.png')
document.querySelector("input[type='button']").addEventListener("click", e => {
_SaveImage(dataURL, "test_image.png")
})
.random-background {
max-height: 100px;
max-width: 100px;
background-size: contain;
}
<div id="imgTest" class="random-background"></div>
<br>
<br>
<input type="button" value="Save Image">
NOTE
This snippet will not work on StackOverflow as part of their security settings. However I also uploaded this to CodePen so you can see a working version.
For the sake of not forcing downloads on anyone I included a button that must be clicked to save the image. However this is not required for the code to work. Simply calling the _SaveImage() function (and passing in the data URL and filename) will work. But having the snippet do this automatically is somewhat problematic as you can get hit with multiple downloads for the same file just by going to the page.
I use react and html-to-image to export HTML to images. Because Safari not working properly with the jpg/png export, I need to export HTML node to SVG (data url is generated like this : data:image/svg...).
With this string, I am creating a new Image inside a Canvas then saving canvas to .Png with method canvas.toDataURL("image/png").
Everything is working on Firefox/Chrome, but on Safari, it's not working the first time.
First Click - Just avec HTML node (no text)
Second Click - Some Images + Previous HTML Node
Third Click - Everything is working
Here is part of my function :
var canvas = document.createElement("canvas")
var ctx = canvas.getContext('2d')
var img = new Image;
setTimeout(()=>{
htmlToImage.toSvg(document.querySelector('.Banner'), {pixelRatio: RatioVal}).then((dataUrl) => {
canvas.width = 1300*RatioVal;
canvas.height = 690*RatioVal;
img.src = dataUrl;
img.onload = () => {
ctx.drawImage(img,0,0,canvas.width, canvas.height)
var Export = canvas.toDataURL("image/png");
document.body.append(Export)
var a = document.createElement('a');
a.href = Export;
a.download = window.Chara.Nom+".png";
a.click();
};
})
},600)
Do you know why I need to click on Export 3 times to have a full image ?
Is this the best way to convert SVG dataUrl to PNG Image ?
I tried many things (Blob to Png etc..) but the problem is the same on Safari.
The question on a single line:
Is there a toDataURL method working on a <IMG> element?
Most of the people seem to be interested in how to get an IMG from a CANVAS, but I need the opposite.
Why? I need to use the toDataURL() method on the IMG.
So, this is the pseudo code that I wish existed in reality:
var img = document.getElementById('myImage');
var canvas = img.getCanvasFromImage();
var dataURL = canvas.toDataURL();
Is there already a method, or a workaround (e.g. creating an empty canvas, copying the IMG on top, etc.) to do the getCanvasFromImage? I couldn't find one.
Some more details WHY, but there is no need to read further. I am using the VIDEO tag to get the camera stream, and when the user clicks a button, I copy the CANVAS to the IMG.
But since I do not want to show the whole picture while taking a photo (I want it to be consistent over different devices, regardless of the camera resolution, keeping a 16:9 aspect ratio), I only show a portion of the image using object-fit: cover; .
So, now I have a "partial" image, but if I do a toDataURL on the canvas I have, it gives me the WHOLE picture, regardless of the "object-fit" value.
If this is not clear, no problem :) I only need a "toDataURL" method working on a <IMG> element :)
HTMLImageElement.prototype.getCanvasFromImage = function(){
const canvas = document.createElement('canvas');
canvas.width = this.width;
canvas.height = this.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(this, 0, 0);
return canvas;
};
const img = document.getElementById('myImage');
img.onload = () => {
const canvas = img.getCanvasFromImage();
const dataURL = canvas.toDataURL();
console.log(dataURL);
}
<img id="myImage" crossorigin="anonymous" src="https://dl.dropbox.com/s/zpoxft30lzrr5mg/20201012_102150.jpg" />
Its work, but please READ THIS. Better way is create pure function and pass image as argument:
function getCanvasFromImage(image) {
const canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(image, 0, 0);
return canvas;
}
i'm using this function to convert an svg to a jpeg (it includes canvg):
svgToDataUrl(svg, format = 'jpeg') {
var id = new Date();
var canvasElement = $(`<canvas id="${id}" width="1198px"
height="1694px"></canvas>`).appendTo('#resultsInterface');
let canvas = canvasElement[0];
window.canvg(canvas, svg);
var imgData = canvas.toDataURL(`image/${format}`, 0.98);
canvasElement.remove();
return imgData;
}
The SVG variable in a SVG image previously generated.
Now, it works properly but, if the SVG contains a tag with an href in base64 format:
<image xlink:href="data:image/png;base64,iVBORblablabla..."></image>
The result is blank. I've tried to check the canvas generated (before it is removed) and is just fine but for some reason canvas.toDataURL seems not working in this case.
Any clue?
Thanks
Daniele
I'm converting images to base64 using canvas. What i need to do is convert those images and then show the result to the user (original image and base64 version). Everything works as expected with small images, but when i try to convert large images (>3MB) and the conversion time increases, the base64 version is empty.
This might be is caused because the result is shown before the toDataURL() function is completed.
I need to show the result after all the needed processing has ended, for testing purposes.
Here's my code:
var convertToBase64 = function(url, callback)
{
var image = new Image();
image.onload = function ()
{
//create canvas and draw image...
var imageData = canvas.toDataURL('image/png');
callback(imageData);
};
image.src = url;
};
convertToBase64('img/circle.png', function(imageData)
{
window.open(imageData);
});
Even though i'm using image.onload() with a callback, i'm unable to show the result after the toDataURL() has been processed.
What am i doing wrong?
UPDATE: I tried both the solutions below and they didn't work. I'm using AngularJS and Electron in this project. Any way i can force the code to be synchronous? Or maybe some solution using Promises?
UPDATE #2: #Kaiido pointed out that toDataURL() is in fact synchronous and this issue is more likely due to maximum URI length. Since i'm using Electron and the image preview was for testing purposes only, i'm going to save the file in a folder and analise it from there.
Your code seems absolutely fine. Not sure why isn't working you. Maybe, there are some issues with your browser. Perhaps try using a different one. Also you could use a custom event, which gets triggered when the image conversion is competed.
// using jQuery for custom event
function convertToBase64(url) {
var image = new Image();
image.src = url;
image.onload = function() {
var canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
var ctx = canvas.getContext('2d');
ctx.drawImage(image, 0, 0);
var imageData = canvas.toDataURL();
$(document).trigger('conversionCompleted', imageData);
};
};
convertToBase64('4mb.jpg');
$(document).on('conversionCompleted', function(e, d) {
window.open(d);
});
This approach might work for you. It shows the image onscreen using the native html element, then draws it to a canvas, then converts the canvas to Base64, then clears the canvas and draws the converted image onto the canvas. You can then scroll between the top image (original) and the bottom image (converted). I tried it on large images and it takes a second or two for the second image to draw but it seems to work...
Html is here:
<img id="imageID">
<canvas id="myCanvas" style="width:400;height:400;">
</canvas>
Script is here:
var ctx;
function convertToBase64(url, callback)
{
var image = document.getElementById("imageID");
image.onload = function() {
var canvas = document.getElementById("myCanvas");
canvas.width = image.naturalWidth;
canvas.height = image.naturalHeight;
ctx = canvas.getContext("2d");
ctx.drawImage(image,0,0);
var imageData = canvas.toDataURL('image/png');
ctx.fillStyle ="#FFFFFF";
ctx.fillRect(0,0,canvas.width,canvas.height);
callback(imageData);
};
image.src = url;
};
var imagename = 'images/bigfiletest.jpg';
window.onload = function () {
convertToBase64(imagename, function(imageData) {
var myImage = new Image();
myImage.src = imageData;
ctx.drawImage(myImage,0,0);
});
}
Note that I also tried it without the callback and it worked fine as well...