Files
aida_front/src/component/Canvas/CanvasEditor/managers/ExportManager.js
X1627315083 c266967f16 接入画布
2025-06-09 10:25:54 +08:00

355 lines
9.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 图片导出管理器
* 负责处理画布的图片导出功能,支持多种导出选项和图层过滤
*/
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;
}
}