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