How to turn this promise based function into rxjs function? - javascript

I have this promise based function and im trying to update it to have the same functionality but use RXJS, im a bit new to rxjs and having a lot of trouble.. any help would be really appreciated
public getBase64ImageFromURL(url: string): Promise<any> {
return new Promise((resolve, reject) => {
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);
const dataURL = canvas.toDataURL('image/png');
resolve(dataURL);
};
img.onerror = error => {
reject(error);
};
img.src = url;
});
}

It's pretty straight forward : create a new Observable and next the same value as the resolve !
public getBase64ImageFromURL(url: string): Observable<string> {
return new Observable<string>((subscriber) => {
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);
const dataURL = canvas.toDataURL('image/png');
subscriber.next(dataURL);
};
img.onerror = (error) => {
subscriber.error(error);
};
img.src = url;
});
}

Related

Image dimensions not reflected correctly

I am trying to get the base64 of some images in Javascript and was using this function:
function getBase64Image(img) {
return new Promise((data) => {
var canvas = document.createElement("canvas");
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
data(canvas.toDataURL("image/png").replace(/^data:image\/(png|jpg|jpeg);base64,/, ""))
})
}
Then I call the function to load in the image using:
var img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = function () {
getBase64Image(this).then(data => {})
}
img.src = wha[1][0]
If I look at the naturalWidth of the image (96px), it is different from the actual image itself (640px). I had been looking at other methods of getting base64 from an image but they also return the same results.

JS image to base64 return string

I have code that works fine
function convertImgToBase64URL(url, callback, outputFormat){
var img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = function(){
var canvas = document.createElement('CANVAS'),
ctx = canvas.getContext('2d'), dataURL;
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img, 0, 0);
dataURL = canvas.toDataURL(outputFormat);
callback(dataURL);
canvas = null;
};
img.src = url;
}
convertImgToBase64URL('/img/logo.png', function(base64Img){
console.log(base64Img);
});
But I need to get the result into a variable
convertImgToBase64URL('/img/logo.png', function(base64Img){
var test = base64Img;
});
alert(test);
Any idea how to pass the result to a variable?

image onload not triggering inside of promise

Hello I created a promise and call it recursively from a loop to fill an array but the onload never triggers thus never resolving the promise.
Can anyone see anything I'm doing wrong?
function imageResizeToDataUriPromise(url, width, height) {
return new Promise(function (resolve, reject) {
var img = new Image();
img.setAttribute('crossOrigin', 'anonymous');
img.onload = function () {
var imgWidth = img.naturalWidth;
var imgHeight = img.naturalHeight;
var result = _scaleImage(imgWidth, imgHeight, width, height, true);
//create an off-screen canvas
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width = result.width;
canvas.height = result.height;
//draw source image into the off-screen canvas:
ctx.drawImage(img, 0, 0, result.width, result.height);
resolve(canvas.toDataURL());
};
img.src = url;
});
}
this is my basic calling block but its in a loop
caller(logo, 150, 150).then
(function (response) {
console.log("Success!", response);
base64Urls.push(response);
});
It works after I use that promise to get an URL and set it to an image element... not sure how you would use the return Data URL. One possible issue is: can you check whether your image source is serving you the image. (double check the network tab in developer tool).
function imageResizeToDataUriPromise(url, width, height) {
return new Promise(function(resolve, reject) {
var img = new Image();
img.setAttribute('crossOrigin', 'anonymous');
img.onload = function() {
console.log("IMG ONLOAD handler invoked");
var imgWidth = img.naturalWidth;
var imgHeight = img.naturalHeight;
var result = img;
//create an off-screen canvas
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width = result.width;
canvas.height = result.height;
//draw source image into the off-screen canvas:
ctx.drawImage(img, 0, 0, result.width, result.height);
ctx.fillStyle = "white";
ctx.font = '21px sans-serif';
ctx.fillText('Hello world', 21, 51);
resolve(canvas.toDataURL());
};
img.src = url;
});
}
imageResizeToDataUriPromise("https://i.imgur.com/j7Ie7pg.jpg", 100, 100)
.then(url => document.querySelector("#an-image").src = url);
console.log("Promise obtained");
<img id="an-image">

Image File Compression before upload

