Ask constraint questions when creating image objects in Chrome Browser - javascript

I tried to create an image object by uploading an image file of 170MB Chrome Browser.
However, the error as below is occurring.
enter image description here
What's the cause?
Is there a size constraint on creating an image object?
const loadFromFile = (file: File) => {
return new Promise((resolve, reject) => {
const reader = new CustomFileReader()
reader.onload = () => resolve(reader.result)
reader.onerror = (e) => reject(e)
reader.readAsDataURL(file)
})
}
const createImage = (dataUrl) => {
return new Promise((resolve, reject) => {
const img = new Image()
img.onload = () => resolve(img)
img.onerror = (error) => { // generate Error Event
console.log('image load error', e)
reject(e)
}
img.src = dataUrl
})
}
const load = async (file: File) => {
const dataUrl = await loadFromFile(file) // successful
const image = await createImage(dataUrl) // error
}
This is the image used for the test: https://upload.wikimedia.org/wikipedia/commons/thumb/6/68/La_crucifixi%C3%B3n%2C_by_Juan_de_Flandes%2C_from_Prado_in_Google_Earth.jpg/2560px-La_crucifixi%C3%B3n%2C_by_Juan_de_Flandes%2C_from_Prado_in_Google_Earth.jpg

Related

How to get image dimensions on Cloudflare Workers?

I'm trying to create a Cloudflare Worker that receives an image URL and return width and height. But I receive the message ReferenceError: Image is not defined for new Image(). Is there a workaround to make the code below work?
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
let imageUrl = new URL(request.url).searchParams.get('imageUrl')
let response = await fetch(imageUrl)
let blob = await response.blob()
let image = new Image() // <------ ReferenceError: Image is not defined
return new Promise((resolve, reject) => {
image.onload = function() {
resolve(new Response(JSON.stringify({
width: image.width,
height: image.height
}), {
headers: {
'content-type': 'application/json'
}
}))
}
image.onerror = reject
image.src = URL.createObjectURL(blob)
})
}
It seems other functions for images have a similar problem. Example: ReferenceError: createImageBitmap is not defined. So any possible solution would be great.
Image are only available in the browse.
If you want to get the width and height of an image in node.js try this
const http = require('http');
const fs = require('fs');
const gm = require('gm');
async function handleRequest() {
const filename = "image.png"
const fileURL = "https://any-page.dom/"+filename
const file = fs.createWriteStream(filename);
return new Promise((resolve, reject) => {
const request = http.get(fileURL, function(response) {
response.pipe(file);
// after download completed close filestream
file.on("finish", () => {
console.log("Download Completed");
file.close();
gm(filename)
.size(function (err, size) {
if (!err) {
console.log('width = ' + size.width);
console.log('height = ' + size.height);
resolve(new Response(JSON.stringify({
width: size.width,
height: size.height
}), {
headers: {
'content-type': 'application/json'
}
}))
} else {
reject(err)
}
});
});
});
})
}

Having trouble getting a Base64 string from FileReader

