Async await now working in Nuxt component - javascript

I have two functions,
One function converts images from whatever format to canvas, then to WEBP image format.
The other function receives the image and console.log the image.
The problem is that when I log the result of the image in the saveToBackend function, I get a result of undefined, but when I console.log the converted image in the convertImage function, I get the image. Please how can i solve the issue?
Below are the functions in my NUXT app
convertImage(file) {
// convert image
let src = URL.createObjectURL(file)
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d')
let userImage = new Image();
userImage.src = src
userImage.onload = function() {
canvas.width = userImage.width;
canvas.height = userImage.height;
ctx.drawImage(userImage, 0, 0);
let webpImage = canvas.toDataURL("image/webp");
console.log(webpImage); // with this i get the image in the console
return webpImage
}
},
async saveToBackend(file, result) {
// convert images to webp
let webpFile = await this.convertImage(file)
console.log(webpFile); // with this i get undefined in the console
}

You can't return webpImage from inside the onload callback. It simply will not wait for onload to execute. You can instead create a Promise that resolves the value of webpImage when onload completes:
convertImage(file) {
return new Promise((resolve) => {
// convert image
let src = URL.createObjectURL(file);
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
let userImage = new Image();
userImage.src = src;
userImage.onload = function() {
canvas.width = userImage.width;
canvas.height = userImage.height;
ctx.drawImage(userImage, 0, 0);
let webpImage = canvas.toDataURL("image/webp");
console.log(webpImage); // with this i get the image in the console
// resolve promise so that saveToBackend can await it
return resolve(webpImage);
};
});
}
Hopefully that helps!

Related

Blob images does not show up at UI, although I can see them on console

