image undefined onload function, need to get height and width [duplicate] - javascript

This question already has answers here:
Arrow Functions and This [duplicate]
(5 answers)
Closed 3 years ago.
I got this code:
_getWidthAndHeight = (ImageURL) => {
var img = new Image();
img.onload = () => {
alert(JSON.stringify(img));
alert(this.height);
alert(this.width);
};
img.src = ImageURL;
}
It is supposed to load the image in google chrome, and get image height and width. Why the object returns empty?

this is not pointing at what you need in arrow functions
_getWidthAndHeight = (ImageURL) => {
var img = new Image();
img.onload = function() { // now "this" will be what you think it is
console.log(this.height,this.width);
};
img.src = ImageURL;
}
_getWidthAndHeight("https://via.placeholder.com/500x400?text=500x400")
With arrow:
_getWidthAndHeight = (ImageURL) => {
var img = new Image();
img.onload = (e) => { // now you can use e.target
console.log(e.target.height,e.target.width);
};
img.src = ImageURL;
}
_getWidthAndHeight("https://via.placeholder.com/500x400?text=500x400")

The problem is that you're using this inside an ES6 arrow function. It has a different context from classic JS functions. You'll have to use this code for it to work:
_getWidthAndHeight = (ImageURL) => {
var img = new Image();
img.onload = function () {
alert(JSON.stringify(img));
alert(this.height);
alert(this.width);
};
img.src = ImageURL;
}

Related

How to call a function that gives a url, which is then used to store and display an image using FileReader

I am new to coding in javascript, I have been tasked as an excersise using some pre-existing functions to create an image item using a given url. I need to read the image, store it in local storage and then display it on the screen. The only functionI need to add too is process file. I am stuck and cannot get it to display the image. I get an error saying that the path does not exist. Below is my code, any guidance to what I am doing wrong? I feel like I am very close but doing something funamendatly wrong.
function addImageEntry(key, url) {
var imgElement = new Image();
imgElement.alt = "Photo entry";
imgElement.src = url;
addSection(key, imgElement);
}
function makeItem(type, data) {
var itemObject = { type: type, data: data };
return JSON.stringify(itemObject);
}
function processFile(event) {
function addImage(url) {
var key = "diary" + Date.now();
addImageEntry(key, url);
var imgElement = new Image();
imgElement.src = url;
var item = makeItem("image", imgElement.src);
localStorage.setItem(key, item);
}
var inputElement = event.target;
var fileObject = inputElement.files[0];
var reader = new FileReader();
reader.addEventListener("load",addImage);
url = reader.readAsDataURL(fileObject);
event.target.value = "";
}
The url = reader.readAsDataURL(fileObject) won't store the image data.
It stores in reader.result.
Use imgElement.src = reader.result.
document.querySelector('input[type="file"]').addEventListener('change', processFile)
function processFile(event) {
var fileObject = event.target.files[0]
var reader = new FileReader()
reader.addEventListener('load', addImage)
reader.readAsDataURL(fileObject)
function addImage() {
var imgElement = new Image()
imgElement.src = reader.result
document.body.append(imgElement)
}
}
Amend:
function addImage(event) {
// use reader.result is ok too
localStorage.setItem('myimage', event.target.result)
}
function addImageEntry() {
var imgElement = new Image()
imgElement.src = localStorage.getItem('myimage')
imgElement.style.display = 'block'
document.body.append(imgElement)
}