I'm attempting to pass a file from an file input field's file list through FileReader and get the Base64 string to pass to the server via axios. The FileReader's onload function seems to get the string, but it evidently loses the string before it is returned. So, the value is undefined when I try to append it to the form data.
I'm told this is an asynchronous function, but I'm not sure where to await the promise. Can someone tell me what I'm doing wrong here?
const handleSubmit = async (e) => {
e.preventDefault()
const formData = new FormData()
// FILE READER -- DOES NOT WORK
const getImageFile = () => {
return new Promise(resolve => {
const reader = new FileReader()
reader.onload = function () {
const imageFile = reader.result
// console.log(`IMAGE FILE:\n ${imageFile}`) // imageFile IS NOT UNDEFINED HERE, BASE64 STRING
}
reader.readAsDataURL(document.getElementById("image").files[0])
})
}
////////////////////////////////
const imageFile = await getImageFile()
Array.from(document.getElementById("form").elements).forEach(element => {
switch (element.name){
case "image":
formData.append(`${element.name}`, imageFile) // UNDEFINED. WHY?
break
case "submit":
break
default:
formData.append(`${element.name}`, element.value)
}
})
console.log([...formData])
try {
const response = axios.post('http://localhost:4000/uploadShow', formData)
console.log(response)
} catch (e) {
console.log(e)
}
}
You have to create the promise yourself
const getImageFile = () => {
return new Promise(resolve => {
const reader = new FileReader()
reader.onload = function () {
resolve(reader.result)
}
reader.readAsDataURL(document.getElementById("image").files[0])
})
}
const handleSubmit = async (e) => {
// ...
const imageFile = await getImageFile()
// ...

ReactJS upload multiple image in base64 into an array

I want to create an image uplaoder based on base64 and I want to get results as an array but I got empty! array, I know maybe it's a asynchronous issue, but I don't know how to use async, await in map any idea?
const [array, setArray] = useState([]);
const fileBase64 = (img) => {
let result = [...img];
setUrlImage(img);
result && result.map(function (img){
let fileReader = new FileReader();
fileReader.readAsDataURL(img);
fileReader.onloadend = async () => {
let res = await fileReader.result;
setArray([...array, res])
};
})
console.log(array)
}
const handleImage = (e) => {
let image = [...e.target.files];
fileBase64(image);
}
<input type="file" multiple={true} onChange={handleImage}/>
Due to this asynchronous nature, state is being set i.e. push before data urls are set in array.
And that's the reason your your array return empty.
To fix it, you can use create Promise which gets resolved after load event of each file. And use Promise.all which would be resolved after each Promise has resolved and then use setArray:
fileBase64 = (img) => {
return new Promise((resolve, reject) => {
let fileReader = new FileReader();
fileReader.onerror = reject
fileReader.onload = function () {
resolve(fileReader.result)
}
fileReader.readAsDataURL(img)
})
}
handleImage = (e) => {
let image = e.target.files;
Promise.all(Array.from(image).map(this.readAsDataURL))
.then((urls) => {
setArray(urls)
})
.catch((error) => {
console.error(error)
})
}

Limit for strings in node.js/express

I am sending a base64-encoded image as a string to my backend using node.js/express. I would like to store it in my Postgres database, but I can not fetch the string. Is there any limit to this?
Before reaching my AJAX call in frontend I fill the data with:
var data = {picture: ""};
const reader = new FileReader();
const get_picture = new Promise((resolve, reject) => {
//event handler
reader.onload = resolve;
reader.onerror = reject;
//read image
reader.readAsDataURL(file);
})
.then(() => {
data.picture = reader.result;
})
.catch(() => {
show_modal(modal.title.error_custom, modal.body.error_image);
});
console.log(target_data);
$.ajax({ [...]
And my console show as expected:
Object { picture: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFIA…"}
This is by express route:
router.post("/upload_image", (req, res, next) => {
const picture = req.body.picture;
console.log("test");
console.log(picture);
}
This shows an empty line in my backend console. Are there any limits to the size of the parameter? Or what am I doing wrong? Thanks
EDIT: this works with async/wait
$("#form").submit(async function (event) {
[...]
var data = {picture: ""};
const get_picture = await new Promise((resolve, reject) => {
//event handler
reader.onload = resolve;
reader.onerror = reject;
//read image
reader.readAsDataURL(file);
})
.then(() => {
data.picture = reader.result;
})
.catch(() => {
show_modal(modal.title.error_custom, modal.body.error_image);
});
$.ajax({ [...]
Your ajax call doesn't wait for the reading process of your file, and send the top initialized object (var data = {picture: ""}).
You should call your ajax request in the .then()
var data = {picture: ""};
const reader = new FileReader();
const get_picture = new Promise((resolve, reject) => {
//event handler
reader.onload = resolve;
reader.onerror = reject;
//read image
reader.readAsDataURL(file);
})
.then(() => {
data.picture = reader.result;
$.ajax({[...]});
})
.catch(() => {
show_modal(modal.title.error_custom, modal.body.error_image);
});

Why doesn't my promise resolves?

I have the following function which resizes images.
The promise should resolve in onload part of my code, however it doesn't for some reason...
import Pica from 'pica';
const pica = new Pica();
export default ({ src, size }) =>
new Promise((resolve, reject) => {
const [width, height] = size.split('x');
const from = new Image();
const to = document.createElement('canvas');
const options = {
width,
height,
};
from.onload = async () => {
try {
const canvas = await pica.resize(from, to, options);
resolve(canvas);
} catch (e) {
reject(e);
}
};
from.src = src;
});
I use this function with to get an array of different-sized versions of one image. I'm using Promise.all() to achieve this.
Here's my code where I'm calling this function:
...
const img = ...
sizes.map(size => {
promisesArray.push(resizeImage({ img, size }));
});
Promise.all(promisesArray).then(data => console.log(data))
I've tried to console.log(resizeImage({ img, size })), and got promise with a pending status which does not resolve.
I've also had an assumption that it was due to Pica. So I tried to simplify the function, but it didn't work either:
// no extra code
export default ({ src, size }) =>
new Promise((resolve, reject) => {
const from = new Image();
from.onload = () => {
// what's wrong here?
resolve('hello');
};
from.src = src;
});
In addition to listing for onload you should always add a listener for onerror since it's possible that the Image will fail to load.
If you add a console.log into the onerror callback I suspect you will see that you've passed in an invalid src to one or more of your calls and the image is simply failing to load.
As an example demonstrating how to wire up the onerror callback (ignoring your resizing code which appears unrelated to your issues):
const loadImg = (src) => new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = (err) => reject(err);
img.src = src;
});
// This should succeed
loadImg('data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7').then(
() => console.log('Image loaded!'),
() => console.log('Image failed!'),
);
// This will fail
loadImg('invalid-url').then(
() => console.log("How did that load?"),
() => console.log("That wasn't an image!"),
);

Categories

Resources