fix: anchor PSD replacements to clip targets
This commit is contained in:
parent
c247093ec9
commit
87be5499d5
@ -1498,6 +1498,7 @@ function renderTextLayerPreviewContent(
|
|||||||
|
|
||||||
function getAssignedImageMaskStyle(
|
function getAssignedImageMaskStyle(
|
||||||
layer: AgentPsdTemplateImageLayerSlot,
|
layer: AgentPsdTemplateImageLayerSlot,
|
||||||
|
frameLayer: AgentPsdTemplateLayerSlot,
|
||||||
layers: AgentPsdTemplateLayerSlot[]
|
layers: AgentPsdTemplateLayerSlot[]
|
||||||
): CSSProperties {
|
): CSSProperties {
|
||||||
const clipMaskLayer = layer.clipMaskLayerId
|
const clipMaskLayer = layer.clipMaskLayerId
|
||||||
@ -1512,7 +1513,7 @@ function getAssignedImageMaskStyle(
|
|||||||
).trim();
|
).trim();
|
||||||
const hasMask = Boolean(normalizedMaskUrl);
|
const hasMask = Boolean(normalizedMaskUrl);
|
||||||
const maskImageUrl = hasMask
|
const maskImageUrl = hasMask
|
||||||
? `url(${buildPsdLayerMaskUrl(normalizedMaskUrl, layer.width)})`
|
? `url(${buildPsdLayerMaskUrl(normalizedMaskUrl, frameLayer.width)})`
|
||||||
: undefined;
|
: undefined;
|
||||||
return {
|
return {
|
||||||
WebkitMaskImage: maskImageUrl,
|
WebkitMaskImage: maskImageUrl,
|
||||||
@ -1529,18 +1530,22 @@ function getAssignedImageMaskStyle(
|
|||||||
|
|
||||||
function getPlacedAssignedImageStyle(params: {
|
function getPlacedAssignedImageStyle(params: {
|
||||||
layer: AgentPsdTemplateImageLayerSlot;
|
layer: AgentPsdTemplateImageLayerSlot;
|
||||||
|
frameLayer?: AgentPsdTemplateLayerSlot | null;
|
||||||
imageSize: AgentPsdImageSize;
|
imageSize: AgentPsdImageSize;
|
||||||
placement: AgentPsdImagePlacement;
|
placement: AgentPsdImagePlacement;
|
||||||
}): CSSProperties {
|
}): CSSProperties {
|
||||||
const { layer, imageSize, placement } = params;
|
const { layer, imageSize, placement } = params;
|
||||||
|
const frameLayer = params.frameLayer || layer;
|
||||||
const normalizedPlacement = normalizeAgentPsdImagePlacement(placement);
|
const normalizedPlacement = normalizeAgentPsdImagePlacement(placement);
|
||||||
|
const frameContentBounds =
|
||||||
|
isAgentPsdImageLayerSlot(frameLayer) ? frameLayer.contentBounds : undefined;
|
||||||
const baseFrame = resolveAgentPsdImageBaseFrame({
|
const baseFrame = resolveAgentPsdImageBaseFrame({
|
||||||
containerWidth: layer.width,
|
containerWidth: frameLayer.width,
|
||||||
containerHeight: layer.height,
|
containerHeight: frameLayer.height,
|
||||||
imageWidth: imageSize.width,
|
imageWidth: imageSize.width,
|
||||||
imageHeight: imageSize.height,
|
imageHeight: imageSize.height,
|
||||||
replaceMode: layer.replaceMode,
|
replaceMode: layer.replaceMode,
|
||||||
contentBounds: layer.contentBounds,
|
contentBounds: frameContentBounds,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -1558,6 +1563,17 @@ function getPlacedAssignedImageStyle(params: {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getAssignedImageFrameLayer(
|
||||||
|
layer: AgentPsdTemplateImageLayerSlot,
|
||||||
|
layers: AgentPsdTemplateLayerSlot[]
|
||||||
|
) {
|
||||||
|
if (!layer.forceClipMask || !layer.clipMaskLayerId) {
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
return layers.find((item) => item.id === layer.clipMaskLayerId) || layer;
|
||||||
|
}
|
||||||
|
|
||||||
function hasEditedTextValue(
|
function hasEditedTextValue(
|
||||||
layer: AgentPsdTemplateTextLayerSlot,
|
layer: AgentPsdTemplateTextLayerSlot,
|
||||||
value: string
|
value: string
|
||||||
@ -3432,15 +3448,18 @@ export function AgentPsdTemplateEditorDialog({
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
setSelectedLayerId(layer.id);
|
setSelectedLayerId(layer.id);
|
||||||
|
const shouldDragAssignedImageContent =
|
||||||
|
isAgentPsdImageLayerSlot(layer) &&
|
||||||
|
Boolean(String(effectiveImageAssignments[layer.id] || "").trim());
|
||||||
|
|
||||||
layerDragStateRef.current = {
|
layerDragStateRef.current = {
|
||||||
layerId: layer.id,
|
layerId: layer.id,
|
||||||
pointerId: event.pointerId,
|
pointerId: event.pointerId,
|
||||||
startClientX: event.clientX,
|
startClientX: event.clientX,
|
||||||
startClientY: event.clientY,
|
startClientY: event.clientY,
|
||||||
startOffset: normalizeLayerPositionOffset(
|
startOffset: shouldDragAssignedImageContent
|
||||||
effectiveLayerPositionOffsets[layer.id]
|
? normalizeLayerPositionOffset(effectiveImagePlacements[layer.id])
|
||||||
),
|
: normalizeLayerPositionOffset(effectiveLayerPositionOffsets[layer.id]),
|
||||||
};
|
};
|
||||||
|
|
||||||
const nextTarget = event.currentTarget;
|
const nextTarget = event.currentTarget;
|
||||||
@ -3459,6 +3478,19 @@ export function AgentPsdTemplateEditorDialog({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shouldDragAssignedImageContent) {
|
||||||
|
updateImagePlacement(layer.id, (current) => ({
|
||||||
|
...current,
|
||||||
|
offsetX:
|
||||||
|
dragState.startOffset.offsetX +
|
||||||
|
(moveEvent.clientX - dragState.startClientX) / stageScale,
|
||||||
|
offsetY:
|
||||||
|
dragState.startOffset.offsetY +
|
||||||
|
(moveEvent.clientY - dragState.startClientY) / stageScale,
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
updateLayerPositionOffset(layer.id, () => ({
|
updateLayerPositionOffset(layer.id, () => ({
|
||||||
offsetX:
|
offsetX:
|
||||||
dragState.startOffset.offsetX +
|
dragState.startOffset.offsetX +
|
||||||
@ -4189,11 +4221,32 @@ export function AgentPsdTemplateEditorDialog({
|
|||||||
if (!layerImageUrl) {
|
if (!layerImageUrl) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
const assignedFrameLayer = assignedUrl
|
||||||
|
? getAssignedImageFrameLayer(
|
||||||
|
layer,
|
||||||
|
selectedTemplateLayers
|
||||||
|
)
|
||||||
|
: layer;
|
||||||
|
const assignedFrameOffset =
|
||||||
|
effectiveLayerPositionOffsets[
|
||||||
|
assignedFrameLayer.id
|
||||||
|
] || normalizeLayerPositionOffset();
|
||||||
|
const assignedFrameBoxStyle = {
|
||||||
|
left:
|
||||||
|
assignedFrameLayer.x +
|
||||||
|
assignedFrameOffset.offsetX,
|
||||||
|
top:
|
||||||
|
assignedFrameLayer.y +
|
||||||
|
assignedFrameOffset.offsetY,
|
||||||
|
width: assignedFrameLayer.width,
|
||||||
|
height: assignedFrameLayer.height,
|
||||||
|
} satisfies CSSProperties;
|
||||||
const assignedImageContainerStyle = assignedUrl
|
const assignedImageContainerStyle = assignedUrl
|
||||||
? {
|
? {
|
||||||
...layerBoxStyle,
|
...assignedFrameBoxStyle,
|
||||||
...getAssignedImageMaskStyle(
|
...getAssignedImageMaskStyle(
|
||||||
layer,
|
layer,
|
||||||
|
assignedFrameLayer,
|
||||||
selectedTemplateLayers
|
selectedTemplateLayers
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
@ -4263,6 +4316,7 @@ export function AgentPsdTemplateEditorDialog({
|
|||||||
assignedUrl && imageSizes[layer.id]
|
assignedUrl && imageSizes[layer.id]
|
||||||
? getPlacedAssignedImageStyle({
|
? getPlacedAssignedImageStyle({
|
||||||
layer,
|
layer,
|
||||||
|
frameLayer: assignedFrameLayer,
|
||||||
imageSize: imageSizes[layer.id],
|
imageSize: imageSizes[layer.id],
|
||||||
placement:
|
placement:
|
||||||
effectiveImagePlacements[
|
effectiveImagePlacements[
|
||||||
|
|||||||
@ -953,15 +953,24 @@ export async function renderAgentPsdTemplate(params: {
|
|||||||
assignmentUrl,
|
assignmentUrl,
|
||||||
"PSD 套版素材"
|
"PSD 套版素材"
|
||||||
);
|
);
|
||||||
|
const clipMaskLayer =
|
||||||
|
layer.forceClipMask && layer.clipMaskLayerId
|
||||||
|
? layerMap.get(layer.clipMaskLayerId)
|
||||||
|
: null;
|
||||||
|
const renderFrameLayer = clipMaskLayer || layer;
|
||||||
|
const renderFrameContentBounds =
|
||||||
|
clipMaskLayer && isAgentPsdImageLayerSlot(clipMaskLayer)
|
||||||
|
? clipMaskLayer.contentBounds
|
||||||
|
: layer.contentBounds;
|
||||||
const sourceImage = sharp(sourceBuffer, { failOn: "none" }).rotate();
|
const sourceImage = sharp(sourceBuffer, { failOn: "none" }).rotate();
|
||||||
const metadata = await sourceImage.clone().metadata();
|
const metadata = await sourceImage.clone().metadata();
|
||||||
const placementFrame = resolveAgentPsdImagePlacementFrame({
|
const placementFrame = resolveAgentPsdImagePlacementFrame({
|
||||||
containerWidth: layer.width,
|
containerWidth: renderFrameLayer.width,
|
||||||
containerHeight: layer.height,
|
containerHeight: renderFrameLayer.height,
|
||||||
imageWidth: Math.max(1, Number(metadata.width || 1)),
|
imageWidth: Math.max(1, Number(metadata.width || 1)),
|
||||||
imageHeight: Math.max(1, Number(metadata.height || 1)),
|
imageHeight: Math.max(1, Number(metadata.height || 1)),
|
||||||
replaceMode: layer.replaceMode,
|
replaceMode: layer.replaceMode,
|
||||||
contentBounds: layer.contentBounds,
|
contentBounds: renderFrameContentBounds,
|
||||||
placement: imagePlacements[layer.id],
|
placement: imagePlacements[layer.id],
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -992,19 +1001,15 @@ export async function renderAgentPsdTemplate(params: {
|
|||||||
top: placementFrame.top,
|
top: placementFrame.top,
|
||||||
width: placementFrame.width,
|
width: placementFrame.width,
|
||||||
height: placementFrame.height,
|
height: placementFrame.height,
|
||||||
canvasWidth: layer.width,
|
canvasWidth: renderFrameLayer.width,
|
||||||
canvasHeight: layer.height,
|
canvasHeight: renderFrameLayer.height,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!slotOverlay) {
|
if (!slotOverlay) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const layerPositionOffset = getLayerPositionOffset(layer.id);
|
const layerPositionOffset = getLayerPositionOffset(renderFrameLayer.id);
|
||||||
const clipMaskLayer =
|
|
||||||
layer.forceClipMask && layer.clipMaskLayerId
|
|
||||||
? layerMap.get(layer.clipMaskLayerId)
|
|
||||||
: null;
|
|
||||||
const shouldApplyMask = Boolean(layer.maskUrl || clipMaskLayer);
|
const shouldApplyMask = Boolean(layer.maskUrl || clipMaskLayer);
|
||||||
if (!shouldApplyMask) {
|
if (!shouldApplyMask) {
|
||||||
if (isDefaultSourceImageLayer) {
|
if (isDefaultSourceImageLayer) {
|
||||||
@ -1013,11 +1018,11 @@ export async function renderAgentPsdTemplate(params: {
|
|||||||
const didAppend = await appendBufferOverlay({
|
const didAppend = await appendBufferOverlay({
|
||||||
input: slotOverlay.input,
|
input: slotOverlay.input,
|
||||||
left:
|
left:
|
||||||
layer.x +
|
renderFrameLayer.x +
|
||||||
layerPositionOffset.offsetX +
|
layerPositionOffset.offsetX +
|
||||||
slotOverlay.left,
|
slotOverlay.left,
|
||||||
top:
|
top:
|
||||||
layer.y +
|
renderFrameLayer.y +
|
||||||
layerPositionOffset.offsetY +
|
layerPositionOffset.offsetY +
|
||||||
slotOverlay.top,
|
slotOverlay.top,
|
||||||
width: slotOverlay.width,
|
width: slotOverlay.width,
|
||||||
@ -1029,8 +1034,8 @@ export async function renderAgentPsdTemplate(params: {
|
|||||||
|
|
||||||
let overlayBuffer = await sharp({
|
let overlayBuffer = await sharp({
|
||||||
create: {
|
create: {
|
||||||
width: Math.max(1, Math.round(layer.width)),
|
width: Math.max(1, Math.round(renderFrameLayer.width)),
|
||||||
height: Math.max(1, Math.round(layer.height)),
|
height: Math.max(1, Math.round(renderFrameLayer.height)),
|
||||||
channels: 4,
|
channels: 4,
|
||||||
background: {
|
background: {
|
||||||
r: 0,
|
r: 0,
|
||||||
@ -1054,8 +1059,8 @@ export async function renderAgentPsdTemplate(params: {
|
|||||||
}
|
}
|
||||||
const maskBuffer = await sharp(rawMaskBuffer)
|
const maskBuffer = await sharp(rawMaskBuffer)
|
||||||
.resize({
|
.resize({
|
||||||
width: Math.max(1, Math.round(layer.width)),
|
width: Math.max(1, Math.round(renderFrameLayer.width)),
|
||||||
height: Math.max(1, Math.round(layer.height)),
|
height: Math.max(1, Math.round(renderFrameLayer.height)),
|
||||||
fit: "fill",
|
fit: "fill",
|
||||||
background: {
|
background: {
|
||||||
r: 0,
|
r: 0,
|
||||||
@ -1093,10 +1098,10 @@ export async function renderAgentPsdTemplate(params: {
|
|||||||
|
|
||||||
const didAppend = await appendBufferOverlay({
|
const didAppend = await appendBufferOverlay({
|
||||||
input: overlayBuffer,
|
input: overlayBuffer,
|
||||||
left: layer.x + layerPositionOffset.offsetX,
|
left: renderFrameLayer.x + layerPositionOffset.offsetX,
|
||||||
top: layer.y + layerPositionOffset.offsetY,
|
top: renderFrameLayer.y + layerPositionOffset.offsetY,
|
||||||
width: layer.width,
|
width: renderFrameLayer.width,
|
||||||
height: layer.height,
|
height: renderFrameLayer.height,
|
||||||
});
|
});
|
||||||
if (!didAppend) continue;
|
if (!didAppend) continue;
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user