I'm trying to load an image on to a canvas so I can write some text on it and maybe save it later on. I have two below functions:
openImage = (memeURL, index) => {
this.setState({currentMeme: index}, () => {
const base_image = new Image();
base_image.crossOrigin = "anonymous";
base_image.src = memeURL;
const base64 = this.getBase64Image(base_image);
this.setState({currentImagebase64: base64});
})
}
getBase64Image(img) {
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
var dataURL = canvas.toDataURL("image/png");
return dataURL;
}
The openImage function is bound to an onClick event so when I click an image it fires up the above operations so that my <img src=""> can feed from state and display the image.
The problem is that when i click the image it never shows up and my currentImagebase64 state value is always data; BUT if debug with web tools it appears fine because theres enough time for the image to load. Aparrently the solution is in the below answer:
canvas.toDataUrl() returns 'data:,'
However, if I write something like suggested the onload function never triggers. For example below code won't trigger the onload for some reason, it just stops executing when it reaches it:
openImage = (memeURL, index) => {
this.setState({currentMeme: index}, () => {
const base_image = new Image();
base_image.onload = function() {
this.crossOrigin = "anonymous";
}
//Set src AFTER the image has loaded
base_image.src = memeURL;
const base64 = this.getBase64Image(base_image);
this.setState({currentImagebase64: base64});
})
}
Can any subject experts lend a hand please?
const base64 = this.getBase64Image(base_image);
this.setState({currentImagebase64: base64});
needs to be executed once the image has loaded
and
base_image.crossOrigin = "anonymous";
needs to be done before setting the src
So, the code becomes
openImage = (memeURL, index) => {
this.setState({currentMeme: index}, () => {
const base_image = new Image();
base_image.crossOrigin = "anonymous";
base_image.onload = () => { // use arrow function so `this` will be what is needed
const base64 = this.getBase64Image(base_image);
this.setState({currentImagebase64: base64});
}
base_image.src = memeURL;
})
}
Your comment
//Set src AFTER the image has loaded
suggests you don't know how onload works ... you set src which starts loading the image, and then onload is triggered when image finishes loading
I'm not entirely sure how react handles the states as above but I've had a similar issue in vanilla JS in which the src wasn't loading until added to the DOM. Keeping it hidden was fine though:
const image = new Image();
image.onload = (e)=>{
// do something
}
image.src = YOUR_IMAGE_PATH;
image.hidden = true;
// add to body
document.body.appendChild(image); // at this point the src is loaded and onload handler is fired
Related
I have been working to change a github code to upload multiple images and get result.
https://github.com/giventofly/pixelit
Tried many ways. But not working.
document.addEventListener("DOMContentLoaded", function () {
//load image to canvas
document.getElementById("pixlInput").onchange = function (e) {
var img = new Image();
img.src = URL.createObjectURL(this.files[0]);
img.onload = () => {
//create element
//document.getElementById('teste').src = img.src;
px.setFromImgSource(img.src);
pixelit();
//.pixelate()
//.convertGrayscale()
//.convertPalette();
//.saveImage();
//console.log(px.getPalette());
};
};
This is the source code. Please help
I am trying to load an image with an html input type="file" and load it to an with javascript without success.
Here is my code so far:
HTML:
<canvas class="imported" id="imported"></canvas>
<button class="import_button" id="import_button">Import a picture</button>
<input type="file" id="imgLoader"/>
JAVASCRIPT:
document.getElementById('import_button').onclick = function() {
document.getElementById('imgLoader').click();
};
document.getElementById('imgLoader').addEventListener('change', importPicture, false);
function importPicture()
{
alert("HERE");
var canvas = document.querySelector('#imported');
var context = canvas.getContext("2d");
var fileinput = document.getElementById('imgLoader');
var img = new Image();
var file = document.getElementById('imgLoader').files[0];
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function(evt)
{
alert("THERE");
if( evt.target.readyState == FileReader.DONE)
{
alert("AGAIN");
img.src = evt.target.result;
context.drawImage(img, 200, 200);
}
}
}
The alerts are all fired up, no errors or message in the console..
How can I load it and display it? Thank you!
The logic (of your original code, not the edited version) is a bit baffling:
document.getElementById('imgLoader').addEventListener('change', importPicture, false);
adds a change event to the file input. That's fine. But then within the "importPicture" function, which runs when the file input changes, you add another change event listener (via fileinput.onchange) ...why are you doing that? I can't see how it makes sense. It means you have to change the file again before the code in there runs. And it also means that every time you change the file it adds more and more listeners, until you have lots of functions firing at once.
The other problem is that you're not waiting for the data to be loaded into the Image object before you try to draw the image on the canvas. You also need to set the dimensions of the canvas itself, and not be prescriptive about the dimensions of the image (because the user could upload anything, of any size).
Here's a working demo:
document.getElementById('import_button').onclick = function() {
document.getElementById('imgLoader').click();
};
var fileinput = document.getElementById('imgLoader').addEventListener('change', importPicture, false);
function importPicture() {
var canvas = document.querySelector('#imported');
var context = canvas.getContext("2d");
var img = new Image();
var file = this.files[0];
var reader = new FileReader();
reader.onload = function(evt) {
img.onload = function() {
canvas.width = img.width;
canvas.height = img.height;
context.drawImage(img, 0, 0);
}
img.src = evt.target.result;
}
reader.readAsDataURL(file);
}
<canvas class="imported" id="imported"></canvas>
<button class="import_button" id="import_button">Import a picture</button>
<input type="file" id="imgLoader" />
Credit to this answer for the final bits.
I tried to convert the image to base64 string using javascript/angularjs following the code showed on this stacko page, you can also check the code in detail here.
function toDataURL(src, callback, outputFormat) {
var img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = function() {
var canvas = document.createElement('CANVAS');
var ctx = canvas.getContext('2d');
var dataURL;
canvas.height = this.naturalHeight;
canvas.width = this.naturalWidth;
ctx.drawImage(this, 0, 0);
dataURL = canvas.toDataURL(outputFormat);
callback(dataURL);
};
img.src = src;
if (img.complete || img.complete === undefined) {
img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
img.src = src;
}
}
toDataURL(
'https://www.gravatar.com/avatar/d50c83cc0c6523b4d3f6085295c953e0',
function(dataUrl) {
console.log('RESULT:', dataUrl)
}
)
I call this function in the init inside the controller but when i load the page the image doesn't load the first time, but if i load the page again the image does load. I also made a button to call the function again, and as expected the image loads just fine after i load the page and press the button.
Debugging the code i found that the image only loads if it gets to the last if statement which, as by the detailed code, is flushing the cache. But since it's trying by the second time wouldn't this be the normal approach?
if (img.complete || img.complete === undefined) {
img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
img.src = src;
}
After getting here it goes on to img.onload and loads the image again, this time the image loads just fine.
What am i missing? Do i need to do something to wait the image to load? Can i do something to make it load later? Or is it something else?
Turns out i wasn't addressing the fact that ImgPreview from ui-cropper can be used, therefore there wasn't any need to convert the image. I only made a $scope in the view to get that ImgPreview and send that to the database. Sadly i can't provide any code.
Using JavaScript, I want to convert an img tag like this:
<img width="11" height="14" src="http://mysite/file.gif" alt="File Icon">
Into one with a dataurl like this:
<img width="11" height="14" src="data:image/gif;base64,R0lGODlhCwAOAMQfAP////7+/vj4+Hh4eHd3d/v7+/Dw8HV1dfLy8ubm5vX19e3t7fr6+nl5edra2nZ2dnx8fMHBwYODg/b29np6eujo6JGRkeHh4eTk5LCwsN3d3dfX13Jycp2dnevr6////yH5BAEAAB8ALAAAAAALAA4AAAVq4NFw1DNAX/o9imAsBtKpxKRd1+YEWUoIiUoiEWEAApIDMLGoRCyWiKThenkwDgeGMiggDLEXQkDoThCKNLpQDgjeAsY7MHgECgx8YR8oHwNHfwADBACGh4EDA4iGAYAEBAcQIg0Dk gcEIQA7" alt="File Icon">
Is this possible?
Here's how to get the data url of an image with fetch:
(async function() {
let blob = await fetch("https://example.com/image.png").then(r => r.blob());
let dataUrl = await new Promise(resolve => {
let reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.readAsDataURL(blob);
});
// now do something with `dataUrl`
})();
First, load the image into a canvas
var canvas = document.createElement("canvas");
context = canvas.getContext('2d');
make_base();
function make_base()
{
base_image = new Image();
base_image.src = 'img/base.png';
base_image.onload = function(){
context.drawImage(base_image, 100, 100);
}
}
Make sure to update the context.drawImage(base_image, 100, 100); to values appropriate for your application.
Source: https://stackoverflow.com/a/6011402/3969707
Then convert the canvas to data.
var jpegUrl = canvas.toDataURL("image/jpeg");
var pngUrl = canvas.toDataURL(); // PNG is the default
Source: https://stackoverflow.com/a/15685877/3969707
I'd solve this problem with a temporary canvas element with the same size of the image loaded:
function imageToUri(url, callback) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
var base_image = new Image();
base_image.src = url;
base_image.onload = function() {
canvas.width = base_image.width;
canvas.height = base_image.height;
ctx.drawImage(base_image, 0, 0);
callback(canvas.toDataURL('image/png'));
canvas.remove();
}
}
imageToUri('./assets/some_image.png', function(uri) {
console.log(uri);
});
This really isn't something you may want to do in JavaScript as it requires the image be parsed in JavaScript which is very slow. You would be loading the image and then putting the output of the function into the img tag, which doesn't save bandwidth, decrease complexity, or improve security.
Your best bet is to do this server-side. I've used this to great success in the past for generating pages which need to have absolutely no linked/referenced external resources. You can, for jsPDF, then use raw JavaScript or jQuery to get the data of an image to pass into the PDF creation process.
This will work everywhere and not rely on resorting to canvas which doesn't have full mobile browser support.
Is there any way I could load an image via javascript and then have a callback fire when it is finished?
Thanks for any ideas.
Have you tried this?
var img = new Image();
img.onload = function(){ alert('loaded'); };
img.src = '/some/image.jpg';
UPDATE
sure you can set the background-image of an element with this. Use the onload event to do whatever you like!
// change background to image - only after image completely loaded
function setBackroundImage(node, imageUrl) {
var img = new Image();
img.onload = function() {
node.style.backgroundImage = imageUrl;
}
img.src = imageUrl;
}
setBackroundImage(document.getElementById('foobar'), '/some/image.jpg');
Here is the sample code to handle image load:
var img = document.createElement('img')
img.src = 'https://www.google.com/intl/en_com/images/srpr/logo3w.png'
$(img).load(function(){ alert('Image loaded')})
$('#container').append(img)