Files
aida_front/src/component/Canvas/CanvasEditor/utils/imageHelper.js

1239 lines
33 KiB
JavaScript
Raw Normal View History

2025-06-09 10:25:54 +08:00
//import { fabric } from "fabric-with-all";
import { LayerType, OperationType, createBitmapLayer } from "./layerHelper";
// 导入新的复合命令
import { CreateImageLayerCommand } from "../commands/LayerCommands";
// 导入新的命令
import {
ChangeFixedImageCommand,
AddImageToLayerCommand,
} from "../commands/LayerCommands";
/**
* 加载并处理图片
* @param {string} imageSource - 图片URL或Base64字符串
* @param {Object} options - 配置选项
* @param {number} options.maxWidth - 最大宽度
* @param {number} options.maxHeight - 最大高度
* @param {boolean} options.centerOnCanvas - 是否居中图片
* @param {function} options.onLoad - 加载完成回调
* @returns {Promise<Object>} - 返回图片对象的Promise
*/
export function loadImage(imageSource, options = {}) {
return new Promise((resolve, reject) => {
fabric.Image.fromURL(
imageSource,
(fabricImage) => {
if (!fabricImage) {
reject(new Error("加载图片失败"));
return;
}
// 计算缩放比例
const imgWidth = fabricImage.width;
const imgHeight = fabricImage.height;
// 应用缩放
if (options.maxWidth && options.maxHeight) {
const scaleX = options.maxWidth / imgWidth;
const scaleY = options.maxHeight / imgHeight;
const scale = Math.min(scaleX, scaleY, 1); // 不超过原始大小
fabricImage.scale(scale);
}
// 设置图片位置 - 默认居中
if (options.centerOnCanvas !== false) {
fabricImage.set({
left: (options.canvasWidth || 800) / 2,
top: (options.canvasHeight || 600) / 2,
originX: "center",
originY: "center",
selectable: true,
hasControls: true,
hasBorders: true,
});
}
// 执行加载完成回调
if (typeof options.onLoad === "function") {
options.onLoad(fabricImage);
}
resolve(fabricImage);
},
{ crossOrigin: "anonymous" }
);
});
}
/**
* 创建图片图层
* @param {Object} layerManager - 图层管理器
* @param {Object} fabricImage - fabric图片对象
* @param {Object} toolManager - 工具管理器
* @param {string} layerName - 图层名称 (可选)
* @returns {Promise<string>} 新图层ID
*/
export async function createImageLayer({
layerManager,
fabricImage,
toolManager,
layerName = null,
} = {}) {
if (!layerManager || !fabricImage) {
console.error("图层管理器或图片对象无效");
return null;
}
try {
// 使用新的复合命令
const createImageLayerCmd = new CreateImageLayerCommand({
layerManager,
fabricImage,
toolManager,
layerName,
});
// 执行复合命令
const newLayerId = await layerManager.commandManager.execute(
createImageLayerCmd
);
return newLayerId;
} catch (error) {
console.error("创建图片图层失败:", error);
throw error;
}
}
/**
* 更改固定图层的图像
* @param {Object} options - 配置选项
* @param {Object} options.layerManager - 图层管理器
* @param {string} options.fixedLayerId - 固定图层ID
* @param {Object} options.fabricImage - 新的图像对象
* @returns {Promise<boolean>} 是否成功更改
*/
export async function changeFixedImage({
layerManager,
fixedLayerId,
fabricImage,
} = {}) {
if (!layerManager || !fixedLayerId || !fabricImage) {
console.error("更改固定图层图像:参数无效");
return false;
}
try {
// 创建更改固定图层图像命令
const changeFixedImageCmd = new ChangeFixedImageCommand({
canvas: layerManager.canvas,
layers: layerManager.layers,
fixedLayerId,
newImage: fabricImage,
layerManager,
});
// 通过命令管理器执行
const result = await layerManager.commandManager.execute(
changeFixedImageCmd
);
if (result) {
console.log(`✅ 成功更改固定图层 "${fixedLayerId}" 的图像`);
}
return result;
} catch (error) {
console.error("更改固定图层图像失败:", error);
throw error;
}
}
/**
* 添加图片到指定图层或创建新图层
* @param {Object} options - 配置选项
* @param {Object} options.layerManager - 图层管理器
* @param {Object} options.toolManager - 工具管理器
* @param {Object} options.fabricImage - 图像对象
* @param {string} options.targetLayerId - 目标图层ID可选未指定则创建新图层
* @param {string} options.layerName - 图层名称用于新建图层
* @returns {Promise<string>} 图层ID
*/
export async function addImageToLayer({
layerManager,
toolManager,
fabricImage,
targetLayerId = null,
layerName = null,
} = {}) {
if (!layerManager || !fabricImage) {
console.error("添加图片到图层:参数无效");
return null;
}
try {
// 创建添加图片到图层命令
const addImageToLayerCmd = new AddImageToLayerCommand({
canvas: layerManager.canvas,
layers: layerManager.layers,
layerManager,
toolManager,
fabricImage,
targetLayerId,
layerName,
activeLayerId: layerManager.activeLayerId,
});
// 通过命令管理器执行
const resultLayerId = await layerManager.commandManager.execute(
addImageToLayerCmd
);
if (resultLayerId) {
if (targetLayerId) {
console.log(`✅ 成功添加图片到现有图层 "${targetLayerId}"`);
} else {
console.log(`✅ 成功创建新图层 "${resultLayerId}" 并添加图片`);
}
}
return resultLayerId;
} catch (error) {
console.error("添加图片到图层失败:", error);
throw error;
}
}
/**
* 从File对象加载图片并创建图层
* @param {File} file - 文件对象
* @param {Object} layerManager - 图层管理器
* @param {Object} canvas - fabric.js画布实例
* @param {Object} options - 配置选项
* @returns {Promise<string>} 新图层ID的Promise
*/
export function uploadImageAndCreateLayer(
{ file, layerManager, canvas, toolManager },
options = {}
) {
return new Promise((resolve, reject) => {
if (!file || !layerManager || !canvas) {
reject(new Error("参数无效"));
return;
}
const reader = new FileReader();
reader.onload = async (e) => {
try {
// 查找背景图层以获取尺寸
const bgLayer = layerManager.layers.value.find(
(layer) => layer.isBackground
);
// 设置最大宽高为背景图层的尺寸
const maxWidth = bgLayer?.canvasWidth || canvas.width;
const maxHeight = bgLayer?.canvasHeight || canvas.height;
// 加载并处理图片
const fabricImage = await loadImage(e.target.result, {
maxWidth: maxWidth * 0.8, // 默认图片最大宽度为背景宽度的80%
maxHeight: maxHeight * 0.8, // 默认图片最大高度为背景高度的80%
canvasWidth: canvas.width,
canvasHeight: canvas.height,
...options,
});
// 创建图片图层
const layerId = await createImageLayer({
layerManager,
fabricImage,
toolManager,
layerName: file.name,
});
resolve(layerId);
} catch (error) {
console.error("处理图片失败:", error);
reject(error);
}
};
reader.onerror = (error) => {
console.error("读取文件失败:", error);
reject(error);
};
reader.readAsDataURL(file);
});
}
/**
* 安全加载图片
* 添加错误处理和重试机制
* @param {string} imageSource - 图片URL或Base64字符串
* @param {Object} options - 配置选项
* @returns {Promise<Object>} - 返回图片对象的Promise
*/
export function safeLoadImage(imageSource, options = {}) {
return new Promise((resolve, reject) => {
let retries = options.retries || 1;
const attemptLoad = (attempt = 0) => {
loadImage(imageSource, options)
.then(resolve)
.catch((error) => {
if (attempt < retries) {
console.warn(
`图片加载失败,正在重试 (${attempt + 1}/${retries})...`
);
setTimeout(() => attemptLoad(attempt + 1), 500);
} else {
reject(error);
}
});
};
attemptLoad();
});
}
/**
* 从URL加载图片并更改固定图层
* @param {Object} options - 配置选项
* @param {string} options.imageUrl - 图片URL
* @param {Object} options.layerManager - 图层管理器
* @param {string} options.fixedLayerId - 固定图层ID
* @param {Object} options.imageOptions - 图片加载选项
* @returns {Promise<boolean>} 是否成功
*/
export function loadImageAndChangeFixedLayer({
imageUrl,
layerManager,
fixedLayerId,
imageOptions = {},
}) {
return new Promise((resolve, reject) => {
if (!imageUrl || !layerManager || !fixedLayerId) {
reject(new Error("参数无效"));
return;
}
loadImage(imageUrl, imageOptions)
.then(async (fabricImage) => {
try {
const result = await changeFixedImage({
layerManager,
fixedLayerId,
fabricImage,
});
resolve(result);
} catch (error) {
console.error("更改固定图层失败:", error);
reject(error);
}
})
.catch((error) => {
console.error("加载图片失败:", error);
reject(error);
});
});
}
/**
* 从File对象更改固定图层图像
* @param {Object} options - 配置选项
* @param {File} options.file - 图像文件对象
* @param {Object} options.layerManager - 图层管理器
* @param {string} options.layerId - 固定图层ID
* @param {Object} options.imageOptions - 图片加载选项
* @returns {Promise<string>} 新图像对象ID的Promise
*/
export function uploadImageAndChangeFixedLayer({
file,
layerManager,
layerId,
imageOptions = {},
}) {
return new Promise((resolve, reject) => {
if (!file || !layerManager || !layerId) {
reject(new Error("参数无效需要文件、图层管理器和图层ID"));
return;
}
// 验证文件类型
if (!file.type.startsWith("image/")) {
reject(new Error("无效的文件类型:必须是图像文件"));
return;
}
const reader = new FileReader();
reader.onload = async (e) => {
try {
// 查找目标固定图层以获取尺寸信息
const targetLayer = layerManager.layers.value.find(
(layer) => layer.id === layerId
);
if (!targetLayer) {
throw new Error(`找不到图层 ID: ${layerId}`);
}
// 验证是否为固定图层
if (!targetLayer.isFixed && !targetLayer.isBackground) {
throw new Error("只能更改固定图层或背景图层的图像");
}
// 查找背景图层以获取画布尺寸
const bgLayer = layerManager.layers.value.find(
(layer) => layer.isBackground
);
const maxWidth = bgLayer?.canvasWidth || layerManager.canvas.width;
const maxHeight = bgLayer?.canvasHeight || layerManager.canvas.height;
// 加载并处理图片
const fabricImage = await loadImage(e.target.result, {
maxWidth: maxWidth,
maxHeight: maxHeight,
canvasWidth: layerManager.canvas.width,
canvasHeight: layerManager.canvas.height,
centerOnCanvas: true,
...imageOptions,
});
// 创建更改固定图层图像命令
const changeFixedImageCmd = new ChangeFixedImageCommand({
canvas: layerManager.canvas,
layers: layerManager.layers,
layerId: layerId,
newImageFile: file,
layerManager: layerManager,
});
// 通过命令管理器执行
const newImageId = await layerManager.commandManager.execute(
changeFixedImageCmd
);
if (newImageId) {
console.log(
`✅ 成功更改固定图层 "${targetLayer.name}" 的图像新图像ID: ${newImageId}`
);
resolve(newImageId);
} else {
throw new Error("更改固定图层图像失败");
}
} catch (error) {
console.error("处理图片失败:", error);
reject(error);
}
};
reader.onerror = (error) => {
console.error("读取文件失败:", error);
reject(new Error("文件读取失败"));
};
reader.readAsDataURL(file);
});
}
/**
* 从File对象加载图片并添加到指定图层 (简化版)
* @param {Object} options - 配置选项
* @param {File} options.file - 文件对象
* @param {Object} options.layerManager - 图层管理器
* @param {Object} options.toolManager - 工具管理器
* @param {string} options.targetLayerId - 目标图层ID可选
* @param {Object} options.imageOptions - 图片加载选项
* @returns {Promise<Object>} 返回 { layerId, imageId, wasLayerCreated } 的Promise
*/
export function uploadImageAndAddToLayer({
file,
layerManager,
toolManager,
targetLayerId = null,
imageOptions = {},
}) {
return new Promise((resolve, reject) => {
if (!file || !layerManager) {
reject(new Error("参数无效:需要文件和图层管理器"));
return;
}
// 验证文件类型
if (!file.type.startsWith("image/")) {
reject(new Error("无效的文件类型:必须是图像文件"));
return;
}
// 创建添加图像到图层命令
const addImageToLayerCmd = new AddImageToLayerCommand({
canvas: layerManager.canvas,
layers: layerManager.layers,
activeLayerId: layerManager.activeLayerId,
imageFile: file,
targetLayerId: targetLayerId,
layerManager: layerManager,
toolManager: toolManager,
});
// 通过命令管理器执行
layerManager.commandManager
.execute(addImageToLayerCmd)
.then((result) => {
if (result) {
console.log(`✅ 成功添加图像到图层,结果:`, result);
resolve(result);
} else {
throw new Error("添加图像到图层失败");
}
})
.catch((error) => {
console.error("添加图像到图层失败:", error);
reject(error);
});
});
}
/**
* 从File对象加载图片并添加到指定图层 (简化版)
* @param {Object} options - 配置选项
* @param {File} options.file - 文件对象
* @param {Object} options.layerManager - 图层管理器
* @param {Object} options.toolManager - 工具管理器
* @param {string} options.targetLayerId - 目标图层ID可选
* @param {Object} options.imageOptions - 图片加载选项
* @returns {Promise<Object>} 返回 { layerId, imageId, wasLayerCreated } 的Promise
*/
export function uploadImageAndAddToLayerSimple({
file,
layerManager,
toolManager,
targetLayerId = null,
imageOptions = {},
}) {
return new Promise((resolve, reject) => {
if (!file || !layerManager) {
reject(new Error("参数无效:需要文件和图层管理器"));
return;
}
// 验证文件类型
if (!file.type.startsWith("image/")) {
reject(new Error("无效的文件类型:必须是图像文件"));
return;
}
// 创建添加图像到图层命令
const addImageToLayerCmd = new AddImageToLayerCommand({
canvas: layerManager.canvas,
layers: layerManager.layers,
activeLayerId: layerManager.activeLayerId,
imageFile: file,
targetLayerId: targetLayerId,
layerManager: layerManager,
toolManager: toolManager,
});
// 通过命令管理器执行
layerManager.commandManager
.execute(addImageToLayerCmd)
.then((result) => {
if (result) {
console.log(`✅ 成功添加图像到图层,结果:`, result);
resolve(result);
} else {
throw new Error("添加图像到图层失败");
}
})
.catch((error) => {
console.error("添加图像到图层失败:", error);
reject(error);
});
});
}
/**
* 批量上传图片并创建图层
* @param {Object} options - 配置选项
* @param {FileList|Array<File>} options.files - 文件列表
* @param {Object} options.layerManager - 图层管理器
* @param {Object} options.canvas - fabric.js画布实例
* @param {Object} options.toolManager - 工具管理器
* @param {Object} options.imageOptions - 图片加载选项
* @param {function} options.onProgress - 进度回调函数
* @returns {Promise<Array<string>>} 新图层ID数组的Promise
*/
export async function batchUploadImagesAndCreateLayers({
files,
layerManager,
canvas,
toolManager,
imageOptions = {},
onProgress = null,
}) {
if (!files || files.length === 0) {
throw new Error("没有提供文件");
}
if (!layerManager || !canvas) {
throw new Error("缺少必要的参数:图层管理器或画布");
}
const results = [];
const errors = [];
for (let i = 0; i < files.length; i++) {
const file = files[i];
try {
// 调用进度回调
if (typeof onProgress === "function") {
onProgress({
current: i + 1,
total: files.length,
fileName: file.name,
status: "processing",
});
}
// 验证文件类型
if (!file.type.startsWith("image/")) {
console.warn(`跳过非图像文件: ${file.name}`);
continue;
}
// 上传图片并创建图层
const layerId = await uploadImageAndCreateLayer(
{ file, layerManager, canvas, toolManager },
imageOptions
);
results.push({
fileName: file.name,
layerId: layerId,
success: true,
});
// 调用进度回调
if (typeof onProgress === "function") {
onProgress({
current: i + 1,
total: files.length,
fileName: file.name,
status: "success",
layerId: layerId,
});
}
console.log(`✅ 成功处理文件: ${file.name}, 图层ID: ${layerId}`);
} catch (error) {
console.error(`❌ 处理文件失败: ${file.name}`, error);
errors.push({
fileName: file.name,
error: error.message,
success: false,
});
// 调用进度回调
if (typeof onProgress === "function") {
onProgress({
current: i + 1,
total: files.length,
fileName: file.name,
status: "error",
error: error.message,
});
}
}
}
// 输出批量处理结果
console.log(`📊 批量处理完成:`);
console.log(` ✅ 成功: ${results.length} 个文件`);
console.log(` ❌ 失败: ${errors.length} 个文件`);
if (errors.length > 0) {
console.warn("失败的文件:", errors);
}
return {
results: results,
errors: errors,
successCount: results.length,
errorCount: errors.length,
total: files.length,
};
}
/**
* 高级图像管理工具
* 提供批量图像处理缓存预加载等高级功能
*/
export class AdvancedImageManager {
constructor(canvasManager) {
this.canvasManager = canvasManager;
this.canvas = canvasManager.canvas;
this.layerManager = canvasManager.layerManager;
// 图像缓存
this.imageCache = new Map();
this.preloadQueue = [];
this.maxCacheSize = 50; // 最大缓存数量
// 批量操作状态
this.batchOperations = [];
this.isBatchMode = false;
// 性能监控
this.performanceMetrics = {
imageLoads: 0,
cacheHits: 0,
totalLoadTime: 0,
averageLoadTime: 0,
};
}
/**
* 预加载图像列表
* @param {Array} imageUrls 要预加载的图像URL数组
* @param {Object} options 选项
*/
async preloadImages(imageUrls, options = {}) {
const {
concurrency = 3, // 并发数量
timeout = 10000,
onProgress = null,
onError = null,
} = options;
const loadPromises = [];
const results = [];
let completed = 0;
// 分批并发加载
for (let i = 0; i < imageUrls.length; i += concurrency) {
const batch = imageUrls.slice(i, i + concurrency);
const batchPromises = batch.map(async (url, index) => {
try {
const startTime = performance.now();
const image = await this.loadAndCacheImage(url, { timeout });
const loadTime = performance.now() - startTime;
// 更新性能指标
this.updatePerformanceMetrics(loadTime);
completed++;
onProgress?.({ completed, total: imageUrls.length, url });
return { success: true, url, image, loadTime };
} catch (error) {
completed++;
onError?.({ url, error, completed, total: imageUrls.length });
return { success: false, url, error: error.message };
}
});
const batchResults = await Promise.all(batchPromises);
results.push(...batchResults);
}
return {
results,
summary: {
total: imageUrls.length,
successful: results.filter((r) => r.success).length,
failed: results.filter((r) => !r.success).length,
cacheHitRate:
this.performanceMetrics.cacheHits /
this.performanceMetrics.imageLoads,
averageLoadTime: this.performanceMetrics.averageLoadTime,
},
};
}
/**
* 加载并缓存图像
* @param {String} url 图像URL
* @param {Object} options 选项
*/
async loadAndCacheImage(url, options = {}) {
// 检查缓存
if (this.imageCache.has(url)) {
this.performanceMetrics.cacheHits++;
return this.imageCache.get(url);
}
// 加载新图像
const image = await this.loadImage(url, options);
// 添加到缓存
this.addToCache(url, image);
return image;
}
/**
* 开始批量操作模式
*/
startBatch() {
this.isBatchMode = true;
this.batchOperations = [];
}
/**
* 批量更换多个固定图层的图像
* @param {Array} operations 操作数组 [{layerType, imageUrl, options}, ...]
*/
async batchChangeFixedImages(operations) {
const operationResults = [];
if (this.isBatchMode) {
// 如果在批量模式下,只收集操作
this.batchOperations.push(
...operations.map((op) => ({
type: "changeFixed",
...op,
}))
);
return { queued: operations.length };
}
// 立即执行模式
for (const operation of operations) {
try {
const result = await this.canvasManager.changeFixedImage(
operation.imageUrl,
{
targetLayerType: operation.layerType,
...operation.options,
}
);
operationResults.push({ success: true, ...result, operation });
} catch (error) {
operationResults.push({
success: false,
error: error.message,
operation,
});
}
}
return {
results: operationResults,
summary: this.getSummary(operationResults),
};
}
/**
* 批量向多个图层添加图像
* @param {Array} operations 操作数组 [{layerId, imageUrl, position, options}, ...]
*/
async batchAddImagesToLayers(operations) {
const operationResults = [];
if (this.isBatchMode) {
this.batchOperations.push(
...operations.map((op) => ({
type: "addToLayer",
...op,
}))
);
return { queued: operations.length };
}
// 并发执行以提高性能
const concurrentOperations = operations.map(async (operation) => {
try {
const result = await this.canvasManager.addImageToLayer(
operation.imageUrl,
operation.layerId,
{
position: operation.position,
...operation.options,
}
);
return { success: true, ...result, operation };
} catch (error) {
return {
success: false,
error: error.message,
operation,
};
}
});
const concurrentResults = await Promise.all(concurrentOperations);
return {
results: concurrentResults,
summary: this.getSummary(concurrentResults),
};
}
/**
* 执行批量操作
*/
async executeBatch() {
if (!this.isBatchMode || this.batchOperations.length === 0) {
return { message: "No batch operations to execute" };
}
const results = [];
const startTime = performance.now();
// 按类型分组操作以优化执行
const groupedOps = this.groupOperationsByType(this.batchOperations);
// 执行分组操作
for (const [type, ops] of Object.entries(groupedOps)) {
try {
let typeResults;
switch (type) {
case "changeFixed":
typeResults = await this.batchChangeFixedImages(ops);
break;
case "addToLayer":
typeResults = await this.batchAddImagesToLayers(ops);
break;
default:
console.warn(`Unknown operation type: ${type}`);
continue;
}
if (typeResults.results) {
results.push(...typeResults.results);
}
} catch (error) {
console.error(`Batch execution failed for type ${type}:`, error);
// 继续执行其他类型的操作
}
}
const executionTime = performance.now() - startTime;
// 清理批量状态
this.isBatchMode = false;
this.batchOperations = [];
return {
results,
summary: {
...this.getSummary(results),
executionTime,
operationsPerSecond: results.length / (executionTime / 1000),
},
};
}
/**
* 创建图像替换模板
* @param {String} templateName 模板名称
* @param {Array} operations 操作定义
*/
createTemplate(templateName, operations) {
if (!this.templates) {
this.templates = new Map();
}
this.templates.set(templateName, {
name: templateName,
operations,
createdAt: new Date(),
usageCount: 0,
});
}
/**
* 应用模板
* @param {String} templateName 模板名称
* @param {Object} variables 变量替换映射
*/
async applyTemplate(templateName, variables = {}) {
const template = this.templates?.get(templateName);
if (!template) {
throw new Error(`Template "${templateName}" not found`);
}
// 替换模板中的变量
const operations = this.replaceTemplateVariables(
template.operations,
variables
);
// 执行操作
const result = await this.batchAddImagesToLayers(operations);
// 更新使用计数
template.usageCount++;
return result;
}
/**
* 智能图像优化
* @param {String} imageUrl 图像URL
* @param {Object} targetSpecs 目标规格 {width, height, quality}
*/
async optimizeImage(imageUrl, targetSpecs) {
const image = await this.loadAndCacheImage(imageUrl);
// 检查是否需要优化
const currentSpecs = {
width: image.width,
height: image.height,
};
if (this.shouldOptimize(currentSpecs, targetSpecs)) {
return this.performImageOptimization(image, targetSpecs);
}
return image;
}
/**
* 清理缓存
* @param {String} strategy 清理策略 'lru', 'size', 'all'
*/
clearCache(strategy = "lru") {
switch (strategy) {
case "all":
this.imageCache.clear();
break;
case "size":
if (this.imageCache.size > this.maxCacheSize) {
const excess = this.imageCache.size - this.maxCacheSize;
const keys = Array.from(this.imageCache.keys());
for (let i = 0; i < excess; i++) {
this.imageCache.delete(keys[i]);
}
}
break;
case "lru":
// 实现 LRU 清理逻辑
this.implementLRUCleanup();
break;
}
}
// === 私有方法 ===
loadImage(url, options = {}) {
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
reject(new Error(`Image load timeout: ${url}`));
}, options.timeout || 10000);
fabric.Image.fromURL(
url,
(img) => {
clearTimeout(timeout);
if (!img || !img.getElement()) {
reject(new Error("Invalid image"));
return;
}
resolve(img);
},
{ crossOrigin: "anonymous" }
);
});
}
addToCache(url, image) {
// 检查缓存大小限制
if (this.imageCache.size >= this.maxCacheSize) {
this.clearCache("size");
}
// 添加时间戳用于 LRU
const cacheEntry = {
image,
lastUsed: Date.now(),
usageCount: 1,
};
this.imageCache.set(url, cacheEntry);
}
updatePerformanceMetrics(loadTime) {
this.performanceMetrics.imageLoads++;
this.performanceMetrics.totalLoadTime += loadTime;
this.performanceMetrics.averageLoadTime =
this.performanceMetrics.totalLoadTime /
this.performanceMetrics.imageLoads;
}
getSummary(results) {
return {
total: results.length,
successful: results.filter((r) => r.success).length,
failed: results.filter((r) => !r.success).length,
successRate: results.filter((r) => r.success).length / results.length,
};
}
groupOperationsByType(operations) {
return operations.reduce((groups, op) => {
const type = op.type;
if (!groups[type]) groups[type] = [];
groups[type].push(op);
return groups;
}, {});
}
replaceTemplateVariables(operations, variables) {
return operations.map((op) => {
const newOp = { ...op };
// 替换字符串中的变量 {{variable}}
Object.keys(newOp).forEach((key) => {
if (typeof newOp[key] === "string") {
newOp[key] = newOp[key].replace(
/\{\{(\w+)\}\}/g,
(match, varName) => {
return variables[varName] || match;
}
);
}
});
return newOp;
});
}
shouldOptimize(current, target) {
const sizeThreshold = 0.8; // 80% 的阈值
return (
current.width > target.width * (1 / sizeThreshold) ||
current.height > target.height * (1 / sizeThreshold)
);
}
performImageOptimization(image, targetSpecs) {
// 实现图像优化逻辑
// 这里可以集成图像压缩、尺寸调整等功能
return image; // 简化实现
}
implementLRUCleanup() {
if (this.imageCache.size <= this.maxCacheSize) return;
// 按最后使用时间排序,移除最久未使用的
const entries = Array.from(this.imageCache.entries()).sort(
(a, b) => a[1].lastUsed - b[1].lastUsed
);
const toRemove = entries.slice(0, this.imageCache.size - this.maxCacheSize);
toRemove.forEach(([key]) => this.imageCache.delete(key));
}
// 获取性能报告
getPerformanceReport() {
return {
...this.performanceMetrics,
cacheSize: this.imageCache.size,
maxCacheSize: this.maxCacheSize,
cacheUtilization: this.imageCache.size / this.maxCacheSize,
recommendations: this.generatePerformanceRecommendations(),
};
}
generatePerformanceRecommendations() {
const recommendations = [];
if (
this.performanceMetrics.cacheHits / this.performanceMetrics.imageLoads <
0.3
) {
recommendations.push("考虑增加缓存大小以提高缓存命中率");
}
if (this.performanceMetrics.averageLoadTime > 2000) {
recommendations.push("图像加载时间较长考虑图像优化或CDN");
}
return recommendations;
}
}
/**
* 图像工具集
* 提供常用的图像处理和图层操作功能
*/
export const ImageUtils = {
// 基础图像加载
loadImage,
safeLoadImage,
// 图层操作
createImageLayer,
changeFixedImage,
addImageToLayer,
// 文件上传处理
uploadImageAndCreateLayer,
uploadImageAndChangeFixedLayer,
uploadImageAndAddToLayer,
uploadImageAndAddToLayerSimple,
batchUploadImagesAndCreateLayers,
// URL图像处理
loadImageAndChangeFixedLayer,
/**
* 快速创建图像图层 (别名)
* @param {File} file - 图像文件
* @param {Object} layerManager - 图层管理器
* @param {Object} canvas - 画布实例
* @param {Object} toolManager - 工具管理器
* @returns {Promise<string>} 图层ID
*/
quickCreateImageLayer: (file, layerManager, canvas, toolManager) => {
return uploadImageAndCreateLayer({
file,
layerManager,
canvas,
toolManager,
});
},
/**
* 快速更改固定图层图像 (别名)
* @param {File} file - 图像文件
* @param {string} layerId - 图层ID
* @param {Object} layerManager - 图层管理器
* @returns {Promise<string>} 新图像ID
*/
quickChangeFixedImage: (file, layerId, layerManager) => {
return uploadImageAndChangeFixedLayer({ file, layerId, layerManager });
},
/**
* 快速添加图像到图层 (别名)
* @param {File} file - 图像文件
* @param {Object} layerManager - 图层管理器
* @param {Object} toolManager - 工具管理器
* @param {string} targetLayerId - 目标图层ID (可选)
* @returns {Promise<Object>} 执行结果
*/
quickAddImageToLayer: (
file,
layerManager,
toolManager,
targetLayerId = null
) => {
return uploadImageAndAddToLayerSimple({
file,
layerManager,
toolManager,
targetLayerId,
});
},
};