我正在努力理解并使這段代碼正常作業。如您所見,它是一個可觀察的 Rxjs 服務。
我用 setTimeout 做了一個解決方法,試圖等到調整大小完成。否則,它會導致一個空的 fileBlobArray。
我已經研究并嘗試了一些諸如 promise.all 和 async-await 沒有成功。
謝謝你的幫助。
import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class resizeService {
constructor() { }
resizeImage(files: FileList, maxWidth: number, maxHeight: number): Observable<any> {
let resizedFileSubject = new Subject();
let fileBlobArray: Blob[] = [];
Array.from(files).map((file, i, { length }) => {
let image: HTMLImageElement = new Image();
image.src = URL.createObjectURL(file);
image.onload = async () => {
let width = image.width;
let height = image.height;
let canvas = document.createElement('canvas');
let ctx: any = canvas.getContext("2d");
let newHeight;
let newWidth;
const ratio = width / height;
// Calculate aspect ratio
if (width > height) {
newWidth = maxHeight * ratio;
newHeight = maxHeight;
} else {
newWidth = maxWidth * ratio;
newHeight = maxWidth;
}
canvas.width = newWidth;
canvas.height = newHeight;
// Draw image on canvas
ctx.drawImage(image, 0, 0, newWidth, newHeight);
fileBlobArray.push(await this.b64ToBlob(canvas.toDataURL("image/jpeg")));
// Detect end of loop
if (i 1 === length) {
// Wait to get async data - Workaround :(
// setTimeout(() => {
resizedFileSubject.next(fileBlobArray);
// console.log('next: ', fileBlobArray)
// }, 1000);
}
}
});
return resizedFileSubject.asObservable();
}
/**
* Convert BASE64 to BLOB
* @param base64Image Pass Base64 image data to convert into the BLOB
*/
private async b64ToBlob(base64Image: string) {
const parts = base64Image.split(';base64,');
const imageType = parts[0].split(':')[1];
const decodedData = window.atob(parts[1]);
const uInt8Array = new Uint8Array(decodedData.length);
for (let i = 0; i < decodedData.length; i) {
uInt8Array[i] = decodedData.charCodeAt(i);
}
return new Blob([uInt8Array], { type: imageType });
}
}
uj5u.com熱心網友回復:
我建議按此順序研究異步 JS/TS 的基礎知識。
- 創建并回傳一個 Promise。
- 承諾.all()
- 異步/等待
- RxJS
考慮到您的示例代碼,您實際上并不需要 RxJS 來滿足此要求。您的服務方法的目的是根據引數中傳遞的影像陣列回傳一個 blob 陣列。
在您了解上述 Promise 的基礎知識之前,請避免在代碼中添加 async/await。目前,您的所有 async/await 關鍵字都沒有做任何事情,因為您的代碼中沒有承諾。
onload純粹看需求,當事件在單個檔案上觸發時,您希望回傳一個新的 blob 。為此,您需要創建一個在onload呼叫函式時決議的 Promise。為簡單起見,我將您的onload函式移至名為handleOnLoad().
return new Promise((res, rej) => {
let image: HTMLImageElement = new Image();
image.src = URL.createObjectURL(file);
image.onload = () => res(this.handleOnLoad(image, maxWidth, maxHeight));
});
現在您Array.from(files).map()可以回傳這些承諾的陣列。陣列中的每個檔案一個。您現在可以將這個陣列包裝在里面Promise.all(),并將其作為您的回傳物件。
這是一個完整的例子。我添加了一個 try/catch 塊來處理 Promise 拒絕:
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class resizeService {
constructor() {}
resizeImage(files: FileList, maxWidth: number, maxHeight: number) {
return Promise.all(
Array.from(files).map(file => {
return new Promise((res, rej) => {
try {
let image: HTMLImageElement = new Image();
image.src = URL.createObjectURL(file);
image.onload = () => res(this.handleOnLoad(image, maxWidth, maxHeight));
} catch (e) {
rej(e);
}
});
})
);
}
private handleOnLoad(
image: HTMLImageElement,
maxWidth: number,
maxHeight: number
) {
let width = image.width;
let height = image.height;
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
let newHeight;
let newWidth;
const ratio = width / height;
// Calculate aspect ratio
if (width > height) {
newWidth = maxHeight * ratio;
newHeight = maxHeight;
} else {
newWidth = maxWidth * ratio;
newHeight = maxWidth;
}
canvas.width = newWidth;
canvas.height = newHeight;
// Draw image on canvas
ctx.drawImage(image, 0, 0, newWidth, newHeight);
return this.b64ToBlob(canvas.toDataURL('image/jpeg'));
}
/**
* Convert BASE64 to BLOB
* @param base64Image Pass Base64 image data to convert into the BLOB
*/
private b64ToBlob(base64Image: string) {
const parts = base64Image.split(';base64,');
const imageType = parts[0].split(':')[1];
const decodedData = window.atob(parts[1]);
const uInt8Array = new Uint8Array(decodedData.length);
for (let i = 0; i < decodedData.length; i) {
uInt8Array[i] = decodedData.charCodeAt(i);
}
return new Blob([uInt8Array], { type: imageType });
}
}
現在這resizeImage()是回傳一個 Promise。您可以在 async/await 函式中呼叫它。
/** Component Class **/
public async resizeEvent(){
const newImages = await service.resizeImage(files, 1920, 1080);
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/415768.html
標籤:
