This commit is contained in:
yixu
2025-09-08 15:36:26 +08:00
commit 9a5cf53e3c
36 changed files with 7750 additions and 0 deletions

93
src/libs/haibao.js Normal file
View File

@@ -0,0 +1,93 @@
export default class Haibao {
constructor(width, height, color = '#fff') {
this.canvas = document.createElement('canvas');
this.ctx = this.canvas.getContext('2d', { alpha: false });
this.canvas.width = width;
this.canvas.height = height;
this.ctx.fillStyle = color;
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height)
this.zIndex = 0
this.imagePromises = []
this.images = []; // 存储待合成的图片信息
}
/**
* 添加图片到合成队列现在返回Promise
* @param {string|HTMLImageElement} image 图片URL或Image对象
* @param {number} x 绘制X坐标
* @param {number} y 绘制Y坐标
* @returns {Promise} 图片加载完成的Promise
*/
add (image, x, y, index) {
this.zIndex++
const zIndex = index ? index : this.zIndex
const loadPromise = this._createLoadPromise(image).then(img => {
this.images.push({ img, x, y, zIndex });
});
this.imagePromises.push(loadPromise);
return loadPromise;
}
/**
* 生成合成后的图片返回Promise
* @returns {Promise<string>} 合成后的Base64图片数据
*/
async generate (mimeType = 'image/jpeg', quality = .8) {
const validTypes = ['image/png', 'image/jpeg', 'image/webp'];
mimeType = validTypes.includes(mimeType) ? mimeType : 'image/png';
quality = Math.min(1, Math.max(0, Number(quality))) || .8;
await Promise.all(this.imagePromises);
// 清空画布
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// 绘制所有图片
this.images.sort((a, b) => a.zIndex - b.zIndex)
this.images.forEach(({ img, x, y, zIndex }) => {
this.ctx.drawImage(img, x, y);
});
const b64 = this.canvas.toDataURL(mimeType, quality)
this.images.length = 0;
this.imagePromises.length = 0;
return b64
}
// 创建加载Promise私有方法
_createLoadPromise (image) {
if (typeof image === 'string') {
return this._loadImageFromUrl(image);
} else if (image instanceof HTMLImageElement) {
return this._handleExistingImage(image);
}
return Promise.reject(new Error('Invalid image type'));
}
// 从URL加载图片
_loadImageFromUrl (url) {
return new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = 'anonymous';
img.src = url;
img.onload = () => resolve(img);
img.onerror = reject;
});
}
// 处理已存在的Image对象
_handleExistingImage (img) {
return new Promise((resolve, reject) => {
if (img.complete && img.naturalHeight !== 0) {
resolve(img);
} else {
img.onload = () => resolve(img);
img.onerror = reject;
}
});
}
}