Files
aida_front/src/component/Canvas/CanvasEditor/managers/ExportManager.js

355 lines
9.9 KiB
JavaScript
Raw Normal View History

2025-06-09 10:25:54 +08:00
/**
* 图片导出管理器
* 负责处理画布的图片导出功能支持多种导出选项和图层过滤
*/
export class ExportManager {
constructor(canvasManager, layerManager) {
this.canvasManager = canvasManager;
this.layerManager = layerManager;
this.canvas = canvasManager.canvas;
}
/**
* 导出图片
* @param {Object} options 导出选项
* @param {Boolean} options.isContainBg 是否包含背景图层
* @param {Boolean} options.isContainFixed 是否包含固定图层
* @param {String} options.layerId 导出具体图层ID
* @param {Array} options.layerIdArray 导出多个图层ID数组
* @param {String} options.expPicType 导出图片类型 (png/jpg/svg)
* @returns {String} 导出的图片数据URL
*/
exportImage(options = {}) {
const {
isContainBg = false,
isContainFixed = false,
layerId = "",
layerIdArray = [],
expPicType = "png"
} = options;
try {
// 如果指定了具体图层ID导出指定图层
if (layerId) {
return this._exportSpecificLayer(layerId, expPicType);
}
// 如果指定了多个图层ID导出多个图层
if (layerIdArray && layerIdArray.length > 0) {
return this._exportMultipleLayers(layerIdArray, expPicType, isContainBg, isContainFixed);
}
// 默认导出所有可见图层
return this._exportAllLayers(expPicType, isContainBg, isContainFixed);
} catch (error) {
console.error("导出图片失败:", error);
throw new Error(`图片导出失败: ${error.message}`);
}
}
/**
* 导出指定单个图层
* @param {String} layerId 图层ID
* @param {String} expPicType 导出类型
* @returns {String} 图片数据URL
* @private
*/
_exportSpecificLayer(layerId, expPicType) {
if (!this.layerManager) {
throw new Error("图层管理器未初始化");
}
const layer = this._getLayerById(layerId);
if (!layer) {
throw new Error(`未找到ID为 ${layerId} 的图层`);
}
if (!layer.visible) {
console.warn(`图层 ${layer.name} 不可见,将导出空白图片`);
}
// 创建临时画布
const tempCanvas = this._createExportCanvas();
const tempFabricCanvas = this._createTempFabricCanvas(tempCanvas);
try {
// 只添加指定图层的对象
this._addLayerObjectsToCanvas(tempFabricCanvas, layer);
// 渲染并导出
tempFabricCanvas.renderAll();
return this._generateDataURL(tempCanvas, expPicType);
} finally {
this._cleanupTempCanvas(tempFabricCanvas);
}
}
/**
* 导出多个指定图层
* @param {Array} layerIdArray 图层ID数组
* @param {String} expPicType 导出类型
* @param {Boolean} isContainBg 是否包含背景图层
* @param {Boolean} isContainFixed 是否包含固定图层
* @returns {String} 图片数据URL
* @private
*/
_exportMultipleLayers(layerIdArray, expPicType, isContainBg, isContainFixed) {
if (!this.layerManager) {
throw new Error("图层管理器未初始化");
}
// 创建临时画布
const tempCanvas = this._createExportCanvas();
const tempFabricCanvas = this._createTempFabricCanvas(tempCanvas);
try {
// 按照图层顺序添加指定的图层
const allLayers = this._getAllLayers();
allLayers.forEach(layer => {
if (!layerIdArray.includes(layer.id)) return;
// 检查图层类型过滤条件
if (!this._shouldIncludeLayer(layer, isContainBg, isContainFixed)) return;
if (layer.visible) {
this._addLayerObjectsToCanvas(tempFabricCanvas, layer);
}
});
// 渲染并导出
tempFabricCanvas.renderAll();
return this._generateDataURL(tempCanvas, expPicType);
} finally {
this._cleanupTempCanvas(tempFabricCanvas);
}
}
/**
* 导出所有图层
* @param {String} expPicType 导出类型
* @param {Boolean} isContainBg 是否包含背景图层
* @param {Boolean} isContainFixed 是否包含固定图层
* @returns {String} 图片数据URL
* @private
*/
_exportAllLayers(expPicType, isContainBg, isContainFixed) {
// 创建临时画布
const tempCanvas = this._createExportCanvas();
const tempFabricCanvas = this._createTempFabricCanvas(tempCanvas);
try {
// 获取所有图层并按顺序添加
const allLayers = this._getAllLayers();
allLayers.forEach(layer => {
// 检查图层类型过滤条件
if (!this._shouldIncludeLayer(layer, isContainBg, isContainFixed)) return;
if (layer.visible) {
this._addLayerObjectsToCanvas(tempFabricCanvas, layer);
}
});
// 渲染并导出
tempFabricCanvas.renderAll();
return this._generateDataURL(tempCanvas, expPicType);
} finally {
this._cleanupTempCanvas(tempFabricCanvas);
}
}
/**
* 判断是否应该包含该图层
* @param {Object} layer 图层对象
* @param {Boolean} isContainBg 是否包含背景图层
* @param {Boolean} isContainFixed 是否包含固定图层
* @returns {Boolean} 是否包含
* @private
*/
_shouldIncludeLayer(layer, isContainBg, isContainFixed) {
// 背景图层处理
if (layer.type === 'background' || layer.isBackground) {
return isContainBg;
}
// 固定图层处理
if (layer.type === 'fixed' || layer.isFixed || layer.locked) {
return isContainFixed;
}
// 其他图层默认包含
return true;
}
/**
* 创建导出用的临时画布
* @returns {HTMLCanvasElement} 临时画布
* @private
*/
_createExportCanvas() {
const tempCanvas = document.createElement("canvas");
tempCanvas.width = this.canvas.width || 800;
tempCanvas.height = this.canvas.height || 600;
return tempCanvas;
}
/**
* 创建临时Fabric画布
* @param {HTMLCanvasElement} tempCanvas 临时画布元素
* @returns {fabric.StaticCanvas} 临时Fabric画布
* @private
*/
_createTempFabricCanvas(tempCanvas) {
const { fabric } = window;
const tempFabricCanvas = new fabric.StaticCanvas(tempCanvas, {
width: this.canvas.width || 800,
height: this.canvas.height || 600,
backgroundColor: this.canvas.backgroundColor || 'transparent'
});
// 设置高质量渲染选项
tempFabricCanvas.enableRetinaScaling = true;
tempFabricCanvas.imageSmoothingEnabled = true;
return tempFabricCanvas;
}
/**
* 将图层对象添加到临时画布
* @param {fabric.StaticCanvas} tempCanvas 临时画布
* @param {Object} layer 图层对象
* @private
*/
_addLayerObjectsToCanvas(tempCanvas, layer) {
if (!layer) return;
// 处理背景图层
if (layer.type === 'background' && layer.fabricObject) {
this._cloneAndAddObject(tempCanvas, layer.fabricObject);
return;
}
// 处理普通图层的对象
if (layer.fabricObjects && Array.isArray(layer.fabricObjects)) {
layer.fabricObjects.forEach(obj => {
if (obj && obj.visible !== false) {
this._cloneAndAddObject(tempCanvas, obj);
}
});
}
// 处理单个fabricObject的情况
if (layer.fabricObject && !layer.fabricObjects) {
this._cloneAndAddObject(tempCanvas, layer.fabricObject);
}
// 处理分组图层的子图层
if (layer.children && Array.isArray(layer.children)) {
layer.children.forEach(childLayerId => {
const childLayer = this._getLayerById(childLayerId);
if (childLayer && childLayer.visible) {
this._addLayerObjectsToCanvas(tempCanvas, childLayer);
}
});
}
}
/**
* 克隆并添加对象到临时画布
* @param {fabric.StaticCanvas} tempCanvas 临时画布
* @param {fabric.Object} obj Fabric对象
* @private
*/
_cloneAndAddObject(tempCanvas, obj) {
if (!obj) return;
try {
obj.clone((cloned) => {
if (cloned) {
// 确保克隆对象的属性正确
cloned.set({
selectable: false,
evented: false,
visible: true
});
tempCanvas.add(cloned);
}
}, ['id', 'layerId', 'name']); // 保留自定义属性
} catch (error) {
console.warn("克隆对象失败:", error);
}
}
/**
* 生成数据URL
* @param {HTMLCanvasElement} canvas 画布元素
* @param {String} expPicType 导出类型
* @returns {String} 数据URL
* @private
*/
_generateDataURL(canvas, expPicType) {
const format = expPicType.toLowerCase();
switch (format) {
case 'jpg':
case 'jpeg':
return canvas.toDataURL('image/jpeg', 0.9);
case 'svg':
// SVG导出需要特殊处理这里先返回PNG
console.warn("SVG导出暂未实现返回PNG格式");
return canvas.toDataURL('image/png', 1.0);
case 'png':
default:
return canvas.toDataURL('image/png', 1.0);
}
}
/**
* 清理临时画布资源
* @param {fabric.StaticCanvas} tempFabricCanvas 临时Fabric画布
* @private
*/
_cleanupTempCanvas(tempFabricCanvas) {
if (tempFabricCanvas) {
try {
tempFabricCanvas.dispose();
} catch (error) {
console.warn("清理临时画布失败:", error);
}
}
}
/**
* 获取所有图层
* @returns {Array} 图层数组
* @private
*/
_getAllLayers() {
if (this.layerManager && this.layerManager.layers) {
return this.layerManager.layers.value || [];
}
return [];
}
/**
* 根据ID获取图层
* @param {String} layerId 图层ID
* @returns {Object|null} 图层对象
* @private
*/
_getLayerById(layerId) {
if (this.layerManager && this.layerManager.getLayerById) {
return this.layerManager.getLayerById(layerId);
}
// 备用方法:直接从图层数组中查找
const allLayers = this._getAllLayers();
return allLayers.find(layer => layer.id === layerId) || null;
}
}