The method below is being used as a parameter for another variable. But the problem here is that it is not returning the file back after it is being compressed.
async CompressImage(imageFile: File): Promise<File> {
return new Promise<File>((resolve, reject) => {
const cReader = new FileReader();
const image = new Image();
cReader.onload = () => {
image.src = cReader.result.toString();
image.onload = () => {
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
context.drawImage(image, 0, 0);
//width & height initialization
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0, width, height);
const convertedFile = canvas.toBlob((blob) => {
const scaledDown = new File([blob], imageFile.name);
});
resolve(convertedFile);
}
};
cReader.readAsDataURL(mediaFile);
});
}

Javascript - Wait for array to finish populating

I am trying to get the value of some array elements. It works for the elements [0], [1], [2], [3], but not [4].
function getBase64() {
const urls = ['https://i.imgur.com/egNg7JU.jpg',
'https://i.imgur.com/RLZ7WH1.jpg', 'https://i.imgur.com/qfabBbA.jpg',
'https://i.imgur.com/Zuh1KaX.jpg', 'https://i.imgur.com/yD7X6Q1.jpg'
];
let base64urls = [];
const start = async () => {
await asyncForEach(urls, async (num) => {
await waitFor(50)
toDataURL(num, function(dataURL) {
base64urls.push(dataURL);
});
})
console.log(base64urls);
console.log(base64urls[4]);
}
start()
}
async function asyncForEach(array, callback) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array)
}
}
const waitFor = (ms) => new Promise(r => setTimeout(r, ms))
toDataURL simply returns the base64 value of an image. Whenever I try console.log(base64urls[4]), it returns 'undefined'. I do get the correct value for the previous elements. Is there some way to restructure this, or perhaps use a different method of waiting for the array to completely populate before checking for the values of its elements?
EDIT
Here is my toDataURL
function toDataURL(src, callback) {
const image = new Image();
image.crossOrigin = 'Anonymous';
image.onload = function () {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.height = this.naturalHeight;
canvas.width = this.naturalWidth;
context.drawImage(this, 0, 0);
const dataURL = canvas.toDataURL('image/jpeg');
callback(dataURL);
};
image.src = src;
}
It looks like toDataURL is asynchronous and callback-based - either change it so that it returns a Promise and await that Promise, or pass a Promise's resolve into the callback:
async function getBase64() {
const urls = ['https://i.imgur.com/egNg7JU.jpg',
'https://i.imgur.com/RLZ7WH1.jpg', 'https://i.imgur.com/qfabBbA.jpg',
'https://i.imgur.com/Zuh1KaX.jpg', 'https://i.imgur.com/yD7X6Q1.jpg'];
const base64urls = [];
for (const url of urls) {
const dataURL = await new Promise(resolve => toDataURL(url, resolve));
base64urls.push(dataURL);
}
console.log(base64urls);
console.log(base64urls[4]);
}
If you want to change your toDataURL function to return a Promise so you don't have to treat it like a callback:
function toDataURL(src) {
return new Promise(resolve => {
const image = new Image();
image.crossOrigin = 'Anonymous';
image.onload = function () {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.height = this.naturalHeight;
canvas.width = this.naturalWidth;
context.drawImage(this, 0, 0);
const dataURL = canvas.toDataURL('image/jpeg');
resolve(dataURL);
};
image.src = src;
});
}
and then const dataURL = await toDataURL(url)
You can use promise.all for this kind of situation to wait for the results of your queries
const urls = ['https://i.imgur.com/egNg7JU.jpg',
'https://i.imgur.com/RLZ7WH1.jpg', 'https://i.imgur.com/qfabBbA.jpg',
'https://i.imgur.com/Zuh1KaX.jpg', 'https://i.imgur.com/yD7X6Q1.jpg'];
let base64urls = [];
Promise.all(urls.map(url => fetch(url))).then(res => toBase64DataURL(res)).then(result => {base64urls.push(result.toDataURL());
console.log(base64urls);});
function toBase64DataURL(src) {
return new Promise(resolve => {
const image = new Image();
image.crossOrigin = 'Anonymous';
image.onload = _=> {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.height = this.naturalHeight;
canvas.width = this.naturalWidth;
context.drawImage(this, 0, 0);
const dataURL = canvas.toDataURL('image/jpeg');
resolve(dataURL);
};
image.src = src;
});
}

Categories