新抠图算法(轻量版)上线 (#73)
新抠图算法(轻量版)上线,生图背景色同步改为多颜色+自动决策 --------- Co-authored-by: kdletters <kdletters@qq.com> Reviewed-on: https://git.genarrative.world/git/GenarrativeAI/Genarrative/pulls/73 Reviewed-by: kdletters <kdletters@qq.com> Co-authored-by: Linghong <ink29535@proton.me> Co-committed-by: Linghong <ink29535@proton.me>
This commit was merged in pull request #73.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -481,7 +481,7 @@ describe('ImageCanvasGenerationDialogModel', () => {
|
||||
{
|
||||
title: '提取提示词',
|
||||
value:
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用单一纯绿色 #00FF00 / RGB(0,255,0) 绿幕。绿幕背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现绿色描边、绿色底板、绿色投影或绿色反光。',
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用所选单一纯色抠图背景。纯色背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现与背景色相同或相近的描边、底板、投影或反光。',
|
||||
},
|
||||
{ title: 'model', value: 'gpt-image-2' },
|
||||
],
|
||||
@@ -496,13 +496,17 @@ describe('ImageCanvasGenerationDialogModel', () => {
|
||||
const canvasSize = { width: 960, height: 720 };
|
||||
const viewport = { x: 0, y: 0, scale: 1 };
|
||||
const characterDraft = createSameSourceGenerationDialogDraft({
|
||||
sourceLayer: createLayer({
|
||||
assetKind: 'character',
|
||||
generationInputs: {
|
||||
fields: [{ title: '角色设定', value: '红发骑士' }],
|
||||
references: [],
|
||||
},
|
||||
}),
|
||||
sourceLayer: createLayer({
|
||||
assetKind: 'character',
|
||||
generationInputs: {
|
||||
fields: [
|
||||
{ title: '角色设定', value: '红发骑士' },
|
||||
{ title: '抠图背景色', value: '暖浅桃色 #FFD6C2' },
|
||||
{ title: '抠图模型', value: '动漫风格 anime-seg' },
|
||||
],
|
||||
references: [],
|
||||
},
|
||||
}),
|
||||
canvasSize,
|
||||
viewport,
|
||||
mode: 'redraw',
|
||||
|
||||
@@ -738,6 +738,7 @@ function restoreSharedImageOptions(
|
||||
sourceLayer: CanvasLayer,
|
||||
sourceDialog?: CanvasGenerationDialogState | null,
|
||||
): Omit<CanvasGenerationDialogState, 'id'> {
|
||||
const fields = getGenerationInputFieldValues(sourceLayer);
|
||||
return {
|
||||
...draft,
|
||||
imageModel: sourceDialog?.imageModel ?? draft.imageModel,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* @vitest-environment jsdom */
|
||||
/* @vitest-environment jsdom */
|
||||
|
||||
import { fireEvent, render, screen, within } from '@testing-library/react';
|
||||
import { useState } from 'react';
|
||||
@@ -15,11 +15,13 @@ import {
|
||||
function ImageOptionsHarness({
|
||||
initialDialog,
|
||||
includeDimensions = true,
|
||||
|
||||
onRememberImageModel = vi.fn(),
|
||||
lockedModel,
|
||||
}: {
|
||||
initialDialog: GenerateDialogState;
|
||||
includeDimensions?: boolean;
|
||||
|
||||
onRememberImageModel?: (model: string) => void;
|
||||
lockedModel?: string;
|
||||
}) {
|
||||
|
||||
@@ -250,7 +250,9 @@ describe('ImageCanvasGenerationModel', () => {
|
||||
],
|
||||
),
|
||||
).toEqual({
|
||||
fields: [{ title: '角色设定', value: '主角骑士' }],
|
||||
fields: [
|
||||
{ title: '角色设定', value: '主角骑士' },
|
||||
],
|
||||
references: [
|
||||
{
|
||||
title: '角色规范',
|
||||
@@ -313,7 +315,7 @@ describe('ImageCanvasGenerationModel', () => {
|
||||
{
|
||||
title: '提取提示词',
|
||||
value:
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用单一纯绿色 #00FF00 / RGB(0,255,0) 绿幕。绿幕背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现绿色描边、绿色底板、绿色投影或绿色反光。',
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用所选单一纯色抠图背景。纯色背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现与背景色相同或相近的描边、底板、投影或反光。',
|
||||
},
|
||||
],
|
||||
references: [
|
||||
|
||||
@@ -97,8 +97,10 @@ export const DEFAULT_ICON_DESCRIPTIONS = [
|
||||
'原图按钮',
|
||||
'冻结按钮',
|
||||
];
|
||||
export const DEFAULT_EDITOR_GENERATION_BACKGROUND_COLOR = 'auto';
|
||||
export const DEFAULT_EDITOR_BGFILTER_SEG_MODEL = 'birefnet';
|
||||
export const UI_DESIGN_ASSET_EXTRACTION_PROMPT =
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用单一纯绿色 #00FF00 / RGB(0,255,0) 绿幕。绿幕背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现绿色描边、绿色底板、绿色投影或绿色反光。';
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用所选单一纯色抠图背景。纯色背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现与背景色相同或相近的描边、底板、投影或反光。';
|
||||
export const QUICK_EDIT_SIZE_PRESETS = [
|
||||
'1024x1024',
|
||||
'1536x1024',
|
||||
@@ -1203,10 +1205,12 @@ export function buildUiDesignAssetExtractionGenerationInputs(
|
||||
references?: CharacterReferenceImage[],
|
||||
): CanvasGenerationInputs {
|
||||
return {
|
||||
fields: createGenerationInputField(
|
||||
'提取提示词',
|
||||
UI_DESIGN_ASSET_EXTRACTION_PROMPT,
|
||||
),
|
||||
fields: [
|
||||
...createGenerationInputField(
|
||||
'提取提示词',
|
||||
UI_DESIGN_ASSET_EXTRACTION_PROMPT,
|
||||
),
|
||||
],
|
||||
references: [
|
||||
...createLayerGenerationInputReference('UI设计图', sourceLayer),
|
||||
...(references ?? []).flatMap((reference, index) =>
|
||||
|
||||
@@ -301,6 +301,8 @@ describe('ImageCanvasGenerationSubmissionModel', () => {
|
||||
prompt: '白发骑士',
|
||||
kind: 'character',
|
||||
model: 'gpt-image-2',
|
||||
screenColor: 'auto',
|
||||
segModel: 'birefnet',
|
||||
aspectRatio: '2:3',
|
||||
imageSize: '2K',
|
||||
referenceImageSrcs: [
|
||||
@@ -316,7 +318,9 @@ describe('ImageCanvasGenerationSubmissionModel', () => {
|
||||
});
|
||||
expect(plan.kind === 'image' ? plan.result.generationInputs : null).toEqual(
|
||||
{
|
||||
fields: [{ title: '角色设定', value: '白发骑士' }],
|
||||
fields: [
|
||||
{ title: '角色设定', value: '白发骑士' },
|
||||
],
|
||||
references: [
|
||||
{
|
||||
title: '角色规范',
|
||||
@@ -665,6 +669,8 @@ describe('ImageCanvasGenerationSubmissionModel', () => {
|
||||
referenceImageSrcs: ['data:image/png;base64,ref'],
|
||||
iconDescriptions: ['返回按钮', '设置按钮'],
|
||||
model: 'gpt-image-2',
|
||||
screenColor: 'auto',
|
||||
segModel: 'birefnet',
|
||||
aspectRatio: '3:2',
|
||||
imageSize: '2K',
|
||||
},
|
||||
|
||||
@@ -29,7 +29,8 @@ import {
|
||||
buildUiDesignGenerationInputs,
|
||||
buildVideoGenerationInputs,
|
||||
CHARACTER_ANIMATION_MODEL,
|
||||
DEFAULT_ICON_DESCRIPTIONS,
|
||||
DEFAULT_EDITOR_BGFILTER_SEG_MODEL,
|
||||
DEFAULT_EDITOR_GENERATION_BACKGROUND_COLOR,
|
||||
DEFAULT_SOUND_EFFECT_DURATION_SECONDS,
|
||||
DEFAULT_SOUND_EFFECT_MODEL,
|
||||
DEFAULT_SPEC_FORM_VALUES,
|
||||
@@ -347,6 +348,8 @@ export function buildImageGenerationSubmissionPlan({
|
||||
),
|
||||
].filter((src): src is string => Boolean(src));
|
||||
const imageModel = normalizeEditorImageModel(dialog.imageModel);
|
||||
const screenColor = DEFAULT_EDITOR_GENERATION_BACKGROUND_COLOR;
|
||||
const segModel = DEFAULT_EDITOR_BGFILTER_SEG_MODEL;
|
||||
return {
|
||||
kind: 'image',
|
||||
normalizedPrompt,
|
||||
@@ -354,6 +357,8 @@ export function buildImageGenerationSubmissionPlan({
|
||||
prompt: normalizedPrompt,
|
||||
kind: 'character',
|
||||
model: imageModel,
|
||||
screenColor,
|
||||
segModel,
|
||||
aspectRatio: dialog.aspectRatio ?? '1:1',
|
||||
imageSize: dialog.imageSize ?? '1K',
|
||||
...(referenceImageSrcs.length ? { referenceImageSrcs } : {}),
|
||||
@@ -569,11 +574,14 @@ export function buildImageGenerationSubmissionPlan({
|
||||
export function buildIconSpritesheetGenerationSubmissionPlan(
|
||||
dialog: GenerateDialogState,
|
||||
): IconSpritesheetGenerationSubmissionPlan {
|
||||
const iconDescriptions = (
|
||||
dialog.prompt.trim()
|
||||
? dialog.prompt.split(/[\r\n,,、;;/|]+/u)
|
||||
: (dialog.iconDescriptions ?? DEFAULT_ICON_DESCRIPTIONS)
|
||||
)
|
||||
const iconDescriptionSource = dialog.prompt.trim()
|
||||
? dialog.prompt.split(/[\r\n,,、;;/|]+/u)
|
||||
: (dialog.iconDescriptions ?? []).some((description) =>
|
||||
description.trim(),
|
||||
)
|
||||
? (dialog.iconDescriptions ?? [])
|
||||
: [];
|
||||
const iconDescriptions = iconDescriptionSource
|
||||
.map((description) => description.trim())
|
||||
.filter(Boolean)
|
||||
.slice(0, ICON_DESCRIPTION_LIMIT);
|
||||
@@ -593,6 +601,8 @@ export function buildIconSpritesheetGenerationSubmissionPlan(
|
||||
}
|
||||
|
||||
const rememberImageModel = normalizeEditorImageModel(dialog.imageModel);
|
||||
const screenColor = DEFAULT_EDITOR_GENERATION_BACKGROUND_COLOR;
|
||||
const segModel = DEFAULT_EDITOR_BGFILTER_SEG_MODEL;
|
||||
return {
|
||||
ok: true,
|
||||
iconDescriptions,
|
||||
@@ -609,6 +619,8 @@ export function buildIconSpritesheetGenerationSubmissionPlan(
|
||||
: {}),
|
||||
iconDescriptions,
|
||||
model: rememberImageModel,
|
||||
screenColor,
|
||||
segModel,
|
||||
aspectRatio: dialog.aspectRatio ?? '1:1',
|
||||
imageSize: dialog.imageSize ?? '1K',
|
||||
},
|
||||
|
||||
@@ -48,7 +48,10 @@ export type UiAssetExtractionImageSize =
|
||||
|
||||
export function createUiAssetExtractionState(
|
||||
sourceLayerId: string,
|
||||
options: { initialTool?: UiAssetExtractionTool | null; model: string },
|
||||
options: {
|
||||
initialTool?: UiAssetExtractionTool | null;
|
||||
model: string;
|
||||
},
|
||||
): UiAssetExtractionState {
|
||||
return {
|
||||
sourceLayerId,
|
||||
|
||||
@@ -172,6 +172,12 @@ describe('ImageCanvasUiAssetExtractionOverlayView', () => {
|
||||
expect(
|
||||
within(panel).getByRole('button', { name: '提取素材模型 nanobanana2' }),
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
within(panel).queryByRole('button', { name: /提取素材背景色/u }),
|
||||
).toBeNull();
|
||||
expect(
|
||||
within(panel).queryByRole('button', { name: /提取素材抠图模型/u }),
|
||||
).toBeNull();
|
||||
expect(within(panel).getByLabelText('参考UI.png')).toBeTruthy();
|
||||
fireEvent.click(
|
||||
within(panel).getByRole('button', { name: '上传UI素材参考图' }),
|
||||
|
||||
@@ -1945,9 +1945,9 @@ describe('useImageCanvasGenerationSubmissionWorkflow', () => {
|
||||
spritesheetWidth: 512,
|
||||
spritesheetHeight: 512,
|
||||
prompt:
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用单一纯绿色 #00FF00 / RGB(0,255,0) 绿幕。绿幕背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现绿色描边、绿色底板、绿色投影或绿色反光。',
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用所选单一纯色抠图背景。纯色背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现与背景色相同或相近的描边、底板、投影或反光。',
|
||||
actualPrompt:
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用单一纯绿色 #00FF00 / RGB(0,255,0) 绿幕。绿幕背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现绿色描边、绿色底板、绿色投影或绿色反光。',
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用所选单一纯色抠图背景。纯色背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现与背景色相同或相近的描边、底板、投影或反光。',
|
||||
model: 'gpt-image-2',
|
||||
provider: 'VectorEngine',
|
||||
taskId: 'task-ui-assets',
|
||||
@@ -1973,6 +1973,8 @@ describe('useImageCanvasGenerationSubmissionWorkflow', () => {
|
||||
expect.objectContaining({
|
||||
sourceImageSrc: 'generated/ui-design.png',
|
||||
model: 'gemini-3.1-flash-image-preview',
|
||||
screenColor: 'auto',
|
||||
segModel: 'birefnet',
|
||||
}),
|
||||
);
|
||||
});
|
||||
@@ -1999,9 +2001,9 @@ describe('useImageCanvasGenerationSubmissionWorkflow', () => {
|
||||
spritesheetWidth: 512,
|
||||
spritesheetHeight: 512,
|
||||
prompt:
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用单一纯绿色 #00FF00 / RGB(0,255,0) 绿幕。绿幕背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现绿色描边、绿色底板、绿色投影或绿色反光。',
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用所选单一纯色抠图背景。纯色背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现与背景色相同或相近的描边、底板、投影或反光。',
|
||||
actualPrompt:
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用单一纯绿色 #00FF00 / RGB(0,255,0) 绿幕。绿幕背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现绿色描边、绿色底板、绿色投影或绿色反光。',
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用所选单一纯色抠图背景。纯色背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现与背景色相同或相近的描边、底板、投影或反光。',
|
||||
model: 'gpt-image-2',
|
||||
provider: 'VectorEngine',
|
||||
taskId: 'task-ui-assets',
|
||||
@@ -2039,9 +2041,9 @@ describe('useImageCanvasGenerationSubmissionWorkflow', () => {
|
||||
spritesheetWidth: 512,
|
||||
spritesheetHeight: 512,
|
||||
prompt:
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用单一纯绿色 #00FF00 / RGB(0,255,0) 绿幕。绿幕背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现绿色描边、绿色底板、绿色投影或绿色反光。',
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用所选单一纯色抠图背景。纯色背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现与背景色相同或相近的描边、底板、投影或反光。',
|
||||
actualPrompt:
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用单一纯绿色 #00FF00 / RGB(0,255,0) 绿幕。绿幕背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现绿色描边、绿色底板、绿色投影或绿色反光。',
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用所选单一纯色抠图背景。纯色背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现与背景色相同或相近的描边、底板、投影或反光。',
|
||||
model: 'gpt-image-2',
|
||||
provider: 'VectorEngine',
|
||||
taskId: 'task-ui-assets',
|
||||
@@ -2087,6 +2089,8 @@ describe('useImageCanvasGenerationSubmissionWorkflow', () => {
|
||||
expect.objectContaining({
|
||||
sourceImageSrc: 'data:image/png;base64,marked-ui-design',
|
||||
model: 'gemini-3.1-flash-image-preview',
|
||||
screenColor: 'auto',
|
||||
segModel: 'birefnet',
|
||||
aspectRatio: '1:1',
|
||||
imageSize: '2K',
|
||||
generationInputs: expect.objectContaining({
|
||||
@@ -2094,7 +2098,7 @@ describe('useImageCanvasGenerationSubmissionWorkflow', () => {
|
||||
expect.objectContaining({
|
||||
title: '提取提示词',
|
||||
value:
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用单一纯绿色 #00FF00 / RGB(0,255,0) 绿幕。绿幕背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现绿色描边、绿色底板、绿色投影或绿色反光。',
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用所选单一纯色抠图背景。纯色背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现与背景色相同或相近的描边、底板、投影或反光。',
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
@@ -2109,9 +2113,9 @@ describe('useImageCanvasGenerationSubmissionWorkflow', () => {
|
||||
spritesheetWidth: 512,
|
||||
spritesheetHeight: 512,
|
||||
prompt:
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用单一纯绿色 #00FF00 / RGB(0,255,0) 绿幕。绿幕背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现绿色描边、绿色底板、绿色投影或绿色反光。',
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用所选单一纯色抠图背景。纯色背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现与背景色相同或相近的描边、底板、投影或反光。',
|
||||
actualPrompt:
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用单一纯绿色 #00FF00 / RGB(0,255,0) 绿幕。绿幕背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现绿色描边、绿色底板、绿色投影或绿色反光。',
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用所选单一纯色抠图背景。纯色背景必须平整无纹理、无渐变、无阴影、无地面、无环境、无道具,方便后续扣除背景;素材自身不要出现与背景色相同或相近的描边、底板、投影或反光。',
|
||||
model: 'gpt-image-2',
|
||||
provider: 'VectorEngine',
|
||||
taskId: 'task-ui-assets',
|
||||
@@ -2135,6 +2139,8 @@ describe('useImageCanvasGenerationSubmissionWorkflow', () => {
|
||||
await waitFor(() => {
|
||||
expect(extractEditorUiDesignAssetsMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
screenColor: 'auto',
|
||||
segModel: 'birefnet',
|
||||
referenceImageSrcs: ['generated/ref-style.png'],
|
||||
generationInputs: expect.objectContaining({
|
||||
references: expect.arrayContaining([
|
||||
|
||||
@@ -58,6 +58,8 @@ import {
|
||||
buildUiDesignAssetExtractionGenerationInputs,
|
||||
buildVideoGenerationInputs,
|
||||
CHARACTER_ANIMATION_MODEL,
|
||||
DEFAULT_EDITOR_BGFILTER_SEG_MODEL,
|
||||
DEFAULT_EDITOR_GENERATION_BACKGROUND_COLOR,
|
||||
DEFAULT_IMAGE_MODEL,
|
||||
DEFAULT_VIDEO_MODEL,
|
||||
ICON_FRAME_DISPLAY_SIZE,
|
||||
@@ -749,6 +751,8 @@ export function useImageCanvasGenerationSubmissionWorkflow({
|
||||
marks: options.marks,
|
||||
});
|
||||
}
|
||||
const screenColor = DEFAULT_EDITOR_GENERATION_BACKGROUND_COLOR;
|
||||
const segModel = DEFAULT_EDITOR_BGFILTER_SEG_MODEL;
|
||||
const generationInputs = buildUiDesignAssetExtractionGenerationInputs(
|
||||
sourceLayer,
|
||||
options.references,
|
||||
@@ -773,6 +777,8 @@ export function useImageCanvasGenerationSubmissionWorkflow({
|
||||
model: normalizeEditorImageModel(
|
||||
options.model ?? DEFAULT_IMAGE_MODEL,
|
||||
),
|
||||
screenColor,
|
||||
segModel,
|
||||
...(referenceImageSrcs.length ? { referenceImageSrcs } : {}),
|
||||
projectId,
|
||||
generationInputs,
|
||||
|
||||
+53
-18
@@ -7086,7 +7086,7 @@ html[data-mobile-keyboard-open='true'] .platform-mobile-bottom-dock {
|
||||
border: 1px solid rgba(15, 23, 42, 0.09);
|
||||
border-radius: 1.45rem;
|
||||
background: rgba(255, 255, 255, 0.97);
|
||||
padding: 0.72rem 0.82rem 0.82rem;
|
||||
padding: 0.72rem 0.82rem 0.58rem;
|
||||
color: #1f2937;
|
||||
font-size: 0.82rem;
|
||||
box-shadow:
|
||||
@@ -7178,14 +7178,20 @@ html[data-mobile-keyboard-open='true'] .platform-mobile-bottom-dock {
|
||||
.image-canvas-editor__generation-composer-footer {
|
||||
grid-column: 1 / -1;
|
||||
display: grid;
|
||||
grid-template-columns: auto minmax(0, 1fr) auto auto;
|
||||
grid-template-columns: max-content minmax(0, 1fr) max-content max-content max-content;
|
||||
align-items: center;
|
||||
gap: 0.46rem;
|
||||
gap: 0.10rem;
|
||||
justify-content: start;
|
||||
position: relative;
|
||||
border-top: 1px solid rgba(15, 23, 42, 0.06);
|
||||
padding-top: 0.44rem;
|
||||
}
|
||||
|
||||
.image-canvas-editor__generation-composer
|
||||
.image-canvas-editor__generation-composer-footer {
|
||||
padding-top: 1.1rem;
|
||||
}
|
||||
|
||||
.image-canvas-editor__generation-close {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@@ -7428,6 +7434,7 @@ button.image-canvas-editor__reference-chip:disabled {
|
||||
min-height: 2.25rem;
|
||||
height: 2.25rem;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 999px;
|
||||
background: transparent;
|
||||
@@ -7436,6 +7443,14 @@ button.image-canvas-editor__reference-chip:disabled {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.image-canvas-editor__option-cluster .platform-inline-option-button__label {
|
||||
display: inline-flex;
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.image-canvas-editor__option-cluster:hover:not(:disabled),
|
||||
.image-canvas-editor__option-cluster[aria-expanded='true'] {
|
||||
border-color: rgba(15, 23, 42, 0.08);
|
||||
@@ -7463,7 +7478,7 @@ button.image-canvas-editor__reference-chip:disabled {
|
||||
}
|
||||
|
||||
.image-canvas-editor__option-cluster--model {
|
||||
max-width: min(15.5rem, 32vw);
|
||||
max-width: 8.5rem;
|
||||
justify-self: end;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@@ -7478,11 +7493,13 @@ button.image-canvas-editor__reference-chip:disabled {
|
||||
.image-canvas-editor__option-popover-anchor--dimensions {
|
||||
grid-column: 1;
|
||||
justify-self: start;
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
.image-canvas-editor__option-popover-anchor--model {
|
||||
grid-column: 3;
|
||||
grid-column: 4;
|
||||
justify-self: end;
|
||||
width: 8.5rem;
|
||||
}
|
||||
|
||||
.image-canvas-editor__model-trigger-label {
|
||||
@@ -7862,7 +7879,7 @@ button.image-canvas-editor__reference-chip:disabled {
|
||||
}
|
||||
|
||||
.image-canvas-editor__generation-submit {
|
||||
grid-column: 4;
|
||||
grid-column: 5;
|
||||
min-width: 5.45rem;
|
||||
height: 2.25rem;
|
||||
gap: 0.4rem;
|
||||
@@ -7902,14 +7919,14 @@ button.image-canvas-editor__reference-chip:disabled {
|
||||
z-index: 13;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
grid-template-rows: auto minmax(5.8rem, auto) auto auto;
|
||||
width: min(34rem, calc(100% - 1.5rem));
|
||||
min-height: 11.2rem;
|
||||
grid-template-rows: auto minmax(5.1rem, auto) auto auto;
|
||||
width: min(42rem, calc(100% - 1.5rem));
|
||||
min-height: 10.4rem;
|
||||
gap: 0.5rem;
|
||||
border: 1px solid #cfd6df;
|
||||
border-radius: 1.35rem;
|
||||
background: #ffffff;
|
||||
padding: 0.62rem 0.7rem 0.68rem;
|
||||
padding: 0.62rem 0.7rem 0.44rem;
|
||||
color: #1f2937;
|
||||
box-shadow: 0 18px 46px rgba(15, 23, 42, 0.16);
|
||||
transform: translateX(-50%);
|
||||
@@ -7917,7 +7934,7 @@ button.image-canvas-editor__reference-chip:disabled {
|
||||
|
||||
.image-canvas-editor__character-composer
|
||||
.image-canvas-editor__generation-prompt {
|
||||
min-height: 5.8rem;
|
||||
min-height: 5.1rem;
|
||||
padding-top: 0.42rem;
|
||||
}
|
||||
|
||||
@@ -7989,24 +8006,31 @@ button.image-canvas-editor__reference-chip:disabled {
|
||||
z-index: 13;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
grid-template-rows: auto minmax(5.8rem, auto) auto auto;
|
||||
width: min(34rem, calc(100% - 1.5rem));
|
||||
min-height: 11.2rem;
|
||||
grid-template-rows: auto minmax(5.1rem, auto) auto auto;
|
||||
width: min(42rem, calc(100% - 1.5rem));
|
||||
min-height: 10.4rem;
|
||||
gap: 0.5rem;
|
||||
border: 1px solid #cfd6df;
|
||||
border-radius: 1.35rem;
|
||||
background: #ffffff;
|
||||
padding: 0.62rem 0.7rem 0.68rem;
|
||||
padding: 0.62rem 0.7rem 0.44rem;
|
||||
color: #1f2937;
|
||||
box-shadow: 0 18px 46px rgba(15, 23, 42, 0.16);
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.image-canvas-editor__icon-composer .image-canvas-editor__generation-prompt {
|
||||
min-height: 5.8rem;
|
||||
min-height: 5.1rem;
|
||||
padding-top: 0.42rem;
|
||||
}
|
||||
|
||||
.image-canvas-editor__character-composer
|
||||
.image-canvas-editor__generation-composer-footer,
|
||||
.image-canvas-editor__icon-composer
|
||||
.image-canvas-editor__generation-composer-footer {
|
||||
padding-top: 0.96rem;
|
||||
}
|
||||
|
||||
.image-canvas-editor__icon-spec-card:disabled {
|
||||
cursor: wait;
|
||||
opacity: 0.68;
|
||||
@@ -8491,6 +8515,7 @@ button.image-canvas-editor__reference-chip:disabled {
|
||||
.image-canvas-editor__quick-edit-panel.image-canvas-editor__generation-composer {
|
||||
width: min(42rem, calc(100vw - 1.5rem));
|
||||
gap: 0.18rem 0.72rem;
|
||||
padding-bottom: 0.48rem;
|
||||
}
|
||||
|
||||
.image-canvas-editor__generation-composer--quick-edit {
|
||||
@@ -8501,6 +8526,11 @@ button.image-canvas-editor__reference-chip:disabled {
|
||||
grid-template-columns: auto minmax(0, 1fr) auto auto;
|
||||
}
|
||||
|
||||
.image-canvas-editor__quick-edit-panel
|
||||
.image-canvas-editor__generation-composer-footer {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.image-canvas-editor__quick-edit-footer
|
||||
.image-canvas-editor__option-popover-anchor--model {
|
||||
grid-column: 3;
|
||||
@@ -8684,7 +8714,7 @@ button.image-canvas-editor__reference-chip:disabled {
|
||||
}
|
||||
|
||||
.image-canvas-editor__ui-extraction-model {
|
||||
grid-column: 2;
|
||||
grid-column: 4;
|
||||
justify-self: end;
|
||||
width: min(15.5rem, 42vw);
|
||||
}
|
||||
@@ -9305,10 +9335,15 @@ button.image-canvas-editor__reference-chip:disabled {
|
||||
width: auto;
|
||||
max-height: min(72vh, 31rem);
|
||||
overflow: auto;
|
||||
padding: 0.58rem;
|
||||
padding: 0.58rem 0.58rem 0.44rem;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.image-canvas-editor__character-composer
|
||||
.image-canvas-editor__generation-composer-footer {
|
||||
padding-top: 0.86rem;
|
||||
}
|
||||
|
||||
.image-canvas-editor__character-reference-row {
|
||||
padding-right: 2rem;
|
||||
}
|
||||
|
||||
@@ -780,6 +780,8 @@ describe('editorProjectClient', () => {
|
||||
prompt: '角色设定',
|
||||
kind: 'character',
|
||||
model: 'gpt-image-2',
|
||||
screenColor: '#FFD6C2',
|
||||
segModel: 'anime-seg',
|
||||
aspectRatio: '2:3',
|
||||
imageSize: '1K',
|
||||
projectId: 'editor-project-1',
|
||||
@@ -802,6 +804,8 @@ describe('editorProjectClient', () => {
|
||||
prompt: '角色设定',
|
||||
kind: 'character',
|
||||
model: 'gpt-image-2',
|
||||
screenColor: '#FFD6C2',
|
||||
segModel: 'anime-seg',
|
||||
aspectRatio: '2:3',
|
||||
imageSize: '1K',
|
||||
projectId: 'editor-project-1',
|
||||
@@ -943,6 +947,8 @@ describe('editorProjectClient', () => {
|
||||
referenceImageSrc: 'data:image/png;base64,spec',
|
||||
iconDescriptions: ['返回按钮'],
|
||||
model: 'gpt-image-2',
|
||||
screenColor: '#E6D8FF',
|
||||
segModel: 'anime-seg',
|
||||
aspectRatio: '1:1',
|
||||
imageSize: '2K',
|
||||
projectId: 'editor-project-1',
|
||||
@@ -962,6 +968,8 @@ describe('editorProjectClient', () => {
|
||||
referenceImageSrc: 'data:image/png;base64,spec',
|
||||
iconDescriptions: ['返回按钮'],
|
||||
model: 'gpt-image-2',
|
||||
screenColor: '#E6D8FF',
|
||||
segModel: 'anime-seg',
|
||||
aspectRatio: '1:1',
|
||||
imageSize: '2K',
|
||||
projectId: 'editor-project-1',
|
||||
@@ -994,9 +1002,9 @@ describe('editorProjectClient', () => {
|
||||
},
|
||||
],
|
||||
prompt:
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用单一纯绿色 #00FF00 / RGB(0,255,0) 绿幕,方便后续扣除背景;素材自身不要出现绿色描边、绿色底板或绿色阴影。',
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用单一纯色背景 中度天蓝 #7FB3FF / RGB(127,179,255),方便后续扣除背景;素材自身不要出现与背景色相同或相近的描边、底板或阴影。',
|
||||
actualPrompt:
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用单一纯绿色 #00FF00 / RGB(0,255,0) 绿幕,方便后续扣除背景;素材自身不要出现绿色描边、绿色底板或绿色阴影。',
|
||||
'仅提取被红色框框选的素材并整理成spritesheet,图集背景必须使用单一纯色背景 中度天蓝 #7FB3FF / RGB(127,179,255),方便后续扣除背景;素材自身不要出现与背景色相同或相近的描边、底板或阴影。',
|
||||
model: 'gpt-image-2',
|
||||
provider: 'VectorEngine',
|
||||
taskId: 'ui-asset-extraction-1',
|
||||
@@ -1005,6 +1013,8 @@ describe('editorProjectClient', () => {
|
||||
const result = await extractEditorUiDesignAssets({
|
||||
sourceImageSrc: 'data:image/png;base64,ui-design',
|
||||
model: 'gpt-image-2',
|
||||
screenColor: '#7FB3FF',
|
||||
segModel: 'anime-seg',
|
||||
referenceImageSrcs: ['data:image/png;base64,ui-ref'],
|
||||
projectId: 'editor-project-1',
|
||||
assetFolderId: 'project',
|
||||
@@ -1026,6 +1036,8 @@ describe('editorProjectClient', () => {
|
||||
body: JSON.stringify({
|
||||
sourceImageSrc: 'data:image/png;base64,ui-design',
|
||||
model: 'gpt-image-2',
|
||||
screenColor: '#7FB3FF',
|
||||
segModel: 'anime-seg',
|
||||
referenceImageSrcs: ['data:image/png;base64,ui-ref'],
|
||||
projectId: 'editor-project-1',
|
||||
generationInputs: {
|
||||
|
||||
@@ -162,6 +162,8 @@ export type EditorImageGenerationInput = {
|
||||
| 'ui-design'
|
||||
| 'publication-material';
|
||||
model?: string;
|
||||
screenColor?: string;
|
||||
segModel?: string;
|
||||
aspectRatio?: string;
|
||||
imageSize?: string;
|
||||
referenceImageSrcs?: string[];
|
||||
@@ -192,6 +194,8 @@ export type EditorIconSpritesheetGenerationInput = {
|
||||
referenceImageSrcs?: string[];
|
||||
iconDescriptions: string[];
|
||||
model?: string;
|
||||
screenColor?: string;
|
||||
segModel?: string;
|
||||
aspectRatio?: string;
|
||||
imageSize?: string;
|
||||
projectId?: string | null;
|
||||
@@ -203,6 +207,8 @@ export type EditorIconSpritesheetGenerationInput = {
|
||||
export type EditorUiDesignAssetExtractionInput = {
|
||||
sourceImageSrc: string;
|
||||
model?: string;
|
||||
screenColor?: string;
|
||||
segModel?: string;
|
||||
referenceImageSrcs?: string[];
|
||||
aspectRatio?: string;
|
||||
imageSize?: string;
|
||||
@@ -856,6 +862,8 @@ export async function generateEditorImage(input: EditorImageGenerationInput) {
|
||||
...(input.size ? { size: input.size } : {}),
|
||||
...(input.kind ? { kind: input.kind } : {}),
|
||||
...(input.model ? { model: input.model } : {}),
|
||||
...(input.screenColor ? { screenColor: input.screenColor } : {}),
|
||||
...(input.segModel ? { segModel: input.segModel } : {}),
|
||||
...(input.aspectRatio ? { aspectRatio: input.aspectRatio } : {}),
|
||||
...(input.imageSize ? { imageSize: input.imageSize } : {}),
|
||||
...(input.referenceImageSrcs?.length
|
||||
@@ -895,6 +903,8 @@ export async function generateEditorIconSpritesheet(
|
||||
: {}),
|
||||
iconDescriptions: input.iconDescriptions,
|
||||
model: input.model?.trim() || EDITOR_IMAGE_MODEL_NANOBANANA2,
|
||||
...(input.screenColor ? { screenColor: input.screenColor } : {}),
|
||||
...(input.segModel ? { segModel: input.segModel } : {}),
|
||||
...(input.aspectRatio ? { aspectRatio: input.aspectRatio } : {}),
|
||||
...(input.imageSize ? { imageSize: input.imageSize } : {}),
|
||||
...(input.projectId ? { projectId: input.projectId } : {}),
|
||||
@@ -922,6 +932,8 @@ export async function extractEditorUiDesignAssets(
|
||||
jsonRequest('POST', {
|
||||
sourceImageSrc: input.sourceImageSrc,
|
||||
...(input.model ? { model: input.model } : {}),
|
||||
...(input.screenColor ? { screenColor: input.screenColor } : {}),
|
||||
...(input.segModel ? { segModel: input.segModel } : {}),
|
||||
...(input.referenceImageSrcs?.length
|
||||
? { referenceImageSrcs: input.referenceImageSrcs }
|
||||
: {}),
|
||||
|
||||
Reference in New Issue
Block a user