Unable to return value from img.onload [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
trying to get dimenstions (e.g. 600x300) from an image using javascript. I am not sure how to return the data because it's not working. Do I need a callback, and how ?
<script>
function getMeta(url){
var img = new Image();
var res = img.onload = function(){
var ret = this.width+'x'+ this.height;
alert(ret);
return ret;
};
img.src = url;
return res;
}
var meta = getMeta('https://upload.wikimedia.org/wikipedia/en/a/a9/Example.jpg');
alert(meta);
</script>
getMeta is finished before onload function. You need to use a Promise or a callback. Example with callback below:
function getMeta(url, cb){
var img = new Image();
img.onload = function(){
var ret = this.width+'x'+ this.height;
console.log(ret);
cb(ret);
};
img.src = url;
}
getMeta('https://upload.wikimedia.org/wikipedia/en/a/a9/Example.jpg', function(meta){
console.log('got meta', meta);
});

Get Image Data URLs on the fly while iterating

Let's say I have an array that contains several image URLs
const imgs = [
'https://placehold.it/120x120&text=image1',
'https://placehold.it/120x120&text=image2',
'https://placehold.it/120x120&text=image3'
]
And I want to get those images as base 64 strings on the fly in preparation for a network request. What would I have to do to accomplish this using javascript?
I've currently tried:
const getDataUrl = (url) => {
return new Promise((resolve, reject) => {
let img = new Image()
let canvas = document.createElement('canvas')
img.setAttribute('crossOrigin', 'anonymous')
img.onload = function(){
canvas.height = img.height
canvas.width = img.width
canvas.getContext('2d').drawImage(img, 0, 0)
resolve(canvas.toDataUrl('png'))
}
img.src = url
})
}
let dataUrls = []
for(let img of imgs){
getDataUrl(img).then(res => {
dataUrls.push(res)
})
console.log(dataUrls)
}
But the promise does not wait for the image to load and resolve and I get an empty array
So I then tried a recursive solution:
let dataUrl = ''
const getDataUrl = (url) => {
let img = new Image()
let canvas = document.createElement('canvas')
img.setAttribute('crossOrigin', 'anonymous')
img.onload = function(){
canvas.height = img.height
canvas.width = img.width
canvas.getContext('2d').drawImage(img, 0, 0)
dataUrl = canvas.toDataUrl('png')
}
img.src = url
if(checkIntegrity()) return dataUrl
}
const checkIntegrity = () => {
if(dataUrl.length > 0){
return true
}else{
return checkIntegrity()
}
}
which is unsavory because I had to rely on dataUrl being in the global scope and didn't work anyway because I get a too much recursion error when I run this.
Finally, I thought I could try predefining the onLoad function and passing the resolve function as an argument to that:
const onLoad = (img, resolve) => {
let canvas = document.createElement('canvas')
canvas.height = img.height
canvas.width = img.width
canvas.getContext('2d').drawImage(img, 0, 0)
resolve(canvas.toDataURL('png'))
}
const getDataUrl = (url) => {
return new Promise((resolve, reject) => {
let img = new Image()
img.setAttribute('crossOrigin', 'anonymous')
img.onload = onLoad(img, resolve)
img.src = url
})
}
for(let img of imgs){
getDataUrl(img).then(res => {
console.log(res)
dataUrls.push(res)
})
}
console.log(dataUrls)
which was my most successfull attempt, but it ends up returning data:, from every call so it isn't working either. Here is a fiddle with that code: https://jsfiddle.net/5o4Lq3bh/34/
Barring this, I'm at my wit's end. I also tried manipulating dom mounted images instead of javascript image objects and using a counter with a loaded check and a different recursive function but I get the same error, too much recursion.
My main issue seems to be the iteration. I am pretty sure for / of is synchronous, so I'm guessing the issue is that I can't pass around resolve willy nilly to other functions and expect to get valid results.
This would be easy to do on load but it has to happen on the fly, any help is appreciated.
The first snippet and the third snippet you shared has some issues.
First snippet, your console.log will always print an empty array because it's outside the then statement.
for(let img of imgs){
getDataUrl(img).then(res => {
dataUrls.push(res)
})
console.log(dataUrls) // will always print [] because this statement should be within then function
}
Third snippet, you are calling onLoad function, instead of passing it as a event handler
img.onload = onLoad(img, resolve) // this will call onLoad, this is not an event handler
The below code works, but this doesn't utilize the full feature of promises
const getDataUrl = (url) => {
return new Promise((resolve, reject) => {
let img = new Image()
img.setAttribute('crossOrigin', 'anonymous')
img.onload = function(){
let canvas = document.createElement('canvas')
canvas.height = img.height
canvas.width = img.width
canvas.getContext('2d').drawImage(img, 0, 0)
let b64String = canvas.toDataURL('png');
resolve(b64String)
}
img.src = url
})
}
for(let img of imgs){
getDataUrl(img).then(res => {
dataUrls.push(res)
console.log(dataUrls.length)
})
}
If you want a much clear approach then use the below
const imgs = [
'https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/pie.png',
'https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/pie.png',
'https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/pie.png'
]
let dataUrls = []
let images = [];
for(let imgUrl of imgs){
images.push(new Promise((resolve, reject) => {
let img = new Image();
img.setAttribute('crossOrigin', 'anonymous')
img.onload = function(){
let canvas = document.createElement('canvas')
canvas.height = img.height
canvas.width = img.width
canvas.getContext('2d').drawImage(img, 0, 0)
let b64String = canvas.toDataURL('png');
dataUrls.push(b64String);
resolve(b64String)
}
img.src = imgUrl
}));
}
Promise.all(images).then(function(){
console.log(dataUrls)
})
https://jsfiddle.net/karthick6891/5o4Lq3bh/52/
Note: FYI, your fiddle didn;t work for me too, I had the same cross origin issue like everyone has posted.

how get value function in variable

Hello me need get variable from function
me return in answer undefined
function etr() {
var img = new Image();
img.onload = paramsImg;
img.src = picFile.result;
function paramsImg() {
return img.height;
};
};
var vvvr = etr();
alert(vvvr);
function etr() {
var img = new Image();
img.onload = paramsImg;
img.src = picFile.result;
function paramsImg() {
return img.height;
};
};
In your function, you mentioned paramsImg before its even loaded, so its not visible to img.onload.
paramsImg is declared simply as function, its not have scope outside the object. You need to use this keyword or mention fn with prototype.
function etr(picFile){
this.paramsImg = function(){
return img.height;
};
var img = new Image();
img.onload = this.paramsImg;
img.src = picFile.result;
}
picfile = {
result: 10
}
var vvvr = new etr(picfile);
alert(vvvr.paramsImg());
Your function etr doesn't return anything. I see that you are trying to return from an event handler for onload, but that only returns from the paramsImg function and not from etr (which has already returned before the image loads). You should wither make etr accept a callback function or return a Promise so that you can alert the images height after the image has loaded. Here is an example with a Promise:
function etr() {
return new Promise( ( resolve, reject ) => {
var img = new Image();
img.onload = _ => resolve(img.height);
img.onerror = reject;
img.src = picFile.result;
} );
};
var picFile = { result: 'https://dummyimage.com/600x1234/000/fff' };
(async function ( ) {
var vvvr = await etr();
alert(vvvr);
})( );

Trying to access variables outside the function in Javascript

I am using the following snip of Javascript from another SO answer:
var _URL = window.URL || window.webkitURL;
$("#file").change(function (e) {
var file, img;
if ((file = this.files[0])) {
img = new Image();
img.onload = function () {
alert(this.width + " " + this.height);
};
img.src = _URL.createObjectURL(file);
}
});
I cannot figure out how to get access to those this.width and this.height variables outside of the function. I have set them equal to existing variables and the variables are always 0 or null.
Its not really useful to just make them available outside a function since you will never really know the onload happened. You want a callback that will use those values at the appropriate time.
var _URL = window.URL || window.webkitURL;
$("#file").change(function (e) {
var file, img;
if ((file = this.files[0])) {
img = new Image();
img.onload = function () {
someCallback(this.width, this.height);
};
img.src = _URL.createObjectURL(file);
}
});
function someCallback (width, height) {
// use those values
}
Yes you can use a global variable but again I point out you won't know when those values have been populated and could end up with problems in your code.
You can also do something like this
var _URL = window.URL || window.webkitURL;
var width="";
var height="";
$("#file").change(function (e) {
var file, img;
if ((file = this.files[0])) {
img = new Image();
img.onload = function () {
width=this.width;
height=this.height;
};
img.src = _URL.createObjectURL(file);
}
});
Now you can use height and width variable out side of your change event. now this both variables are global variable

Categories

Resources