Reuse the decoded result and report silent adoption skips
Adopting a crop result previously downloaded the full-size image a second time inside the crop layer. Pass the already-decoded image through, cutting one decode round trip. Adoption could also return without any feedback when the preview was still loading, no target was selected, or the crop/layer state changed. Those cases now show a visible message instead of failing silently.
This commit is contained in:
@@ -1,5 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## 0.7.2
|
||||
|
||||
- Adopting a result no longer decodes the full-size image a second time: the already-decoded image is reused for the crop layer, cutting one download/decode round trip.
|
||||
- Show a visible message when adoption is skipped because the preview is still loading, no target is selected, or the crop/layer state changed, instead of failing silently.
|
||||
- Bump the asset versions for the crop, comparison and result-adoption modules.
|
||||
|
||||
## 0.7.1
|
||||
|
||||
- Uploading a new source image now keeps the painted mask, undo/redo history and viewport, the same way adopting a result does; only the source pixels change. A first upload still starts with an empty mask.
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "adachi-inpaint-workbench"
|
||||
version = "0.7.1"
|
||||
version = "0.7.2"
|
||||
description = "Inline mask painting and WebUI-style inpainting nodes for ComfyUI"
|
||||
requires-python = ">=3.10"
|
||||
license = { file = "LICENSE" }
|
||||
|
||||
+3
-1
@@ -118,7 +118,9 @@ export class ImageCompareView {
|
||||
|
||||
async adopt() {
|
||||
this.refreshTargets();
|
||||
if (!this.ready || !this.targetSelect.value || this.busy) return;
|
||||
if (this.busy) return;
|
||||
if (!this.ready) { this.status(T("The result preview is still loading"), true); return; }
|
||||
if (!this.targetSelect.value) { this.status(T("Select an inline mask to adopt into"), true); return; }
|
||||
const target = this.targetSelect.value, result = this.results[this.index];
|
||||
this.busy = true; this.updateButton(); this.status(T("Setting the result as the new source image…"));
|
||||
try {
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { app } from "../../scripts/app.js";
|
||||
import { api } from "../../scripts/api.js";
|
||||
import { ImageCompareView } from "./compare.js?v=0.5.9";
|
||||
import { ImageCompareView } from "./compare.js?v=0.7.2";
|
||||
import { appendComparison } from "./compare_history.js?v=0.5.8";
|
||||
import { routeWheelOutsideImage } from "./wheel_routing.js";
|
||||
import { T } from "./i18n.js";
|
||||
|
||||
@@ -19,6 +19,9 @@ const ZH = {
|
||||
"This result belongs to another crop; generate a result for the current region": "该结果来自其他选区,请为当前选区重新生成",
|
||||
"Result dimensions must match the selected crop": "结果宽高必须与当前裁切区域一致",
|
||||
"The crop changed while adopting the result": "采用过程中选区已改变,请重新生成结果",
|
||||
"The result was not applied; the crop or layer state changed": "结果未应用,选区或图层状态已改变",
|
||||
"The result preview is still loading": "结果预览仍在加载中",
|
||||
"Select an inline mask to adopt into": "请选择要回填的内联蒙版",
|
||||
"Painting tools and mask settings": "绘图工具与蒙版设置",
|
||||
"Browser draft storage was full. The source was saved as an input file; the image, masks and layers are preserved.": "浏览器草稿空间不足,已将原图保存为图片文件;图像、蒙版和图层均已保留。",
|
||||
"Editing mode": "编辑模式",
|
||||
|
||||
+7
-5
@@ -1,7 +1,7 @@
|
||||
import { CROP_PRESETS, cropAt } from "./crop_geometry.js?v=0.6.2";
|
||||
import { T } from "./i18n.js";
|
||||
import { syncCropDimensions } from "./parameter_bridge.js?v=0.6.4";
|
||||
import { installResultAdoption } from "./result_adoption.js?v=0.6.4";
|
||||
import { installResultAdoption } from "./result_adoption.js?v=0.7.2";
|
||||
|
||||
const fields = ["mask", "baseMask", "history", "future", "lastMask", "dirty"];
|
||||
const canvas = (w, h) =>
|
||||
@@ -505,7 +505,7 @@ export class InlineCropController {
|
||||
this.sync();
|
||||
this.editor.schedule();
|
||||
}
|
||||
async accept(record, {allowBusy = false} = {}) {
|
||||
async accept(record, {allowBusy = false, image = null} = {}) {
|
||||
if (
|
||||
this.editor.destroyed ||
|
||||
this.mode !== "crop" ||
|
||||
@@ -520,7 +520,7 @@ export class InlineCropController {
|
||||
this.resultTimer = setTimeout(() => {
|
||||
const next = this.pendingResult;
|
||||
this.pendingResult = null;
|
||||
this.accept(next).catch((error) =>
|
||||
this.accept(next, {allowBusy}).catch((error) =>
|
||||
this.editor.status(error.message, true),
|
||||
);
|
||||
}, 50);
|
||||
@@ -531,7 +531,9 @@ export class InlineCropController {
|
||||
: record.image.filename;
|
||||
if (name === this.widgets.layer_image.value) return;
|
||||
const version = ++this.acceptVersion;
|
||||
const image = await load(this.imageUrl(name));
|
||||
// The adoption path already decoded this image once; reuse it instead of
|
||||
// downloading and decoding the full-size result a second time.
|
||||
const decoded = image || await load(this.imageUrl(name));
|
||||
if (
|
||||
this.editor.destroyed ||
|
||||
version !== this.acceptVersion ||
|
||||
@@ -539,7 +541,7 @@ export class InlineCropController {
|
||||
this.mode !== "crop"
|
||||
)
|
||||
return;
|
||||
this.layer = image;
|
||||
this.layer = decoded;
|
||||
this.widgets.layer_image.value = name;
|
||||
if (!this.contexts.blend && this.target !== "blend")
|
||||
await this.makeBlend(this.widgets.blend_data.value);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { InlineMaskEditor } from "./editor.js?v=0.7.1";
|
||||
import { installInpaintWorkbench } from "./inpaint_node.js?v=0.6.1";
|
||||
import { bindWidgetToNodeWidth } from "./widget_layout.js?v=0.5.5";
|
||||
import { routeWheelOutsideImage } from "./wheel_routing.js";
|
||||
import { InlineCropController } from "./inline_crop.js?v=0.6.9";
|
||||
import { InlineCropController } from "./inline_crop.js?v=0.7.2";
|
||||
import { canStoreDraft, prepareInlineDraft, syncInlineWidgets } from "./draft_guard.js?v=0.6.3";
|
||||
import { T } from "./i18n.js";
|
||||
import { removeLegacyFeedback } from "./legacy_feedback.js?v=0.6.4";
|
||||
|
||||
@@ -40,9 +40,12 @@ export function installResultAdoption(node, crop) {
|
||||
throw Error(T("The crop changed while adopting the result"));
|
||||
}
|
||||
const descriptor = {filename:uploaded.name, subfolder:uploaded.subfolder || "", type:"input"};
|
||||
await crop.accept({job:region.job, image:descriptor}, {allowBusy:true});
|
||||
await crop.accept({job:region.job, image:descriptor}, {allowBusy:true, image});
|
||||
const name = descriptor.subfolder ? `${descriptor.subfolder}/${descriptor.filename}` : descriptor.filename;
|
||||
if (crop.widgets.layer_image.value !== name) throw Error(T("The crop changed while adopting the result"));
|
||||
if (crop.widgets.layer_image.value !== name) {
|
||||
// accept() may have skipped silently (busy / changed job / duplicate).
|
||||
throw Error(T("The result was not applied; the crop or layer state changed"));
|
||||
}
|
||||
editor.status("");
|
||||
} finally {
|
||||
URL.revokeObjectURL(objectUrl); crop.busy = false; crop.sync();
|
||||
|
||||
Reference in New Issue
Block a user