Merge remote-tracking branch 'origin/dev-jenken' into dev-jenken
This commit is contained in:
@@ -111,6 +111,22 @@ type EditorAsset = {
|
||||
assetObjectId?: string;
|
||||
};
|
||||
|
||||
type CanvasGenerationInputField = {
|
||||
title: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
type CanvasGenerationInputReference = {
|
||||
title: string;
|
||||
label: string;
|
||||
src: string;
|
||||
};
|
||||
|
||||
type CanvasGenerationInputs = {
|
||||
fields: CanvasGenerationInputField[];
|
||||
references: CanvasGenerationInputReference[];
|
||||
};
|
||||
|
||||
type CanvasLayer = {
|
||||
id: string;
|
||||
resourceId: string;
|
||||
@@ -134,6 +150,7 @@ type CanvasLayer = {
|
||||
sourceResourceId?: string | null;
|
||||
groupId?: string | null;
|
||||
assetKind?: 'spec' | 'character' | 'icon' | 'icon-spec' | null;
|
||||
generationInputs?: CanvasGenerationInputs | null;
|
||||
};
|
||||
|
||||
type CanvasViewport = {
|
||||
@@ -388,8 +405,8 @@ const INITIAL_LAYERS: CanvasLayer[] = [
|
||||
src: '/creation-type-references/puzzle.webp',
|
||||
x: 470,
|
||||
y: 300,
|
||||
width: 420,
|
||||
height: 420,
|
||||
width: 640,
|
||||
height: 640,
|
||||
originalWidth: 640,
|
||||
originalHeight: 640,
|
||||
zIndex: 1,
|
||||
@@ -402,8 +419,8 @@ const INITIAL_LAYERS: CanvasLayer[] = [
|
||||
src: '/creation-type-references/big-fish.webp',
|
||||
x: 930,
|
||||
y: 360,
|
||||
width: 420,
|
||||
height: 236,
|
||||
width: 720,
|
||||
height: 405,
|
||||
originalWidth: 720,
|
||||
originalHeight: 405,
|
||||
zIndex: 2,
|
||||
@@ -550,6 +567,18 @@ function formatImageSizeValue(width: number, height: number) {
|
||||
return `${safeWidth}x${safeHeight}`;
|
||||
}
|
||||
|
||||
function resolveLayerResolutionSize(
|
||||
originalWidth: number,
|
||||
originalHeight: number,
|
||||
fallback: { width: number; height: number },
|
||||
) {
|
||||
// 中文注释:画布不再维护独立展示 Size,图片显示尺寸统一跟随图片原始 Resolution。
|
||||
return {
|
||||
width: Math.max(1, Math.round(originalWidth || fallback.width || 1)),
|
||||
height: Math.max(1, Math.round(originalHeight || fallback.height || 1)),
|
||||
};
|
||||
}
|
||||
|
||||
function buildQuickEditSizeOptions(currentSize: string) {
|
||||
return Array.from(new Set([currentSize, ...QUICK_EDIT_SIZE_PRESETS]));
|
||||
}
|
||||
@@ -571,10 +600,11 @@ function createLayerFromAsset(
|
||||
viewport: CanvasViewport,
|
||||
screenCenter: { x: number; y: number },
|
||||
): CanvasLayer {
|
||||
const longestSide = Math.max(asset.width, asset.height);
|
||||
const sizeRatio = longestSide > 0 ? 360 / longestSide : 1;
|
||||
const width = Math.round(asset.width * sizeRatio);
|
||||
const height = Math.round(asset.height * sizeRatio);
|
||||
const { width, height } = resolveLayerResolutionSize(
|
||||
asset.width,
|
||||
asset.height,
|
||||
{ width: 360, height: 360 },
|
||||
);
|
||||
const worldCenterX = (screenCenter.x - viewport.x) / viewport.scale;
|
||||
const worldCenterY = (screenCenter.y - viewport.y) / viewport.scale;
|
||||
const offset = index * 34;
|
||||
@@ -625,6 +655,7 @@ function serializeLayer(layer: CanvasLayer): EditorProjectLayerSnapshot {
|
||||
sourceResourceId: layer.sourceResourceId,
|
||||
groupId: layer.groupId,
|
||||
assetKind: layer.assetKind,
|
||||
generationInputs: layer.generationInputs,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -650,10 +681,18 @@ function hydrateLayer(
|
||||
src,
|
||||
x: numberFromSnapshot(snapshot.x, 0),
|
||||
y: numberFromSnapshot(snapshot.y, 0),
|
||||
width: numberFromSnapshot(snapshot.width, 320),
|
||||
height: numberFromSnapshot(snapshot.height, 320),
|
||||
originalWidth: numberFromSnapshot(snapshot.originalWidth, 320),
|
||||
originalHeight: numberFromSnapshot(snapshot.originalHeight, 320),
|
||||
...(() => {
|
||||
const originalWidth = numberFromSnapshot(snapshot.originalWidth, 320);
|
||||
const originalHeight = numberFromSnapshot(snapshot.originalHeight, 320);
|
||||
return {
|
||||
...resolveLayerResolutionSize(originalWidth, originalHeight, {
|
||||
width: numberFromSnapshot(snapshot.width, 320),
|
||||
height: numberFromSnapshot(snapshot.height, 320),
|
||||
}),
|
||||
originalWidth,
|
||||
originalHeight,
|
||||
};
|
||||
})(),
|
||||
zIndex: numberFromSnapshot(snapshot.zIndex, 1),
|
||||
sourceType: isCanvasSourceType(snapshot.sourceType)
|
||||
? snapshot.sourceType
|
||||
@@ -668,6 +707,7 @@ function hydrateLayer(
|
||||
sourceResourceId: stringOrNull(snapshot.sourceResourceId),
|
||||
groupId: stringOrNull(snapshot.groupId),
|
||||
assetKind: canvasAssetKindOrNull(snapshot.assetKind),
|
||||
generationInputs: generationInputsOrNull(snapshot.generationInputs),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -724,6 +764,45 @@ function stringOrNull(value: unknown) {
|
||||
return typeof value === 'string' && value.trim() ? value : null;
|
||||
}
|
||||
|
||||
function generationInputsOrNull(value: unknown): CanvasGenerationInputs | null {
|
||||
if (!value || typeof value !== 'object') {
|
||||
return null;
|
||||
}
|
||||
const snapshot = value as {
|
||||
fields?: unknown;
|
||||
references?: unknown;
|
||||
};
|
||||
const fields = Array.isArray(snapshot.fields)
|
||||
? snapshot.fields.flatMap((field) => {
|
||||
if (!field || typeof field !== 'object') {
|
||||
return [];
|
||||
}
|
||||
const item = field as { title?: unknown; value?: unknown };
|
||||
const title = stringOrNull(item.title);
|
||||
const fieldValue = stringOrNull(item.value);
|
||||
return title && fieldValue ? [{ title, value: fieldValue }] : [];
|
||||
})
|
||||
: [];
|
||||
const references = Array.isArray(snapshot.references)
|
||||
? snapshot.references.flatMap((reference) => {
|
||||
if (!reference || typeof reference !== 'object') {
|
||||
return [];
|
||||
}
|
||||
const item = reference as {
|
||||
title?: unknown;
|
||||
label?: unknown;
|
||||
src?: unknown;
|
||||
};
|
||||
const title = stringOrNull(item.title);
|
||||
const label = stringOrNull(item.label);
|
||||
const src = stringOrNull(item.src);
|
||||
return title && label && src ? [{ title, label, src }] : [];
|
||||
})
|
||||
: [];
|
||||
|
||||
return fields.length || references.length ? { fields, references } : null;
|
||||
}
|
||||
|
||||
function canvasAssetKindOrNull(value: unknown): CanvasLayer['assetKind'] {
|
||||
return value === 'spec' ||
|
||||
value === 'character' ||
|
||||
@@ -828,6 +907,11 @@ function calculateCharacterAnimationPrice(
|
||||
return (resolution === '720p' ? 20 : 10) * durationSeconds;
|
||||
}
|
||||
|
||||
function resolveCharacterAnimationSourceImageSrc(layer: CanvasLayer) {
|
||||
// 中文注释:角色图已持久化到 OSS 时优先传 objectKey,避免把大 Data URL 塞进 JSON 请求体触发 body limit。
|
||||
return layer.objectKey?.trim() || layer.src;
|
||||
}
|
||||
|
||||
function createCanvasLayerReference(
|
||||
layer: CanvasLayer,
|
||||
): CharacterReferenceImage {
|
||||
@@ -838,6 +922,110 @@ function createCanvasLayerReference(
|
||||
};
|
||||
}
|
||||
|
||||
function createGenerationInputField(
|
||||
title: string,
|
||||
value: string | null | undefined,
|
||||
): CanvasGenerationInputField[] {
|
||||
const normalizedValue = value?.trim();
|
||||
return normalizedValue ? [{ title, value: normalizedValue }] : [];
|
||||
}
|
||||
|
||||
function buildImageGenerationInputs(prompt: string): CanvasGenerationInputs {
|
||||
return {
|
||||
fields: createGenerationInputField('生成提示词', prompt),
|
||||
references: [],
|
||||
};
|
||||
}
|
||||
|
||||
function buildSpecGenerationInputs(
|
||||
specType: SpecGenerationType,
|
||||
values: SpecFormValues,
|
||||
): CanvasGenerationInputs {
|
||||
if (specType === 'custom') {
|
||||
return {
|
||||
fields: createGenerationInputField('自定义规范提示词', values.customPrompt),
|
||||
references: [],
|
||||
};
|
||||
}
|
||||
|
||||
const baseFields = [
|
||||
...createGenerationInputField('玩法设定', values.playSetting),
|
||||
...createGenerationInputField('美术风格', values.artStyle),
|
||||
];
|
||||
if (specType === 'character') {
|
||||
baseFields.push(
|
||||
...createGenerationInputField('头身比', values.bodyRatio),
|
||||
...createGenerationInputField('角色视角', values.characterView),
|
||||
);
|
||||
}
|
||||
return {
|
||||
fields: baseFields,
|
||||
references: [],
|
||||
};
|
||||
}
|
||||
|
||||
function buildCharacterGenerationInputs(
|
||||
prompt: string,
|
||||
specReference: CharacterReferenceImage | null | undefined,
|
||||
references: CharacterReferenceImage[] | undefined,
|
||||
): CanvasGenerationInputs {
|
||||
return {
|
||||
fields: createGenerationInputField('角色设定', prompt),
|
||||
references: [
|
||||
...(specReference
|
||||
? [
|
||||
{
|
||||
title: '角色形象规范',
|
||||
label: specReference.label,
|
||||
src: specReference.src,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(references ?? []).map((reference, index) => ({
|
||||
title: `常规参考图 ${index + 1}`,
|
||||
label: reference.label,
|
||||
src: reference.src,
|
||||
})),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function buildIconGenerationInputs(
|
||||
iconDescriptions: string[],
|
||||
specReference: CharacterReferenceImage,
|
||||
): CanvasGenerationInputs {
|
||||
return {
|
||||
fields: iconDescriptions.map((description, index) => ({
|
||||
title: `素材描述 ${index + 1}`,
|
||||
value: description,
|
||||
})),
|
||||
references: [
|
||||
{
|
||||
title: '图标素材规范',
|
||||
label: specReference.label,
|
||||
src: specReference.src,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function buildEditGenerationInputs(
|
||||
title: '修改要求' | '快速编辑提示词',
|
||||
prompt: string,
|
||||
sourceLayer: CanvasLayer,
|
||||
): CanvasGenerationInputs {
|
||||
return {
|
||||
fields: createGenerationInputField(title, prompt),
|
||||
references: [
|
||||
{
|
||||
title: '参考图',
|
||||
label: sourceLayer.title,
|
||||
src: sourceLayer.src,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function buildPortalMenuStyle(
|
||||
anchor: HTMLElement | null,
|
||||
placement: 'above' | 'below',
|
||||
@@ -2421,10 +2609,11 @@ export function ImageCanvasEditorView() {
|
||||
uploadedImage.onload = () => {
|
||||
const originalWidth = uploadedImage.naturalWidth || fallbackWidth;
|
||||
const originalHeight = uploadedImage.naturalHeight || fallbackHeight;
|
||||
const longestSide = Math.max(originalWidth, originalHeight);
|
||||
const sizeRatio = longestSide > 0 ? Math.min(1, 420 / longestSide) : 1;
|
||||
const width = Math.round(originalWidth * sizeRatio);
|
||||
const height = Math.round(originalHeight * sizeRatio);
|
||||
const { width, height } = resolveLayerResolutionSize(
|
||||
originalWidth,
|
||||
originalHeight,
|
||||
{ width: fallbackWidth, height: fallbackHeight },
|
||||
);
|
||||
if (options.addToCanvas) {
|
||||
setLayers((currentLayers) =>
|
||||
currentLayers.map((layer) =>
|
||||
@@ -2685,19 +2874,28 @@ export function ImageCanvasEditorView() {
|
||||
assetKind?: CanvasLayer['assetKind'];
|
||||
title?: string;
|
||||
dialogId?: string;
|
||||
generationInputs?: CanvasGenerationInputs;
|
||||
} = {},
|
||||
) => {
|
||||
layerCounterRef.current += 1;
|
||||
const generatedIndex = layerCounterRef.current;
|
||||
const originalWidth = generated.width || 1024;
|
||||
const originalHeight = generated.height || 1024;
|
||||
const longestSide = Math.max(originalWidth, originalHeight);
|
||||
const sizeRatio = longestSide > 0 ? Math.min(1, 420 / longestSide) : 1;
|
||||
const width = options.frame?.width ?? Math.round(originalWidth * sizeRatio);
|
||||
const height =
|
||||
options.frame?.height ?? Math.round(originalHeight * sizeRatio);
|
||||
const { width, height } = resolveLayerResolutionSize(
|
||||
originalWidth,
|
||||
originalHeight,
|
||||
{ width: 1024, height: 1024 },
|
||||
);
|
||||
const worldCenterX = (canvasSize.width / 2 - viewport.x) / viewport.scale;
|
||||
const worldCenterY = (canvasSize.height / 2 - viewport.y) / viewport.scale;
|
||||
const frameX =
|
||||
options.frame && options.frame.width > 0
|
||||
? options.frame.x + options.frame.width / 2 - width / 2
|
||||
: undefined;
|
||||
const frameY =
|
||||
options.frame && options.frame.height > 0
|
||||
? options.frame.y + options.frame.height / 2 - height / 2
|
||||
: undefined;
|
||||
const nextLayer: CanvasLayer = {
|
||||
id: options.sourceLayer
|
||||
? `layer-edit-${generatedIndex}`
|
||||
@@ -2711,10 +2909,10 @@ export function ImageCanvasEditorView() {
|
||||
src: generated.imageSrc,
|
||||
x: options.sourceLayer
|
||||
? options.sourceLayer.x + options.sourceLayer.width + 32
|
||||
: (options.frame?.x ?? worldCenterX - width / 2),
|
||||
: (frameX ?? worldCenterX - width / 2),
|
||||
y: options.sourceLayer
|
||||
? options.sourceLayer.y
|
||||
: (options.frame?.y ?? worldCenterY - height / 2),
|
||||
: (frameY ?? worldCenterY - height / 2),
|
||||
width,
|
||||
height,
|
||||
originalWidth,
|
||||
@@ -2730,6 +2928,7 @@ export function ImageCanvasEditorView() {
|
||||
objectKey: generated.objectKey,
|
||||
assetObjectId: generated.assetObjectId,
|
||||
sourceResourceId: options.sourceLayer?.resourceId,
|
||||
generationInputs: options.generationInputs,
|
||||
};
|
||||
|
||||
setLayers((currentLayers) => [...currentLayers, nextLayer]);
|
||||
@@ -2761,9 +2960,20 @@ export function ImageCanvasEditorView() {
|
||||
const addQuickEditResultLayer = (
|
||||
generated: EditorImageGenerationResult,
|
||||
sourceLayer: CanvasLayer,
|
||||
generationInputs: CanvasGenerationInputs,
|
||||
) => {
|
||||
layerCounterRef.current += 1;
|
||||
const generatedIndex = layerCounterRef.current;
|
||||
const originalWidth = generated.width || sourceLayer.originalWidth || 1024;
|
||||
const originalHeight = generated.height || sourceLayer.originalHeight || 1024;
|
||||
const { width, height } = resolveLayerResolutionSize(
|
||||
originalWidth,
|
||||
originalHeight,
|
||||
{
|
||||
width: sourceLayer.width,
|
||||
height: sourceLayer.height,
|
||||
},
|
||||
);
|
||||
const nextLayer: CanvasLayer = {
|
||||
id: `layer-quick-edit-${generatedIndex}`,
|
||||
resourceId: `local-resource-quick-edit-${generatedIndex}`,
|
||||
@@ -2771,10 +2981,10 @@ export function ImageCanvasEditorView() {
|
||||
src: generated.imageSrc,
|
||||
x: sourceLayer.x + sourceLayer.width + 32,
|
||||
y: sourceLayer.y,
|
||||
width: sourceLayer.width,
|
||||
height: sourceLayer.height,
|
||||
originalWidth: sourceLayer.originalWidth,
|
||||
originalHeight: sourceLayer.originalHeight,
|
||||
width,
|
||||
height,
|
||||
originalWidth,
|
||||
originalHeight,
|
||||
zIndex: generatedIndex + 10,
|
||||
sourceType: generated.sourceType,
|
||||
prompt: generated.prompt,
|
||||
@@ -2787,6 +2997,7 @@ export function ImageCanvasEditorView() {
|
||||
sourceResourceId: sourceLayer.resourceId,
|
||||
groupId: sourceLayer.groupId,
|
||||
assetKind: sourceLayer.assetKind,
|
||||
generationInputs,
|
||||
};
|
||||
|
||||
setLayers((currentLayers) => [...currentLayers, nextLayer]);
|
||||
@@ -2801,6 +3012,7 @@ export function ImageCanvasEditorView() {
|
||||
const addIconSpritesheetResultLayers = (
|
||||
generated: EditorIconSpritesheetGenerationResult,
|
||||
iconResults: EditorIconSpritesheetIconResult[],
|
||||
generationInputs: CanvasGenerationInputs,
|
||||
frame?: GenerateDialogState['placeholder'],
|
||||
dialogId?: string,
|
||||
) => {
|
||||
@@ -2822,10 +3034,11 @@ export function ImageCanvasEditorView() {
|
||||
iconResults.forEach((icon) => {
|
||||
const originalWidth = icon.width || 128;
|
||||
const originalHeight = icon.height || 128;
|
||||
const longestSide = Math.max(originalWidth, originalHeight);
|
||||
const sizeRatio = longestSide > 0 ? Math.min(1, 128 / longestSide) : 1;
|
||||
const width = Math.round(originalWidth * sizeRatio);
|
||||
const height = Math.round(originalHeight * sizeRatio);
|
||||
const { width, height } = resolveLayerResolutionSize(
|
||||
originalWidth,
|
||||
originalHeight,
|
||||
{ width: 128, height: 128 },
|
||||
);
|
||||
if (cursorX > startX && cursorX + width - startX > maxRowWidth) {
|
||||
cursorX = startX;
|
||||
cursorY += rowHeight + spacing;
|
||||
@@ -2853,6 +3066,7 @@ export function ImageCanvasEditorView() {
|
||||
provider: generated.provider,
|
||||
taskId: generated.taskId,
|
||||
assetKind: 'icon',
|
||||
generationInputs,
|
||||
});
|
||||
|
||||
cursorX += width + spacing;
|
||||
@@ -2964,6 +3178,7 @@ export function ImageCanvasEditorView() {
|
||||
addIconSpritesheetResultLayers(
|
||||
generated,
|
||||
generated.iconImageSrcs,
|
||||
buildIconGenerationInputs(iconDescriptions, dialog.iconSpecReference),
|
||||
getGeneratingDialogPlaceholder(dialog),
|
||||
canvasDialog.id,
|
||||
);
|
||||
@@ -3001,7 +3216,15 @@ export function ImageCanvasEditorView() {
|
||||
model: quickEditPanel.model,
|
||||
referenceImageSrcs: [referenceImageSrc],
|
||||
});
|
||||
addQuickEditResultLayer(generated, quickEditSourceLayer);
|
||||
addQuickEditResultLayer(
|
||||
generated,
|
||||
quickEditSourceLayer,
|
||||
buildEditGenerationInputs(
|
||||
'快速编辑提示词',
|
||||
normalizedPrompt,
|
||||
quickEditSourceLayer,
|
||||
),
|
||||
);
|
||||
} catch (error) {
|
||||
setQuickEditPanel({
|
||||
...quickEditPanel,
|
||||
@@ -3048,7 +3271,14 @@ export function ImageCanvasEditorView() {
|
||||
prompt: normalizedPrompt,
|
||||
sourceImageSrc: referenceImageSrc,
|
||||
});
|
||||
addGeneratedResultLayer(generated, { sourceLayer });
|
||||
addGeneratedResultLayer(generated, {
|
||||
sourceLayer,
|
||||
generationInputs: buildEditGenerationInputs(
|
||||
'修改要求',
|
||||
normalizedPrompt,
|
||||
sourceLayer,
|
||||
),
|
||||
});
|
||||
} else if (dialog.mode === 'spec') {
|
||||
const specType = dialog.specType ?? 'custom';
|
||||
const specValues =
|
||||
@@ -3065,6 +3295,7 @@ export function ImageCanvasEditorView() {
|
||||
assetKind: specType === 'icon' ? 'icon-spec' : 'spec',
|
||||
title: `${SPEC_TYPE_LABEL[specType]} ${layerCounterRef.current + 1}`,
|
||||
dialogId: canvasDialog?.id,
|
||||
generationInputs: buildSpecGenerationInputs(specType, specValues),
|
||||
});
|
||||
} else if (dialog.mode === 'character') {
|
||||
const referenceImageSrcs = [
|
||||
@@ -3083,6 +3314,11 @@ export function ImageCanvasEditorView() {
|
||||
assetKind: 'character',
|
||||
title: `角色形象 ${layerCounterRef.current + 1}`,
|
||||
dialogId: canvasDialog?.id,
|
||||
generationInputs: buildCharacterGenerationInputs(
|
||||
normalizedPrompt,
|
||||
dialog.characterSpecReference,
|
||||
dialog.characterReferences,
|
||||
),
|
||||
});
|
||||
} else {
|
||||
const generated = await generateEditorImage({
|
||||
@@ -3091,6 +3327,7 @@ export function ImageCanvasEditorView() {
|
||||
addGeneratedResultLayer(generated, {
|
||||
frame: getGeneratingDialogPlaceholder(dialog),
|
||||
dialogId: canvasDialog?.id,
|
||||
generationInputs: buildImageGenerationInputs(normalizedPrompt),
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -3738,7 +3975,9 @@ export function ImageCanvasEditorView() {
|
||||
try {
|
||||
const result = await generateEditorCharacterAnimation({
|
||||
sourceLayerId: characterAnimationSourceLayer.id,
|
||||
sourceImageSrc: characterAnimationSourceLayer.src,
|
||||
sourceImageSrc: resolveCharacterAnimationSourceImageSrc(
|
||||
characterAnimationSourceLayer,
|
||||
),
|
||||
sourceWidth: characterAnimationSourceLayer.originalWidth,
|
||||
sourceHeight: characterAnimationSourceLayer.originalHeight,
|
||||
promptText,
|
||||
@@ -4348,8 +4587,8 @@ export function ImageCanvasEditorView() {
|
||||
size="xs"
|
||||
className="image-canvas-editor__size-badge"
|
||||
>
|
||||
{Math.round(layer.width)} x {Math.round(layer.height)}{' '}
|
||||
px
|
||||
{Math.round(layer.originalWidth)} x{' '}
|
||||
{Math.round(layer.originalHeight)} px
|
||||
</PlatformPillBadge>
|
||||
) : null}
|
||||
{layerGeneratingLabel ? (
|
||||
@@ -5896,24 +6135,42 @@ export function ImageCanvasEditorView() {
|
||||
<dl className="image-canvas-editor__metadata-grid">
|
||||
<dt>图片类型</dt>
|
||||
<dd>{formatLayerImageType(metadataLayer)}</dd>
|
||||
<dt>Prompt</dt>
|
||||
<dd className="image-canvas-editor__metadata-prompt">
|
||||
{metadataLayer.prompt ? (
|
||||
<dt>生成输入</dt>
|
||||
<dd className="image-canvas-editor__metadata-inputs">
|
||||
{metadataLayer.generationInputs?.fields.length ||
|
||||
metadataLayer.generationInputs?.references.length ? (
|
||||
<>
|
||||
<span>{metadataLayer.prompt}</span>
|
||||
<PlatformActionButton
|
||||
type="button"
|
||||
tone="secondary"
|
||||
size="xs"
|
||||
className="image-canvas-editor__metadata-copy"
|
||||
onClick={() => {
|
||||
void navigator.clipboard?.writeText(
|
||||
metadataLayer.prompt ?? '',
|
||||
);
|
||||
}}
|
||||
>
|
||||
复制Prompt
|
||||
</PlatformActionButton>
|
||||
{metadataLayer.generationInputs.fields.map((field) => (
|
||||
<div
|
||||
key={`${field.title}-${field.value}`}
|
||||
className="image-canvas-editor__metadata-input-field"
|
||||
>
|
||||
<span className="image-canvas-editor__metadata-input-title">
|
||||
{field.title}
|
||||
</span>
|
||||
<span>{field.value}</span>
|
||||
</div>
|
||||
))}
|
||||
{metadataLayer.generationInputs.references.length ? (
|
||||
<div className="image-canvas-editor__metadata-reference-list">
|
||||
{metadataLayer.generationInputs.references.map(
|
||||
(reference) => (
|
||||
<div
|
||||
key={`${reference.title}-${reference.label}-${reference.src}`}
|
||||
className="image-canvas-editor__metadata-reference-card"
|
||||
>
|
||||
<img src={reference.src} alt="" aria-hidden="true" />
|
||||
<span className="image-canvas-editor__metadata-reference-copy">
|
||||
<span className="image-canvas-editor__metadata-input-title">
|
||||
{reference.title}
|
||||
</span>
|
||||
<span>{reference.label}</span>
|
||||
</span>
|
||||
</div>
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
) : (
|
||||
'-'
|
||||
@@ -5921,11 +6178,6 @@ export function ImageCanvasEditorView() {
|
||||
</dd>
|
||||
<dt>Model</dt>
|
||||
<dd>{metadataLayer.model ?? '-'}</dd>
|
||||
<dt>Size</dt>
|
||||
<dd>
|
||||
{Math.round(metadataLayer.width)} x{' '}
|
||||
{Math.round(metadataLayer.height)} px
|
||||
</dd>
|
||||
<dt>Resolution</dt>
|
||||
<dd>
|
||||
{metadataLayer.originalWidth} x {metadataLayer.originalHeight} px
|
||||
|
||||
Reference in New Issue
Block a user