fix: speed up psd editor image preview

This commit is contained in:
Your Name 2026-06-02 16:34:51 +08:00
parent 19dc43049d
commit 6f4a881238

View File

@ -400,6 +400,42 @@ function buildPsdLayerPreviewUrl(
return buildTemplatePreviewThumbUrl(imageUrl, { width, quality });
}
function buildAssignedPsdLayerPreviewFallbackUrls(
imageUrl: string,
params?: {
width?: number;
quality?: number;
}
) {
const normalizedUrl = String(imageUrl || "").trim();
if (!normalizedUrl) {
return [];
}
const width = Math.max(96, Math.min(1280, Math.round(params?.width || 720)));
const quality = Math.max(52, Math.min(82, Math.round(params?.quality || 74)));
const directDisplayUrl = buildImageProxyUrl(normalizedUrl, {
width,
quality,
format: "webp",
});
const proxyUrl = buildImageProxyUrl(normalizedUrl, {
width,
quality,
format: "webp",
delivery: "proxy",
});
const seen = new Set<string>();
return [normalizedUrl, directDisplayUrl, proxyUrl].filter((url) => {
if (!url || seen.has(url)) {
return false;
}
seen.add(url);
return true;
});
}
function buildPsdLayerMaskUrl(maskUrl: string, layerWidth: number) {
const normalizedUrl = String(maskUrl || "").trim();
if (!normalizedUrl) {
@ -536,6 +572,72 @@ function TemplatePreviewImage({
);
}
function AssignedPsdLayerPreviewImage({
sourceUrl,
alt,
className,
width,
quality,
style,
}: {
sourceUrl: string;
alt: string;
className?: string;
width?: number;
quality?: number;
style?: CSSProperties;
}) {
const fallbackUrls = useMemo(
() => buildAssignedPsdLayerPreviewFallbackUrls(sourceUrl, { width, quality }),
[quality, sourceUrl, width]
);
const fallbackUrlKey = fallbackUrls.join("\n");
const [activeUrlIndex, setActiveUrlIndex] = useState(0);
const [hasLoaded, setHasLoaded] = useState(false);
useEffect(() => {
setActiveUrlIndex(0);
setHasLoaded(false);
}, [fallbackUrlKey]);
useEffect(() => {
if (hasLoaded || activeUrlIndex + 1 >= fallbackUrls.length) {
return;
}
const timeoutId = window.setTimeout(() => {
setActiveUrlIndex((current) =>
current + 1 < fallbackUrls.length ? current + 1 : current
);
}, 6500);
return () => window.clearTimeout(timeoutId);
}, [activeUrlIndex, fallbackUrls.length, hasLoaded]);
const src = fallbackUrls[activeUrlIndex] || "";
if (!src) {
return null;
}
return (
<img
alt={alt}
className={className}
decoding="async"
fetchPriority="high"
loading="eager"
onError={() =>
setActiveUrlIndex((current) =>
current + 1 < fallbackUrls.length ? current + 1 : current
)
}
onLoad={() => setHasLoaded(true)}
src={src}
style={style}
/>
);
}
function getScrollAreaViewportElement(root: HTMLDivElement | null) {
return (
(root?.querySelector(
@ -4293,45 +4395,54 @@ export function AgentPsdTemplateEditorDialog({
}}
title={`${getLayerLabel(layer)}:${layer.layerName}`}
>
<img
alt={layer.layerName}
className={
assignedUrl ? "" : "h-full w-full"
}
decoding="async"
src={buildPsdLayerPreviewUrl(layerImageUrl, {
width: assignedUrl
? Math.max(layer.width, layer.height)
: layer.width,
quality: assignedUrl ? 74 : 68,
delivery: assignedUrl ? "proxy" : undefined,
})}
style={
assignedUrl && imageSizes[layer.id]
? getPlacedAssignedImageStyle({
layer,
frameLayer: assignedFrameLayer,
imageSize: imageSizes[layer.id],
placement:
effectiveImagePlacements[
layer.id
],
})
: assignedUrl
? {
{assignedUrl ? (
<AssignedPsdLayerPreviewImage
alt={layer.layerName}
quality={74}
sourceUrl={layerImageUrl}
style={
imageSizes[layer.id]
? getPlacedAssignedImageStyle({
layer,
frameLayer: assignedFrameLayer,
imageSize: imageSizes[layer.id],
placement:
effectiveImagePlacements[
layer.id
],
})
: {
width: "100%",
height: "100%",
objectFit: getImageFit(
layer.replaceMode
),
}
: {
width: "100%",
height: "100%",
objectFit: "fill",
}
}
/>
}
width={Math.max(
layer.width,
layer.height
)}
/>
) : (
<img
alt={layer.layerName}
className="h-full w-full"
decoding="async"
src={buildPsdLayerPreviewUrl(
layerImageUrl,
{
width: layer.width,
quality: 68,
}
)}
style={{
width: "100%",
height: "100%",
objectFit: "fill",
}}
/>
)}
</div>
);
}