You've already forked Nano-Banana-AI-Image-Editor
146 lines
4.0 KiB
TypeScript
146 lines
4.0 KiB
TypeScript
export function base64ToBlob(base64: string, mimeType: string = 'image/png'): Blob {
|
||
const byteCharacters = atob(base64);
|
||
const byteNumbers = new Array(byteCharacters.length);
|
||
|
||
for (let i = 0; i < byteCharacters.length; i++) {
|
||
byteNumbers[i] = byteCharacters.charCodeAt(i);
|
||
}
|
||
|
||
const byteArray = new Uint8Array(byteNumbers);
|
||
return new Blob([byteArray], { type: mimeType });
|
||
}
|
||
|
||
export function blobToBase64(blob: Blob): Promise<string> {
|
||
return new Promise((resolve, reject) => {
|
||
const reader = new FileReader();
|
||
reader.onload = () => {
|
||
const result = reader.result as string;
|
||
const base64 = result.split(',')[1]; // Remove data:image/png;base64, prefix
|
||
resolve(base64);
|
||
};
|
||
reader.onerror = reject;
|
||
reader.readAsDataURL(blob);
|
||
});
|
||
}
|
||
|
||
// 将URL转换为Blob
|
||
export async function urlToBlob(url: string): Promise<Blob> {
|
||
const response = await fetch(url);
|
||
return await response.blob();
|
||
}
|
||
|
||
export function createImageFromBase64(base64: string): Promise<HTMLImageElement> {
|
||
return new Promise((resolve, reject) => {
|
||
const img = new Image();
|
||
img.onload = () => resolve(img);
|
||
img.onerror = reject;
|
||
img.src = `data:image/png;base64,${base64}`;
|
||
});
|
||
}
|
||
|
||
export function resizeImageToFit(
|
||
image: HTMLImageElement,
|
||
maxWidth: number,
|
||
maxHeight: number
|
||
): { width: number; height: number } {
|
||
const ratio = Math.min(maxWidth / image.width, maxHeight / image.height);
|
||
return {
|
||
width: image.width * ratio,
|
||
height: image.height * ratio
|
||
};
|
||
}
|
||
|
||
export function generateId(): string {
|
||
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
||
}
|
||
|
||
export function downloadImage(imageData: string, filename: string): void {
|
||
if (imageData.startsWith('blob:')) {
|
||
// 对于Blob URL,我们需要获取实际的Blob数据
|
||
fetch(imageData)
|
||
.then(response => response.blob())
|
||
.then(blob => {
|
||
const url = URL.createObjectURL(blob);
|
||
const a = document.createElement('a');
|
||
a.href = url;
|
||
a.download = filename;
|
||
document.body.appendChild(a);
|
||
a.click();
|
||
document.body.removeChild(a);
|
||
URL.revokeObjectURL(url);
|
||
});
|
||
} else if (imageData.startsWith('data:')) {
|
||
// 对于数据URL,直接下载
|
||
const a = document.createElement('a');
|
||
a.href = imageData;
|
||
a.download = filename;
|
||
document.body.appendChild(a);
|
||
a.click();
|
||
document.body.removeChild(a);
|
||
} else {
|
||
// 对于其他URL,获取并转换为blob
|
||
fetch(imageData)
|
||
.then(response => response.blob())
|
||
.then(blob => {
|
||
const url = URL.createObjectURL(blob);
|
||
const a = document.createElement('a');
|
||
a.href = url;
|
||
a.download = filename;
|
||
document.body.appendChild(a);
|
||
a.click();
|
||
document.body.removeChild(a);
|
||
URL.revokeObjectURL(url);
|
||
});
|
||
}
|
||
}
|
||
|
||
// 优化的图像压缩函数
|
||
export async function compressImage(blob: Blob, quality: number = 0.8): Promise<Blob> {
|
||
return new Promise((resolve, reject) => {
|
||
const canvas = document.createElement('canvas');
|
||
const ctx = canvas.getContext('2d');
|
||
|
||
if (!ctx) {
|
||
reject(new Error('无法获取canvas上下文'));
|
||
return;
|
||
}
|
||
|
||
const img = new Image();
|
||
img.onload = () => {
|
||
// 设置canvas尺寸
|
||
canvas.width = img.width;
|
||
canvas.height = img.height;
|
||
|
||
// 绘制图像
|
||
ctx.drawImage(img, 0, 0);
|
||
|
||
// 转换为Blob
|
||
canvas.toBlob(
|
||
(compressedBlob) => {
|
||
if (compressedBlob) {
|
||
resolve(compressedBlob);
|
||
} else {
|
||
reject(new Error('图像压缩失败'));
|
||
}
|
||
},
|
||
'image/jpeg',
|
||
quality
|
||
);
|
||
};
|
||
|
||
img.onerror = reject;
|
||
|
||
// 将Blob转换为URL以便加载到图像中
|
||
const url = URL.createObjectURL(blob);
|
||
img.src = url;
|
||
|
||
// 清理URL
|
||
img.onload = () => {
|
||
URL.revokeObjectURL(url);
|
||
// 调用原始的onload处理程序
|
||
if (img.onload) {
|
||
(img.onload as (() => void)).call(img);
|
||
}
|
||
};
|
||
});
|
||
} |