I am trying to create multiple blob images, and show them for a video timeline UI. To create the images, I take screenshots of the video for some certain time frames, and create img elements, then add img.src as blob images' url. The problem is blob images does not show up at UI, although I can see them on console. Any ideas?
Code snippet from creation of blob images:
// draw the video frame to canvas
const ctx = canvas.getContext("2d");
ctx.drawImage(videoPlayer, 0, 0, canvas.width, canvas.height);
ctx.canvas.toBlob(
blob => {
resolve(blob);
},
"image/jpeg",
0.75 /* quality */
);
Code Snippet from creation of images:
let img = '';
for (let i = 0; i < count / 3; i++) {
const cover = await GetVideoCover(item.video_url, i);
var url = URL.createObjectURL(cover);
var image = new Image();
image.src = url;
img += "<img src='"+image.src+"'>";
console.log(img)
}
return img;
The console log from console.log(img)line:
actual html img elements:
When I manually update the source as below, it works, but I did not understand why it does not get the source by itself. Any idea would be appreciated.
Try registering an onload event listener on the image element and then handle all code that depends on that image in the event listener, like so:
for (let i = 0; i < count / 3; i++) {
const cover = await GetVideoCover(item.video_url, i);
var url = URL.createObjectURL(cover);
var image = new Image();
image.src = url;
image.addEventListener('load', (event) => {
// perform some magic here e.g append to DOM or draw the image to canvas
}
}
Thank you for the contributions, the answers did not work but they helped me in the process. I solved the problem today and wanted to share it here.
I should have mentioned before as the created images are fed to vis.js.
When I experimented more, I saw vis.js does not append the created objects, but it changes the innerHTML of the timeline. (vis.js might not support blob images as src of img tag)
Then, I decided to give a shot to append element. To do that, I created a new div element, and appended the created images to that div.
I also added an additional promise level to the blob image creation process, since some files were missing.
Code snippet from newly added promise level:
const blobToImage = (itemVideoURL,captureSecond) => {
return new Promise(async (resolve,reject)=> {
let cover = await GetVideoCover(itemVideoURL,captureSecond);
const url = URL.createObjectURL(cover)
let img = new Image()
img.onload = () => {
URL.revokeObjectURL(url)
resolve(img)
}
img.src = url
img.height = '75'
})
}
Code snippet from new function:
let divElement = document.createElement('div');
for (let i = 0; i < count * 3; i++) {
let newImage = await blobToImage(item.video_url,i+1)
divElement.appendChild(newImage)
}
return divElement;
It magically worked.
You should use a single image rather than multiple images.
Just concatanate all images together :
let imgEle1 = document.querySelectorAll(".image")[0];
let imgEle2 = document.querySelectorAll(".image")[1];
let resEle = document.querySelector(".result");
var context = resEle.getContext("2d");
let BtnEle = document.querySelector(".Btn");
BtnEle.addEventListener("click", () => {
resEle.width = imgEle1.width;
resEle.height = imgEle1.height;
context.globalAlpha = 1.0;
context.drawImage(imgEle1, 0, 0);
context.globalAlpha = 0.5;
context.drawImage(imgEle2, 0, 0);
});

How to make progress bar with real percent number with Promise and Async/await with Just native javascript?

I have something i searched a lot about the solution but i don't find anything. Also i tried a lot of things but also no thing work with me. I hope to find something here.
I build a website, in some stages i allow the user to convert his images from any type to WEBP. So I made I constructor function to do this proccess:
async function loadImage(url) {
return await new Promise((resolve, reject) => {
let img = new Image();
img.addEventListener('load', e => resolve(img));
img.addEventListener('error', () => {
reject(new Error(`Failed to load image's URL: ${url}`));
});
img.src = url;
});
}
async function convert(image, options) {
let newImage = new Image();
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
return await new Promise((resolve) => {
canvas.width = image.width;
canvas.height = image.height;
ctx.drawImage(image, 0, 0, image.width, image.height);
// convert canvas to webp image
newImage.src = canvas.toDataURL(`image/${options.to}`, 1);
resolve(newImage)
});
}
async function Converter(userImage, options) {
let src = URL.createObjectURL(userImage);
let image = new Image();
image.src = src;
image.style.width = "auto";
image.style.height = "auto";
let t;
await loadImage(src).then(img => {
return convert(img, options)
}).then(newImage => {
t = newImage;
})
return t;
}
export default Converter;
I allow him to load the images and converting it with Javascript without upload the images to server.
I am using this function in another js file like this:
formInputs.addEventListener('change', e => {
if (formInputs.files.length > 0) {
updateFilatorTable(filatorInput.files);
}
})
As you see i am using promises and async/wait, for waiting images to load and convert. but the problem also here in await. how can i show the user Progress bar when the image loading and after that showing another progress bar when the image converting, with real percent for example: 25% converting.
Every thing working good but the problem is how to show progress bar when i load the image and when i convert it?
can i make something like that with promise and await?

Passing Images to JSZIP in a Promise

I am drawing a series of images on to a canvas, and passing the canvas image into a zip folder with JsZip. The filenames for the series of images is represented in the drawOrder Array.
Since the images take time to load, the drawImage() is done with a Promise. The image loads successfully on the canvas, but the zip generated returns as an empty zip file.
I suspect this is because toBlob and Promise are both asynchronous functions? My understanding on asynchronous functions is a little weak, I hope someone could explain why it is not working and point me in the right direction.
//THE PROMISE
function promiseAll(order){
return Promise.all(
order.map(function (t) {
return new Promise(function (resolve) {
var img = new Image();
img.src = "http://foo/" + t + ".png";
img.onload = function () {
resolve(img);
};
});
})
);
};
function toCanvas() {
var drawOrder = ["base1", "base2", "object1", "foreground1"];
var canvas = document.querySelector("canvas");
var ctx = canvas.getContext("2d");
//Use Preloader
promiseAll(drawOrder).then(function (allImages){
console.log("Layers loaded", allImages);
for (let k = 0; k < drawOrder.length; k++) {
ctx.drawImage(allImages[k], 0, 0, canvas.width, canvas.height)
};
canvas.toBlob(function(blob) {
zip.file("hello.png", blob);
};
});
};
zip.generateAsync({type:"base64"}).then(function (base64) {
location.href="data:application/zip;base64," + base64;
});

Esri Take Map Scrrenshots using Javascript

I am trying to generate a pdf report including current map screenshot of ESRI map using JavaScript. Here is my code.
var getCurrentMapScreenShot = function (success, error) {
esriLoader.Config.defaults.io.proxyUrl = myAppSettingsModel.SettingsModel.MapSettings.AGSProxyURL;
esriLoader.Config.defaults.io.alwaysUseProxy = true;
var printTask = new esriLoader.PrintTask("myexportUrl");
var template = new esriLoader.PrintTemplate();
template.exportOptions = {
width: 600,
height: 600,
dpi: 96
};
template.format = "image/png";
template.layout = "MAP_ONLY",
template.preserveScale = true;
template.layoutOptions = {
legendLayers: [], // empty array means no legend
scalebarUnit: "Miles"
};
var params = new esriLoader.PrintParameters();
params.map = map;
params.template = template;
printTask.execute(params, success, error);
}
This function will give you an event that contains a url , Then I am passing this url to get map base64 data.
Here is the function calling.
map.GetCurrentMapScreenShot(function (event) {
var mapScreenShotURL = event.url;
Factory.GetBase64ForImgUrl(mapScreenShotURL,
function (mapImageBase64Encoded) {});
and here is the function that converts url to base64image
function getBase64ForImgUrl(url, callback, outputFormat) {
console.log("#################### Summary Report Image " + url);
var canvas = document.createElement('CANVAS');
var ctx = canvas.getContext('2d');
var img = new Image;
img.crossOrigin = 'Anonymous';
img.onload = function () {
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img, 0, 0);
var dataURL = canvas.toDataURL(outputFormat || 'image/png');
callback.call(this, dataURL);
// Clean up
canvas = null;
};
img.src = url;
}
I am getting base64 image data of the map , But the problem is that, I am getting blurred image of the map with no feature layers and no icons..And also map contains some junk texts.
Thanks
I resolved the issue almost, Now I am getting the map image that contains map Icons and layer graphics, But unfortunately still getting some junk texts.
I have changed the code as follows.
template.format = "JPG";
template.layout = "A4 Landscape",
template.preserveScale = false;
template.layoutOptions = {
"legendLayers": [], // empty array means no legend
"scalebarUnit": "Miles"
}

Dont resolve promise until after images load

The below is supposed:
loop through a group of img tags
grab each tag's src url
convert it to a base64 encoded string using a HTML 5 canvas
once all images have been converted, the promise should be resolved and the callback called
My problem:
I need to wait for each image to load in the canvas before I can convert it to base64
to solve this I used `img.onload = function(){ ..... return base64Img; };
Unfortunately, calling img.src = element.src; each time through resolves the promise, it doesn't wait for the images to load and call return base64Img; so I end up with an empty array when $.when.apply($, promises).then(function(){}); is called.
How can I change this promise so that it does not resolve until all the images have been loaded and converted?
function accountCreation(){
$('#container').hide(); // hide the display while we save the info as it will take a few seconds, you should do a loading bar or something here instead
var user = Parse.User.current(); // get the currently logged in user object
// loop through each image element
var promises = $('.images').map(function(index, element) {
var src = $(element).attr('src');
var canvas = document.createElement('CANVAS');
var ctx = canvas.getContext('2d');
var img = new Image;
img.crossOrigin = 'Anonymous';
img.onload = function(){
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img,0,0);
var base64Img = canvas.toDataURL('image/png');
// Clean up
canvas = null;
return base64Img;
};
img.src = element.src;
});
$.when.apply($, promises).then(function() {
// arguments[0][0] is first result
// arguments[1][0] is second result and so on
for (var i = 0; i < arguments.length; i++) {
var file = new Parse.File("photo.jpg", { base64: arguments[i]}); // this part actually saves the image file to parse
user.set("image" + i, file); // set this image to the corosponding column on our object
}
// save the user object
user.save(null,{
success: function(user) {
$('#message').html('Profile Updated!');
$('#container').show(); // show the screen again, you should just remove your loading bar now if you used one
},
error: function(user, error) {
console.log('Failed to create new object, with error code: ' + error.message);
}
});
});
}
Your array of promises just contains undefined values, as the callback function doesn't return anything. As there are no Deferred objects in the array, the when method doesn't have anything to wait for, so it runs the then callback right away.
Create a Deferred object to return, and resolve it when the image is loaded:
var promises = $('.images').map(function(index, element) {
// created a Deferred object to return
var deferred = $.Deferred();
var src = $(element).attr('src');
var canvas = document.createElement('CANVAS');
var ctx = canvas.getContext('2d');
var img = new Image;
img.crossOrigin = 'Anonymous';
img.onload = function(){
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img,0,0);
var base64Img = canvas.toDataURL('image/png');
// Clean up
canvas = null;
// Resolve the Deferred object when image is ready
deferred.resolve(base64Img);
};
img.src = element.src;
// return the Deferred object so that it ends up in the array
return deferred;
});

Categories

Resources