导出图片添加印花平铺判断
This commit is contained in:
31
src/assets/icons/CPoint.svg
Normal file
31
src/assets/icons/CPoint.svg
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="96.000000pt" height="96.000000pt" viewBox="0 0 96.000000 96.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
|
||||
<g transform="translate(0.000000,96.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M346 936 c-21 -13 -49 -41 -62 -62 -41 -67 -27 -180 27 -218 47 -32
|
||||
53 -12 12 40 -71 94 -2 229 116 229 37 0 58 -7 87 -28 32 -22 40 -24 42 -12
|
||||
14 64 -142 100 -222 51z"/>
|
||||
<path d="M368 877 c-33 -28 -48 -57 -48 -96 0 -39 9 -61 26 -61 10 0 14 13 14
|
||||
46 0 57 12 79 50 93 61 21 110 -22 110 -96 0 -48 14 -56 31 -19 31 67 -35 156
|
||||
-114 156 -29 0 -50 -7 -69 -23z"/>
|
||||
<path d="M580 794 c0 -58 -9 -84 -43 -121 -19 -21 -19 -23 -2 -29 34 -13 85
|
||||
75 85 148 0 37 -10 58 -26 58 -10 0 -14 -15 -14 -56z"/>
|
||||
<path d="M410 749 c-13 -6 -28 -15 -32 -22 -4 -7 -8 -106 -8 -222 l-1 -210
|
||||
-27 34 c-62 80 -89 101 -126 101 -27 0 -39 -6 -52 -25 -15 -24 -15 -28 0 -68
|
||||
21 -53 78 -123 94 -113 18 11 16 17 -28 75 -44 58 -48 72 -25 91 21 18 54 -6
|
||||
93 -68 31 -47 74 -78 93 -67 5 4 9 101 9 224 0 225 3 241 42 241 10 0 19 -1
|
||||
19 -2 1 -2 5 -86 8 -188 5 -165 8 -185 24 -188 15 -3 17 5 17 61 0 72 17 100
|
||||
45 77 10 -9 15 -32 15 -77 0 -56 2 -64 18 -61 12 2 16 11 14 34 -5 48 14 86
|
||||
41 82 20 -3 22 -9 25 -66 3 -53 6 -63 20 -60 12 2 19 16 22 43 4 32 10 41 27
|
||||
43 36 5 46 -36 39 -166 -6 -127 -19 -160 -75 -195 -48 -29 -176 -34 -246 -10
|
||||
-48 18 -56 25 -130 128 -16 22 -25 26 -37 19 -15 -8 -11 -18 31 -75 78 -105
|
||||
94 -113 236 -117 119 -3 121 -3 167 27 69 44 82 74 86 214 6 179 -8 221 -72
|
||||
216 -22 -2 -39 4 -55 20 -17 17 -32 22 -55 19 -19 -2 -38 2 -45 9 -6 7 -25 13
|
||||
-40 13 l-29 0 -4 100 c-3 103 -11 122 -53 133 -11 3 -31 1 -45 -4z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -872,13 +872,13 @@ export class ToggleChildLayerVisibilityCommand extends Command {
|
||||
// this.oldVisibility = this.childLayer ? this.childLayer.visible : null;
|
||||
}
|
||||
|
||||
async execute() {
|
||||
async execute(visible) {
|
||||
if (!this.childLayer) {
|
||||
throw new Error("找不到要切换可见性的子图层");
|
||||
}
|
||||
|
||||
// 切换可见性
|
||||
this.childLayer.visible = !this.childLayer.visible;
|
||||
this.childLayer.visible = typeof visible === "boolean" ? visible : !this.childLayer.visible;
|
||||
|
||||
// 更新画布上图层对象的可见性
|
||||
if (this.canvas) {
|
||||
|
||||
@@ -287,7 +287,7 @@ const canDeleteComputed = computed(() => {
|
||||
:is-child="isChild"
|
||||
:is-active="layer.id === activeLayerId"
|
||||
:is-selected="isLayerSelected(layer.id)"
|
||||
:is-multi-select-mode="isMultiSelectMode && !layer.specialType"
|
||||
:is-multi-select-mode="isMultiSelectMode && !(layer.isPrintTrims || layer.isPrintTrimsGroup)"
|
||||
:is-editing="editingLayerId === layer.id"
|
||||
:editing-name="editingLayerName"
|
||||
:can-delete="
|
||||
@@ -296,7 +296,7 @@ const canDeleteComputed = computed(() => {
|
||||
:expanded-group-ids="expandedGroupIds"
|
||||
@click="(...args) => forwardEvent('layer-click', ...args)"
|
||||
@double-click="(...args) => forwardEvent('layer-double-click', ...args)"
|
||||
@context-menu="(...args) => !layer.specialType && forwardEvent('context-menu', ...args)"
|
||||
@context-menu="(...args) => !(layer.isPrintTrims || layer.isPrintTrimsGroup) && forwardEvent('context-menu', ...args)"
|
||||
@checkbox-change="(...args) => forwardEvent('checkbox-change', ...args)"
|
||||
@toggle-visibility="(...args) => forwardEvent('toggle-visibility', ...args)"
|
||||
@toggle-lock="(...args) => forwardEvent('toggle-lock', ...args)"
|
||||
@@ -337,7 +337,7 @@ const canDeleteComputed = computed(() => {
|
||||
:expanded-group-ids="expandedGroupIds"
|
||||
:isChild="true"
|
||||
:parentLayerId="layer.id"
|
||||
:group-name="layer.specialType || groupName"
|
||||
:group-name="groupName"
|
||||
@layer-click="(...args) => forwardEvent('layer-click', ...args)"
|
||||
@layer-double-click="(...args) => forwardEvent('layer-double-click', ...args)"
|
||||
@context-menu="(...args) => forwardEvent('context-menu', ...args)"
|
||||
|
||||
@@ -1242,7 +1242,7 @@ async function handleCrossLevelMove(moveData) {
|
||||
try {
|
||||
const layer = findLayerRecursively(layers.value, layerId).layer;
|
||||
const toLayer = findLayerRecursively(layers.value, toParentId).layer;
|
||||
if(layer?.specialType || toLayer?.specialType) {
|
||||
if(layer?.isPrintTrims || layer?.isPrintTrimsGroup || toLayer?.isPrintTrims || toLayer?.isPrintTrimsGroup) {
|
||||
console.warn("当前图层不可移动到外部");
|
||||
return;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -178,11 +178,7 @@
|
||||
import { ref, onMounted, watch, onUnmounted, reactive } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
const { t } = useI18n();
|
||||
import {
|
||||
OperationType,
|
||||
SpecialLayerId,
|
||||
SpecialType,
|
||||
} from "../../utils/layerHelper";
|
||||
import { OperationType, SpecialLayerId } from "../../utils/layerHelper";
|
||||
import { loadImageUrlToLayer } from "../../utils/imageHelper";
|
||||
import {
|
||||
calculateRotatedTopLeftDeg,
|
||||
@@ -283,9 +279,6 @@
|
||||
const getActiveObject = (e) => {
|
||||
console.log("==========切换激活对象", e, activeObjects);
|
||||
activeObjects.value = [...e.selected];
|
||||
// .filter((v) =>
|
||||
// v.specialType ? v.specialType === SpecialType.REPEAT_O : true
|
||||
// );// 过滤出印花对象
|
||||
activeObjects.value.forEach((v) => {
|
||||
v.layer = props.layerManager.getLayerById(v.layerId);
|
||||
});
|
||||
@@ -783,7 +776,7 @@
|
||||
}
|
||||
> .list {
|
||||
display: flex;
|
||||
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -166,19 +166,19 @@ const normalToolsList = ref([
|
||||
icon: { name: "CFont", size: "20" },
|
||||
class: "text-btn",
|
||||
},
|
||||
{
|
||||
id: OperationType.PART,
|
||||
title: t("Canvas.GarmentPartSelector"),
|
||||
action: () => selectTool(OperationType.PART),
|
||||
icon: { name: "CPart", size: "28" },
|
||||
class: "part-btn",
|
||||
activeList: [
|
||||
OperationType.PART,
|
||||
OperationType.PART_RECTANGLE,
|
||||
OperationType.PART_BRUSH,
|
||||
OperationType.PART_ERASER,
|
||||
],
|
||||
},
|
||||
// {
|
||||
// id: OperationType.PART,
|
||||
// title: t("Canvas.GarmentPartSelector"),
|
||||
// action: () => selectTool(OperationType.PART),
|
||||
// icon: { name: "CPart", size: "28" },
|
||||
// class: "part-btn",
|
||||
// activeList: [
|
||||
// OperationType.PART,
|
||||
// OperationType.PART_RECTANGLE,
|
||||
// OperationType.PART_BRUSH,
|
||||
// OperationType.PART_ERASER,
|
||||
// ],
|
||||
// },
|
||||
{
|
||||
id: "help",
|
||||
title: t("Canvas.help"),
|
||||
|
||||
@@ -1000,6 +1000,8 @@ defineExpose({
|
||||
isContainBg = false, // 是否包含背景图层
|
||||
isContainFixed = false, // 是否包含固定图层
|
||||
isContainFixedOther = false, // 是否包含其他固定图层
|
||||
isPrintTrimsNoRepeat = true, // 是否包含印花图层的不平铺
|
||||
isPrintTrimsRepeat = true, // 是否包含印花图层的平铺
|
||||
isCropByBg = false, // 是否使用背景大小裁剪 // 如果为true,则导出时裁剪到背景图层大小
|
||||
layerId = "", // 导出具体图层ID
|
||||
layerIdArray = [], // 导出多个图层ID数组
|
||||
@@ -1010,6 +1012,8 @@ defineExpose({
|
||||
isContainBg,
|
||||
isContainFixed,
|
||||
isContainFixedOther,
|
||||
isPrintTrimsNoRepeat,
|
||||
isPrintTrimsRepeat,
|
||||
isCropByBg,
|
||||
layerId,
|
||||
layerIdArray,
|
||||
@@ -1250,7 +1254,7 @@ defineExpose({
|
||||
/>
|
||||
|
||||
<!-- 部件选取面板 -->
|
||||
<PartSelectorPanel
|
||||
<!-- <PartSelectorPanel
|
||||
v-if="canvasManagerLoaded && !enabledRedGreenMode"
|
||||
:canvas="canvasManager && canvasManager.canvas"
|
||||
:commandManager="commandManager"
|
||||
@@ -1259,7 +1263,7 @@ defineExpose({
|
||||
:canvasManager="canvasManager"
|
||||
:toolManager="toolManager"
|
||||
:activeTool="activeTool"
|
||||
/>
|
||||
/> -->
|
||||
|
||||
<!-- 文本编辑面板 -->
|
||||
<TextEditorPanel
|
||||
@@ -1414,6 +1418,7 @@ defineExpose({
|
||||
/* background-color: #f8f8f8; */
|
||||
:deep(.canvas-container) {
|
||||
position: absolute !important;
|
||||
filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1426,33 +1431,31 @@ defineExpose({
|
||||
}
|
||||
|
||||
.background-grid {
|
||||
--offsetX: 0px;
|
||||
--offsetY: 0px;
|
||||
--size: 8px;
|
||||
--color: #dedcdc;
|
||||
--offsetX: 50%;
|
||||
--offsetY: 50%;
|
||||
--size: 10px;
|
||||
--color: rgba(229, 229,229,0.5);
|
||||
background-image: -webkit-linear-gradient(
|
||||
45deg,
|
||||
var(--color) 25%,
|
||||
90deg,
|
||||
var(--color) 1px,
|
||||
transparent 0,
|
||||
transparent 75%,
|
||||
var(--color) 0
|
||||
),
|
||||
-webkit-linear-gradient(45deg, var(--color) 25%, transparent 0, transparent
|
||||
75%, var(--color) 0);
|
||||
background-image: linear-gradient(
|
||||
45deg,
|
||||
var(--color) 25%,
|
||||
-webkit-linear-gradient(
|
||||
0,
|
||||
var(--color) 1px,
|
||||
transparent 0,
|
||||
);
|
||||
background-image:linear-gradient(
|
||||
90deg,
|
||||
var(--color) 1px,
|
||||
transparent 0,
|
||||
transparent 75%,
|
||||
var(--color) 0
|
||||
),
|
||||
linear-gradient(
|
||||
45deg,
|
||||
var(--color) 25%,
|
||||
0,
|
||||
var(--color) 1px,
|
||||
transparent 0,
|
||||
transparent 75%,
|
||||
var(--color) 0
|
||||
);
|
||||
background-color: #fafafa;
|
||||
background-position: var(--offsetX) var(--offsetY),
|
||||
calc(var(--size) + var(--offsetX)) calc(var(--size) + var(--offsetY));
|
||||
background-size: calc(var(--size) * 2) calc(var(--size) * 2);
|
||||
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
createLayer,
|
||||
LayerType,
|
||||
SpecialLayerId,
|
||||
SpecialType,
|
||||
BlendMode,
|
||||
} from "../utils/layerHelper";
|
||||
import { ObjectMoveCommand } from "../commands/ObjectCommands";
|
||||
@@ -45,7 +44,7 @@ import {
|
||||
} from "../utils/layerUtils";
|
||||
import { imageModeHandler } from "../utils/imageHelper";
|
||||
import { getObjectAlphaToCanvas } from "../utils/objectHelper";
|
||||
import { AddLayerCommand, RemoveLayerCommand } from "../commands/LayerCommands";
|
||||
import { AddLayerCommand, RemoveLayerCommand, ToggleChildLayerVisibilityCommand } from "../commands/LayerCommands";
|
||||
import { fa, id } from "element-plus/es/locales.mjs";
|
||||
import i18n from "@/lang/index.ts";
|
||||
const {t} = i18n.global;
|
||||
@@ -717,6 +716,8 @@ export class CanvasManager {
|
||||
originX: backgroundLayerObject.originX || "left",
|
||||
originY: backgroundLayerObject.originY || "top",
|
||||
absolutePositioned: true,
|
||||
rx: 15,
|
||||
ry: 15,
|
||||
});
|
||||
}
|
||||
getBackgroundLayer() {
|
||||
@@ -827,7 +828,7 @@ export class CanvasManager {
|
||||
updateMaskPosition(backgroundLayerObject) {
|
||||
if (!backgroundLayerObject || !this.maskLayer || !this.canvas.clipPath)
|
||||
return;
|
||||
|
||||
console.log("backgroundLayerObject");
|
||||
const left = backgroundLayerObject.left;
|
||||
const top = backgroundLayerObject.top;
|
||||
|
||||
@@ -922,6 +923,8 @@ export class CanvasManager {
|
||||
* @param {Boolean} options.isContainBg 是否包含背景图层
|
||||
* @param {Boolean} options.isContainFixed 是否包含固定图层
|
||||
* @param {Boolean} options.isContainFixedOther 是否包含其他固定图层
|
||||
* @param {Boolean} options.isPrintTrimsNoRepeat 是否包含印花图层的不平铺
|
||||
* @param {Boolean} options.isPrintTrimsRepeat 是否包含印花图层的平铺
|
||||
* @param {String} options.layerId 导出具体图层ID
|
||||
* @param {Array} options.layerIdArray 导出多个图层ID数组
|
||||
* @param {String} options.expPicType 导出图片类型 (png/jpg/svg)
|
||||
@@ -942,6 +945,8 @@ export class CanvasManager {
|
||||
// this.canvas.renderAll(); // 重新渲染画布
|
||||
// 自动设置红绿图模式相关参数
|
||||
const enhancedOptions = {
|
||||
isPrintTrimsNoRepeat: true,
|
||||
isPrintTrimsRepeat: true,
|
||||
...options,
|
||||
// 如果没有明确指定,则根据当前模式自动设置
|
||||
restoreOpacityInRedGreen:
|
||||
@@ -972,7 +977,46 @@ export class CanvasManager {
|
||||
console.log("红绿图模式导出图层:", normalLayerIds);
|
||||
}
|
||||
}
|
||||
return await this.exportManager.exportImage(enhancedOptions);
|
||||
|
||||
// 处理特殊图层的显示状态
|
||||
const ptlids = [];
|
||||
if(!enhancedOptions.isPrintTrimsNoRepeat || !enhancedOptions.isPrintTrimsRepeat){
|
||||
let layers = this.layers?.value?.find((layer) => layer.isPrintTrimsGroup)?.children || [];
|
||||
for(let layer of layers){
|
||||
if(!layer.visible) continue;
|
||||
let repeat = layer.fabricObjects?.[0]?.fill?.repeat || "no-repeat";
|
||||
if(typeof repeat !== "string") repeat = "no-repeat";
|
||||
if(repeat === "no-repeat"){
|
||||
if(enhancedOptions.isPrintTrimsNoRepeat) continue;
|
||||
}else{
|
||||
if(enhancedOptions.isPrintTrimsRepeat) continue;
|
||||
}
|
||||
ptlids.push(layer.id);
|
||||
const command = new ToggleChildLayerVisibilityCommand({
|
||||
canvas: this.canvas,
|
||||
layers: this.layers,
|
||||
layerId: layer.id,
|
||||
layerManager: this.layerManager,
|
||||
});
|
||||
await command.execute(false);
|
||||
}
|
||||
await this.changeCanvas();
|
||||
}
|
||||
const res = await this.exportManager.exportImage(enhancedOptions);
|
||||
// 恢复特殊图层的显示状态
|
||||
if(ptlids.length > 0){
|
||||
for(let id of ptlids){
|
||||
const command = new ToggleChildLayerVisibilityCommand({
|
||||
canvas: this.canvas,
|
||||
layers: this.layers,
|
||||
layerId: id,
|
||||
layerManager: this.layerManager,
|
||||
});
|
||||
await command.execute(true);
|
||||
}
|
||||
await this.changeCanvas();
|
||||
}
|
||||
return res;
|
||||
} catch (error) {
|
||||
console.warn("CanvasManager导出图片失败:", error);
|
||||
throw error;
|
||||
@@ -1533,7 +1577,7 @@ export class CanvasManager {
|
||||
selectable: true,
|
||||
hasControls: true,
|
||||
hasBorders: true,
|
||||
specialType: SpecialType.PRINT_TRIMS_O,
|
||||
isPrintTrims: true,
|
||||
globalCompositeOperation: BlendMode.MULTIPLY,
|
||||
});
|
||||
resolve(fabricImage);
|
||||
@@ -1547,7 +1591,7 @@ export class CanvasManager {
|
||||
visible: true,
|
||||
locked: false,
|
||||
opacity: 1.0,
|
||||
specialType: SpecialType.PRINT_TRIMS_L,
|
||||
isPrintTrims: true,
|
||||
blendMode: BlendMode.MULTIPLY,
|
||||
fabricObjects: [image.toObject(["id", "layerId", "layerName"])],
|
||||
metadata: {sourceData: item},
|
||||
@@ -1601,7 +1645,7 @@ export class CanvasManager {
|
||||
width: image.width,
|
||||
height: image.height,
|
||||
},
|
||||
specialType: SpecialType.REPEAT_O,
|
||||
isPrintTrims: true,
|
||||
});
|
||||
this.canvas.add(rect);
|
||||
let layer = createLayer({
|
||||
@@ -1611,7 +1655,7 @@ export class CanvasManager {
|
||||
visible: true,
|
||||
locked: true,
|
||||
opacity: 1,
|
||||
specialType: SpecialType.REPEAT_L,
|
||||
isPrintTrims: true,
|
||||
blendMode: BlendMode.MULTIPLY,
|
||||
fabricObjects: [rect.toObject(["id", "layerId", "layerName"])],
|
||||
metadata: {sourceData: item},
|
||||
@@ -1630,7 +1674,7 @@ export class CanvasManager {
|
||||
// })
|
||||
// children.push(layer);
|
||||
// }
|
||||
// if(children.length === 0) return;
|
||||
if(children.length === 0) return;
|
||||
const groupRect = new fabric.Rect({});
|
||||
await this.setObjecCliptInfo(groupRect);
|
||||
// 插入组图层
|
||||
@@ -1646,11 +1690,8 @@ export class CanvasManager {
|
||||
children: children,
|
||||
clippingMask: groupRect.toObject(),
|
||||
isPrintTrimsGroup: true,
|
||||
specialType: SpecialType.PRINT_TRIMS_G,
|
||||
});
|
||||
this.layers.value.splice(groupIndex, 0, groupLayer);
|
||||
console.log("==========layers", [...this.layers.value]);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -502,7 +502,6 @@ export class ToolManager {
|
||||
if (!this.canvas) return;
|
||||
this.canvas.isDrawingMode = false;
|
||||
this.canvas.selection = true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -511,7 +510,7 @@ export class ToolManager {
|
||||
*/
|
||||
checkToolCanOperateSelectedObject() {
|
||||
const layer = this.layerManager?.getActiveLayer();
|
||||
const isSpecialLayer = !!layer?.specialType;
|
||||
const isSpecialLayer = !!layer?.isPrintTrims || !!layer?.isPrintTrimsGroup;
|
||||
if (isSpecialLayer) {
|
||||
this._disableBrushIndicator();
|
||||
this.canvas.defaultCursor = "not-allowed";
|
||||
|
||||
@@ -25,18 +25,6 @@ export const SpecialLayerId = {
|
||||
SPECIAL_GROUP: "group_special", // 特殊组
|
||||
COLOR: "special_color", // 颜色图层
|
||||
}
|
||||
/**
|
||||
* 特殊类型
|
||||
*/
|
||||
export const SpecialType = {
|
||||
PRINT_TRIMS_G: "print_trims_group", // 印花和元素图层组
|
||||
PRINT_TRIMS_L: "print_trims_layer", // 印花和元素图层
|
||||
PRINT_TRIMS_O: "print_trims_object", // 印花和元素图层对象
|
||||
REPEAT_L: "repeat_layer",// 平铺图层
|
||||
REPEAT_O: "repeat_object",// 平铺图层对象
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -335,20 +335,20 @@ const otherData = {
|
||||
color: {rgba: {r:255,g:0,b:0,a:1}},
|
||||
printObject: {
|
||||
prints: [
|
||||
// {
|
||||
// ifSingle: false,
|
||||
// level2Type: "Pattern",
|
||||
// designType: "Library",
|
||||
// path: "/src/assets/images/canvas/yinhua1.jpg",
|
||||
// location: [250, 780],
|
||||
// scale: [0.3, 0.4],
|
||||
// angle: 0,
|
||||
// },
|
||||
{
|
||||
ifSingle: false,
|
||||
level2Type: "Pattern",
|
||||
designType: "Library",
|
||||
path: "/src/assets/images/canvas/yinhua1.jpg",
|
||||
location: [250, 780],
|
||||
scale: [0.3, 0.4],
|
||||
angle: 0,
|
||||
},
|
||||
{
|
||||
ifSingle: true,
|
||||
level2Type: "Pattern",
|
||||
designType: "Library",
|
||||
path: "/src/assets/images/canvas/yinhua1.jpg",
|
||||
location: [550, 650],
|
||||
scale: [0.15, 0.2],
|
||||
angle: 0,
|
||||
|
||||
Reference in New Issue
Block a user