UNPKG

@msom/common

Version:

@msom/common

147 lines (131 loc) 4.14 kB
/** * 图片分割器类 - 用于加载图片并根据配置分割图片 */ export class ImageSplitter { private processedImages: Map<string, string>; // 存储处理后的图片数据 (name -> base64) private taskQueue: Array<{ imageUrl: string; configUrl: string; }>; // 任务队列 private isProcessing: boolean; // 标记是否正在处理任务 /** * 构造函数 - 初始化图片分割器 */ constructor() { this.processedImages = new Map(); this.taskQueue = []; this.isProcessing = false; } /** * 添加图片分割任务(链式调用) * @param imageUrl - 要分割的图片URL * @param configUrl - 分割配置的JSON文件URL * @returns 当前实例(支持链式调用) */ add(imageUrl: string, configUrl: string): this { this.taskQueue.push({ imageUrl, configUrl }); if (!this.isProcessing) { this.processQueue(); } return this; } /** * 获取分割后的图片base64数据 * @param name - 配置中定义的图片名称 * @returns base64图片数据或null(如果不存在) */ get(name: string): string | null { if (this.processedImages.has(name)) { return this.processedImages.get(name) as string; } console.warn(`[ImageSplitter] 图片名称 "${name}" 不存在`); return null; } /** * 处理任务队列(私有方法) */ private async processQueue(): Promise<void> { if (this.taskQueue.length === 0) { this.isProcessing = false; return; } this.isProcessing = true; const task = this.taskQueue.shift()!; try { // 并行加载图片和配置 const [image, config] = await Promise.all([ this.loadImage(task.imageUrl), this.fetchConfig(task.configUrl), ]); // 处理每个分割区域 for (const [name, region] of Object.entries(config)) { if (this.processedImages.has(name)) { console.warn(`[ImageSplitter] 名称冲突: "${name}" 已存在,跳过`); continue; } const base64 = this.cropImage(image, region); this.processedImages.set(name, base64); } } catch (error) { console.error("[ImageSplitter] 处理任务失败:", error); } // 递归处理下一个任务 this.processQueue(); } /** * 加载图片(私有方法) * @param url - 图片URL * @returns 加载完成的Image对象 */ private loadImage(url: string): Promise<HTMLImageElement> { return new Promise((resolve, reject) => { const img = new Image(); img.crossOrigin = "Anonymous"; // 处理跨域问题 img.onload = () => resolve(img); img.onerror = (e) => reject(new Error(`图片加载失败: ${url}`)); img.src = url; }); } /** * 获取配置(私有方法) * @param url - 配置JSON的URL * @returns 解析后的配置对象 */ private async fetchConfig( url: string ): Promise< Record<string, { x: number; y: number; width: number; height: number }> > { const response = await fetch(url); if (!response.ok) throw new Error(`配置加载失败: ${url}`); return response.json(); } /** * 裁剪图片(私有方法) * @param image - 原始图片对象 * @param region - 裁剪区域 { x, y, width, height } * @returns base64格式的图片数据 */ private cropImage( image: HTMLImageElement, region: { x: number; y: number; width: number; height: number } ): string { const canvas = document.createElement("canvas"); canvas.width = region.width; canvas.height = region.height; const ctx = canvas.getContext("2d"); if (!ctx) throw new Error("无法获取canvas上下文"); ctx.drawImage( image, region.x, region.y, region.width, region.height, // 源图裁剪区域 0, 0, region.width, region.height // 画布绘制区域 ); return canvas.toDataURL("image/png"); } }