functions not defined inside another function - javascript

I'm trying to make a download button and want the images to be downloadable. However, I'm facing trouble as two of my function toBlob and save functions are being told to be undefined.
What am I doing wrong here? I'm using Vue.
methods: {
async downloadImage(val) {
const blob = await toBlob(src);
save(blob, 'image.jpg');
},
toBlob(src) {
new Promise((res) => {
const img = document.createElement("img");
const c = document.createElement("canvas");
const ctx = c.getContext("2d");
img.onload = ({ target }) => {
c.width = target.naturalWidth;
c.height = target.naturalHeight;
ctx.drawImage(target, 0, 0);
c.toBlob((b) => res(b), "image/jpeg", 0.5);
};
img.crossOrigin = "";
img.src = src;
});
save = (blob, name = "image.jpg") => {
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.target = "_blank";
a.download = name;
a.click();
};
},
}

You can't reference fields defined in an object from that object. I.e., you can't do:
let x = {
y: 0,
z: y + 1,
};
The simplest alternative is to define the reused (or all) fields outside the object:
let y = 0;
let x = {
y,
z: y + 1
};
OR
let y = 0;
let z = y + 1;
let x = {y, z};
You also have some minor syntax errors. E.g., you can't have {x: 3;}.
For your example, this would look like:
let downloadImage = async val => {
const blob = await toBlob(src);
save(blob, 'image.jpg');
};
let toBlob = async src => {
new Promise((res) => {
const img = document.createElement("img");
const c = document.createElement("canvas");
const ctx = c.getContext("2d");
img.onload = ({target}) => {
c.width = target.naturalWidth;
c.height = target.naturalHeight;
ctx.drawImage(target, 0, 0);
c.toBlob((b) => res(b), "image/jpeg", 0.5);
};
img.crossOrigin = "";
img.src = src;
})
};
let save = (blob, name = "image.jpg") => {
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.target = "_blank";
a.download = name;
a.click();
};
let obj = {methods: {downloadImage, toBlob, save}}

To call other methods in the Vue instance you use this.
And you should also be returning the Promise from toBlob
methods: {
async downloadImage(val) {
const blob = await this.toBlob(src);
this.save(blob, 'image.jpg');
},
toBlob(src) {
return new Promise((res) => {
const img = document.createElement("img");
const c = document.createElement("canvas");
const ctx = c.getContext("2d");
img.onload = ({
target
}) => {
c.width = target.naturalWidth;
c.height = target.naturalHeight;
ctx.drawImage(target, 0, 0);
c.toBlob((b) => res(b), "image/jpeg", 0.5);
};
img.crossOrigin = "";
img.src = src;
});
}
save(blob, name = "image.jpg") {
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.target = "_blank";
a.download = name;
a.click();
}
}
}

Related

Uncaught (in promise) Error: Failed to compile fragment shader Error in Tensorflow.js project

I'm using face-api.js Javascript API to develop a web app that user uploads her/his picture and we want to detect faces in the picture.
On the other hand I used VGGface 16 model json formatted to predict that user uploaded image is similar to which celebrity.
following are my javascript codes:
const MODEL_URL = '../faceapi_models'
Promise.all([
faceapi.nets.ssdMobilenetv1.loadFromUri(MODEL_URL),
faceapi.nets.faceRecognitionNet.loadFromUri(MODEL_URL),
// faceapi.nets.faceLandmark68Net.loadFromUri(MODEL_URL),
])
.then((val) => {
console.log('val')
})
.catch((err) => {
console.log(err)
})
let model
async function loadModel() {
model = await tf.loadLayersModel('../web_model/vgg_model.json');
}
loadModel()
.then((val) => {
console.log('Model is Loaded');
})
.catch((err) => {
console.log('Model Not Load : ' + err)
})
let croppedImage = null;
const user_pic = document.getElementById('user_pic')
const preview = document.getElementById('preview')
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
window.onload = function() {
canvas.width = preview.width;
canvas.height = preview.height;
ctx.drawImage(preview, 0, 0);
};
preview.onclick = () => user_pic.click()
user_pic.addEventListener('change', () => {
const reader = new FileReader()
reader.onload = (e) => {
const img = new Image();
img.onload = function() {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
};
img.src = e.target.result;
}
reader.readAsDataURL(user_pic.files[0]);
detectFaces(user_pic.files[0])
})
async function detectFaces(input) {
let imgURL = URL.createObjectURL(input)
const imgElement = new Image()
imgElement.src = imgURL
const results = await faceapi.detectAllFaces(imgElement)
.then(results => {
if (Array.isArray(results) && results.forEach) {
results.forEach(result => {
const { x, y, width, height } = result.box;
const crop = ctx.getImageData(x, y, width, height);
croppedImage = new ImageData(crop.data, width, height);
const input = tf.browser.fromPixels(croppedImage);
const resizedImage = tf.image.resizeBilinear(input, [224, 224]);
const inputTensor = resizedImage.expandDims(0);
const predictions = model.predict(inputTensor).data();
const celebrityIndex = predictions.indexOf(Math.max(...predictions));
console.log(celebrityIndex)
// const celebrityName = celebrityLabels[celebrityIndex];
// Display the results
// const resultDisplay = document.getElementById('result');
// resultDisplay.innerHTML = `Most similar celebrity: ${celebrityName}`;
});
} else {
console.error('Results is not an array or does not have a forEach function.');
}
});
}
I have solve many problem that I have yet but I do not know how to handle this problem and Why did this problem arise?
This is complete erorr :
I found that problem is with x, y, width, height constants that had float values. a simple way is converting those to Int like this :
const {x, y, width, height} = result.box;
const xInt = Math.floor(x);
const yInt = Math.floor(y);
const widthInt = Math.floor(width);
const heightInt = Math.floor(height);

How to turn this promise based function into rxjs function?

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;
});
}

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;
});
}

JSON to PNG Empty picture

Need help with my function to download a PNG from a SVG.
I read many similar post about that but don't succeed to apply to my code.
The image that I download is empty ...
My code :
function downloadCarteJPEG(nom,dpi) {
var svg = document.querySelector("svg");
var svgData = "";
if (typeof window.XMLSerializer != "undefined") {
svgData = (new XMLSerializer()).serializeToString(svg);
} else {
console.error("XMLSerializer undefined");
return;
}
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
var svgSize = svg.getBoundingClientRect();
canvas.width = svgSize.width * dpi / 25.4;
canvas.height = svgSize.height * dpi / 25.4;
var data = btoa(unescape(encodeURIComponent(svgData)));
data = 'data:image/svg+xml;base64,' + data;
var image = document.createElement("img");
image.onload = function() {
ctx.drawImage(image, 0, 0);
var link = document.createElement("a");
link.download = nom;
link.href = canvas.toDataURL("image/png");
document.querySelector("body").appendChild(link);
link.click();
document.querySelector("body").removeChild(link);
};
image.src = data;
console.log("EXIT");
}

Categories