I have this snippet of code.. i want to know where i'm wrong.. i save an image, that i have stored inside my project, into a new File.. but when i try to reconvert it to an image i get an empty image..
function selectImagesToUpload() {
const input = document.getElementById("product_pics");
const preview = document.querySelector(".preview");
const images = preview.querySelectorAll("div.preview > p");
images.forEach(async item => {
let fn = item.innerText.split(';')[0];
let ext = fn.slice(fn.lastIndexOf('.') + 1, fn.length);
let p = await fetch(fn).then(response => response.blob());
let b = await p.arrayBuffer();
let f0 = new File(new Uint8Array(b), fn, { type: `image/${ext}` });
var reader = new FileReader();
reader.onload = function (e) {
var image = document.createElement("img");
image.src = e.target.result;
document.body.appendChild(image);
}
reader.readAsDataURL(f0);
});
}
This is an example paragraph with the relative url (i set it in the assets of the project) : < p > img/prodotto7.jpg;< /p >
This is the result of the append to the dom : empty image
Can someone help me? This is like a test, i must do it work to go on with my project..
Investigating with some crazy tricks i get a "Uncaught InvalidCharacterError: Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded." on the line "atob(e.target.result);" so the FileReader isn't doing it's work correctly..
let fn = item.innerText.split(';')[0];
let ext = fn.slice(fn.lastIndexOf('.') + 1, fn.length);
let p = await fetch(fn).then(response => response.blob());
let b = await p.arrayBuffer();
let ua = new Uint8Array(b)
let u64 = ua.toBase64;
let f0 = new File( ua , fn, { type: `image/${ext}` });
console.log(f0);
const para = document.createElement("p");
para.textContent = item.textContent;
preview.appendChild(para);
var reader = new FileReader()
reader.onload = function (e) {
var image = document.createElement("img");
image.src = e.target.result;
console.log(image.src);
var bs = atob(e.target.result);
var buffer = new ArrayBuffer(bs.length);
var ba = new Uint8Array(buffer);
for (var i = 0; i < bs.length; i++) {
ba[i] = bs.charCodeAt(i);
}
var blob = new Blob([ba], { type: "image/jpg" });
document.body.appendChild(URL.createObjectURL(blob));
}
reader.readAsDataURL(f0);
SOLVED (i was needing mechanisms of File variables - transforming images and then get them back - with the scope to store images into a File[] or a FileList, then inside a FormData variable, with the final scope to post and get messages with a microservice, mission complete.. and now i added the synchronization!!)
service.ts
import { HttpClient } from "@angular/common/http";
import { Inject, Injectable } from "@angular/core";
import { DOCUMENT } from '@angular/common';
@Injectable({
providedIn: 'root'
})
export class GestioneProdottiService {
formData !: FormData;
fileTypes = [
"image/apng",
"image/bmp",
"image/gif",
"image/jpeg",
"image/pjpeg",
"image/png",
"image/svg+xml",
"image/tiff",
"image/webp",
"image/x-icon",
];
constructor(private httpClient: HttpClient,
@Inject(DOCUMENT) private document: Document) { }
insImages = (data: FormData) => {
//return this.httpClient.post<ApiMsg>(`http://${this.server}:${this.port}/url`, articolo);
}
getFormDataEntries() {
for (const pair of this.formData.entries())
console.log(pair[0], pair[1]);
}
selectImagesToUpload() {
return new Promise<File[]>(async (resolve) => {
console.log('promise');
const input = this.document.getElementById("product_pics");
const preview = this.document.querySelector(".preview");
const images = preview?.querySelectorAll("div.preview > p");
const arrSupp = new Array();
images?.forEach(item =>
arrSupp.push(item));
let fl: File[] = new Array();
//console.log(fl);
await Promise.all(arrSupp.map(async item => {
if (preview?.firstChild === undefined) {
console.log('primo');
/* *** TODO ***
const para = document.createElement("p");
console.log(item.innerText);
para.textContent = item.textContent;
preview.appendChild(para);
fl[i] = */
} else {
console.log('secondo');
//console.log(item.textContent);
let fn = item?.textContent?.split(';')[0];
let ext = fn?.slice(fn.lastIndexOf('.') + 1, fn.length);
if (fn) {
let p = await fetch(fn).then(response => response.blob());
let b = await p.arrayBuffer();
let ua = new Uint8Array(b)
//console.log(ua)
//let b64 = ua.toBase64(); //it does not work in some of the most widely-used browsers.
const bin = [];
for (let i = 0; i < ua.length; i++) {
bin.push(String.fromCharCode(ua[i]));
}
const b64encoded = btoa(bin.join(""));
//console.log(b64encoded);
const trimmedString = b64encoded.replace('dataimage/jpegbase64', '');
const imageContent = atob(trimmedString);
const buffer = new ArrayBuffer(imageContent.length);
const view = new Uint8Array(buffer);
for (let n = 0; n < imageContent.length; n++) {
view[n] = imageContent.charCodeAt(n);
}
const type = `image/${ext}`;
const blob = new Blob([buffer], { type });
let f0 = new File([blob], fn, { lastModified: new Date().getTime(), type });
var image = this.document.createElement("img");
image.src = `data:image/png;base64, ${b64encoded}`;
//console.log(image.src)
//console.log(f0);
this.document.body.appendChild(image); //img show!
this.Main(f0);
const para = this.document.createElement("p");
console.log(`filename : ${fn};`);
para.textContent = `${fn};`;
preview.appendChild(para);
fl.push(f0);
}
}
}));
while (preview?.firstChild) {
preview.removeChild(preview.firstChild);
}
const curFiles = (<HTMLInputElement>input)?.files;
if (curFiles?.length === 0) {
} else {
if (curFiles) {
for (const file of curFiles) {
if (this.validFileType(file)) {
let filename = String(file.name);
let image = filename.slice(0, filename.lastIndexOf('.'));
if (this.validImage(image)) {
const para = this.document.createElement("p");
//console.log(`filename : ${file.name};`);
para.textContent = `${filename};`;
preview?.appendChild(para);
fl.push(file);
this.Main(file);
}
}
}
}
}
resolve(fl);
})
}
async f() {
console.log("calling");
const result = await this.selectImagesToUpload().then(
(fl: File[]) => {
let fd = new FormData();
console.log('1then');
console.log(fl);
for (let i = 0; i < fl.length; i++) {
fd.append(fl[i].name, fl[i]);
}
this.formData = fd;
},
(err) => {
console.log('errore');
console.log(err);
});
}
validFileType(file: File) {
return this.fileTypes.includes(file.type);
}
validImage(image: string) {
return !image.includes(';') && !image.includes('.');
}
clearAllImages() {
const preview = this.document.querySelector(".preview");
const images = preview?.querySelector("div.preview > p");
while (preview?.firstChild) {
preview.removeChild(preview.firstChild);
}
this.formData = new FormData();
}
async Main(file: any) {
const toBase64 = (file: any) => new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
resolve(reader.result);
}
reader.onerror = reject;
});
let b64 = await toBase64(file);
//console.log(b64);
var image = this.document.createElement("img");
image.src = String(b64);
//let u8 = Uint8Array.fromBase64(b64); //it does not work in some of the most widely-used browsers.
this.document.body.appendChild(image); //img show!
}
}
component.ts
...
@ViewChild('product_pics')
productPicsInput!: ElementRef;
constructor(private gestioneProdotti: GestioneProdottiService) {}
...
selectImagesToUpload($event : any) {
this.gestioneProdotti.f();
}
clearValues($event: any) {
this.gestioneProdotti.clearAllImages();
const input = this.productPicsInput.nativeElement
input.value = "";
}
component.html
<!-- Immagine -->
<div class="mb-4">
<label class="form-label">Immagine:</label>
<input #product_pics class="form-control" type="file"
enctype="multipart/form-data"
id="product_pics"
name="product_pics"
accept=".jpg, .jpeg, .png"
(change)="selectImagesToUpload($event)" multiple />
<!application/x-www-form-urlencoded-->
<button type="button" class="btn btn-primary" (click)="clearValues($event)">Clear all</button>
</div>
<div id="uploadImages" class="preview">
@if(articolo.imgsrc){
<p>{{articolo.imgsrc}};</p>
}@else{
<p>No files currently selected for upload</p>
}
</div>