fix image preview
This commit is contained in:
+146
-93
@@ -89,6 +89,31 @@ app.registerExtension({
|
||||
// 创建预览图像对象
|
||||
this._preview_image = new Image();
|
||||
this._preview_path = null;
|
||||
|
||||
// 检查是否有image_data小部件,如果没有则创建一个隐藏的
|
||||
let image_data_widget = this.widgets.find(w => w.name === "image_data");
|
||||
if (!image_data_widget) {
|
||||
image_data_widget = this.addWidget("text", "image_data", "", null);
|
||||
image_data_widget.hidden = true;
|
||||
logDebug("创建隐藏的image_data小部件");
|
||||
} else {
|
||||
logDebug("找到现有的image_data小部件");
|
||||
}
|
||||
|
||||
// 保存对image_data小部件的引用
|
||||
this._image_data_widget = image_data_widget;
|
||||
|
||||
// 设置图像加载事件处理
|
||||
this._preview_image.onload = () => {
|
||||
logDebug(`图像加载成功: ${this._preview_image.width}x${this._preview_image.height}`);
|
||||
this.setDirtyCanvas(true, true);
|
||||
};
|
||||
|
||||
this._preview_image.onerror = (err) => {
|
||||
logDebug(`图像加载失败`);
|
||||
logDetailedDebug("加载错误:", err);
|
||||
};
|
||||
|
||||
logDebug("创建预览图像对象");
|
||||
|
||||
// 使节点可序列化
|
||||
@@ -145,62 +170,87 @@ app.registerExtension({
|
||||
ctx.strokeRect(previewX, previewY, previewWidth, previewHeight);
|
||||
logDebug("绘制预览区域背景");
|
||||
|
||||
// 如果有预览图像且已加载完成
|
||||
if (this._preview_image && this._preview_image.complete && this._preview_image.width > 0) {
|
||||
logDebug(`有预览图像: ${this._preview_image.width}x${this._preview_image.height}`);
|
||||
try {
|
||||
// 计算图像显示大小,保持比例
|
||||
const img = this._preview_image;
|
||||
const imgRatio = img.width / img.height;
|
||||
let drawWidth, drawHeight;
|
||||
|
||||
if (imgRatio > previewWidth / previewHeight) {
|
||||
// 图像较宽,以宽度为限
|
||||
drawWidth = previewWidth - 10;
|
||||
drawHeight = drawWidth / imgRatio;
|
||||
logDebug(`图像较宽,调整为 ${drawWidth}x${drawHeight}`);
|
||||
} else {
|
||||
// 图像较高,以高度为限
|
||||
drawHeight = previewHeight - 10;
|
||||
drawWidth = drawHeight * imgRatio;
|
||||
logDebug(`图像较高,调整为 ${drawWidth}x${drawHeight}`);
|
||||
// 获取image_data小部件中的值
|
||||
const imageData = this._image_data_widget ? this._image_data_widget.value : "";
|
||||
|
||||
// 如果有图像数据,则加载并显示
|
||||
if (imageData && imageData !== "") {
|
||||
logDebug("从image_data小部件获取到数据");
|
||||
|
||||
// 如果图像源不是当前的数据,则更新
|
||||
if (this._preview_image.src !== imageData) {
|
||||
logDebug("更新预览图像源");
|
||||
this._preview_image.src = imageData;
|
||||
}
|
||||
|
||||
// 如果有预览图像且已加载完成
|
||||
if (this._preview_image && this._preview_image.complete && this._preview_image.width > 0) {
|
||||
logDebug(`有预览图像: ${this._preview_image.width}x${this._preview_image.height}`);
|
||||
try {
|
||||
// 计算图像显示大小,保持比例
|
||||
const img = this._preview_image;
|
||||
const imgRatio = img.width / img.height;
|
||||
let drawWidth, drawHeight;
|
||||
|
||||
if (imgRatio > previewWidth / previewHeight) {
|
||||
// 图像较宽,以宽度为限
|
||||
drawWidth = previewWidth - 10;
|
||||
drawHeight = drawWidth / imgRatio;
|
||||
logDebug(`图像较宽,调整为 ${drawWidth}x${drawHeight}`);
|
||||
} else {
|
||||
// 图像较高,以高度为限
|
||||
drawHeight = previewHeight - 10;
|
||||
drawWidth = drawHeight * imgRatio;
|
||||
logDebug(`图像较高,调整为 ${drawWidth}x${drawHeight}`);
|
||||
}
|
||||
|
||||
// 计算居中位置
|
||||
const drawX = previewX + (previewWidth - drawWidth) / 2;
|
||||
const drawY = previewY + (previewHeight - drawHeight) / 2;
|
||||
logDebug(`绘制位置: x=${drawX}, y=${drawY}`);
|
||||
|
||||
// 绘制预览图像
|
||||
ctx.drawImage(img, drawX, drawY, drawWidth, drawHeight);
|
||||
logDebug("绘制预览图像完成");
|
||||
|
||||
// 显示图像尺寸
|
||||
ctx.fillStyle = "#ffffff";
|
||||
ctx.font = "12px Arial";
|
||||
ctx.textAlign = "left";
|
||||
ctx.fillText(`${img.naturalWidth}x${img.naturalHeight}`,
|
||||
previewX + 5, previewY + previewHeight - 5);
|
||||
logDebug("绘制图像尺寸信息");
|
||||
} catch (error) {
|
||||
logDebug(`绘制图像错误: ${error.message}`);
|
||||
// 显示错误信息
|
||||
ctx.fillStyle = "#ff5555";
|
||||
ctx.font = "12px Arial";
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillText("图像加载或绘制出错",
|
||||
previewX + previewWidth/2, previewY + previewHeight/2);
|
||||
ctx.textAlign = "left";
|
||||
}
|
||||
} else {
|
||||
logDebug("无预览图像或图像未加载完成");
|
||||
if (this._preview_image) {
|
||||
logDetailedDebug("预览图像状态:", {
|
||||
complete: this._preview_image.complete,
|
||||
width: this._preview_image.width,
|
||||
src: this._preview_image.src ? this._preview_image.src.substring(0, 50) + "..." : ""
|
||||
});
|
||||
}
|
||||
|
||||
// 计算居中位置
|
||||
const drawX = previewX + (previewWidth - drawWidth) / 2;
|
||||
const drawY = previewY + (previewHeight - drawHeight) / 2;
|
||||
logDebug(`绘制位置: x=${drawX}, y=${drawY}`);
|
||||
|
||||
// 绘制预览图像
|
||||
ctx.drawImage(img, drawX, drawY, drawWidth, drawHeight);
|
||||
logDebug("绘制预览图像完成");
|
||||
|
||||
// 显示图像尺寸
|
||||
ctx.fillStyle = "#ffffff";
|
||||
ctx.font = "12px Arial";
|
||||
ctx.textAlign = "left";
|
||||
ctx.fillText(`${img.naturalWidth}x${img.naturalHeight}`,
|
||||
previewX + 5, previewY + previewHeight - 5);
|
||||
logDebug("绘制图像尺寸信息");
|
||||
} catch (error) {
|
||||
logDebug(`绘制图像错误: ${error.message}`);
|
||||
// 显示错误信息
|
||||
ctx.fillStyle = "#ff5555";
|
||||
ctx.font = "12px Arial";
|
||||
// 没有图像时显示提示
|
||||
ctx.fillStyle = "#aaaaaa";
|
||||
ctx.font = "14px Arial";
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillText("图像加载或绘制出错",
|
||||
previewX + previewWidth/2, previewY + previewHeight/2);
|
||||
ctx.fillText("图片正在加载...",
|
||||
previewX + previewWidth/2, previewY + previewHeight/2);
|
||||
ctx.textAlign = "left";
|
||||
logDebug("绘制加载提示文本");
|
||||
}
|
||||
} else {
|
||||
logDebug("无预览图像或图像未加载完成");
|
||||
if (this._preview_image) {
|
||||
logDetailedDebug("预览图像状态:", {
|
||||
complete: this._preview_image.complete,
|
||||
width: this._preview_image.width,
|
||||
src: this._preview_image.src
|
||||
});
|
||||
}
|
||||
logDebug("无图像数据");
|
||||
|
||||
// 没有图像时显示提示
|
||||
ctx.fillStyle = "#aaaaaa";
|
||||
@@ -242,50 +292,53 @@ app.registerExtension({
|
||||
// 输出消息
|
||||
logDetailedDebug("输出消息:", message.outputs);
|
||||
|
||||
// 检查是否有图像路径输出
|
||||
const imagePath = message.outputs.image_path;
|
||||
if (!imagePath || typeof imagePath !== "string") {
|
||||
logDebug("无效的图像路径");
|
||||
return;
|
||||
}
|
||||
|
||||
logDebug(`获取到图像路径: ${imagePath}`);
|
||||
|
||||
// 如果路径无效或与上次相同,则不重新加载
|
||||
if (imagePath.startsWith("错误:") || imagePath === this._preview_path) {
|
||||
logDebug("图像路径无效或与上次相同");
|
||||
return;
|
||||
}
|
||||
|
||||
this._preview_path = imagePath;
|
||||
logDebug(`设置新的预览路径: ${this._preview_path}`);
|
||||
|
||||
// 创建正确的预览URL
|
||||
const previewUrl = `/view?filename=${encodeURIComponent(imagePath)}&ts=${Date.now()}`;
|
||||
logDebug(`预览URL: ${previewUrl}`);
|
||||
|
||||
// 设置图像加载事件
|
||||
this._preview_image.onload = () => {
|
||||
logDebug(`图像加载成功: ${this._preview_image.width}x${this._preview_image.height}`);
|
||||
// 检查是否有图像数据输出
|
||||
const imageData = message.outputs.image_data;
|
||||
if (imageData && typeof imageData === "string" && imageData !== "") {
|
||||
logDebug("发现image_data输出");
|
||||
|
||||
// 更新image_data小部件
|
||||
if (this._image_data_widget) {
|
||||
this._image_data_widget.value = imageData;
|
||||
logDebug("已更新image_data小部件");
|
||||
} else {
|
||||
logDebug("没有找到image_data小部件");
|
||||
}
|
||||
|
||||
// 强制请求重绘
|
||||
this.setDirtyCanvas(true, true);
|
||||
};
|
||||
|
||||
this._preview_image.onerror = (err) => {
|
||||
logDebug(`图像加载失败`);
|
||||
logDetailedDebug("加载错误:", err);
|
||||
// 尝试使用备选URL加载
|
||||
const alternativeUrl = `/output/${encodeURIComponent(imagePath)}?ts=${Date.now()}`;
|
||||
logDebug(`尝试备选URL: ${alternativeUrl}`);
|
||||
this._preview_image.src = alternativeUrl;
|
||||
};
|
||||
|
||||
// 加载图像
|
||||
this._preview_image.src = previewUrl;
|
||||
logDebug(`开始加载图像: ${this._preview_image.src}`);
|
||||
|
||||
// 强制请求重绘
|
||||
this.setDirtyCanvas(true, true);
|
||||
logDebug("请求画布更新");
|
||||
logDebug("请求画布更新");
|
||||
} else {
|
||||
// 检查是否有图像路径输出
|
||||
const imagePath = message.outputs.image_path;
|
||||
if (!imagePath || typeof imagePath !== "string") {
|
||||
logDebug("无效的图像路径或数据");
|
||||
return;
|
||||
}
|
||||
|
||||
logDebug(`获取到图像路径: ${imagePath}`);
|
||||
|
||||
// 如果路径无效或与上次相同,则不重新加载
|
||||
if (imagePath.startsWith("错误:") || imagePath === this._preview_path) {
|
||||
logDebug("图像路径无效或与上次相同");
|
||||
return;
|
||||
}
|
||||
|
||||
this._preview_path = imagePath;
|
||||
logDebug(`设置新的预览路径: ${this._preview_path}`);
|
||||
|
||||
// 创建正确的预览URL
|
||||
const previewUrl = `/view?filename=${encodeURIComponent(imagePath)}&ts=${Date.now()}`;
|
||||
logDebug(`预览URL: ${previewUrl}`);
|
||||
|
||||
// 加载图像
|
||||
this._preview_image.src = previewUrl;
|
||||
logDebug(`开始加载图像: ${this._preview_image.src}`);
|
||||
|
||||
// 强制请求重绘
|
||||
this.setDirtyCanvas(true, true);
|
||||
logDebug("请求画布更新");
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
// KLingAI扩展入口点
|
||||
import './image_downloader_preview.js';
|
||||
|
||||
console.log("[JM-KLingAI] 扩展入口点加载完成");
|
||||
// 记录扩展加载信息
|
||||
console.log("[JM-KLingAI] 扩展入口点加载完成,版本 1.0.1");
|
||||
+19
-11
@@ -29,6 +29,7 @@ class KLingAIImageDownloader:
|
||||
self.last_downloaded_image = None
|
||||
self.last_image_path = None
|
||||
self.preview_available = False # 标记预览是否可用
|
||||
self.image_data = "" # 存储base64图片数据
|
||||
print(f"初始化KLingAIImageDownloader,输出目录: {self.default_output_dir}")
|
||||
|
||||
@classmethod
|
||||
@@ -48,15 +49,17 @@ class KLingAIImageDownloader:
|
||||
"multiline": False,
|
||||
"placeholder": "Optional: Custom output directory path within outputs folder"
|
||||
}),
|
||||
# 隐藏字段用于存储base64图片数据
|
||||
"image_data": ("STRING", {"default": "", "multiline": True, "visible": False}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE", "STRING", "STRING")
|
||||
RETURN_NAMES = ("IMAGE", "image_path", "image_url")
|
||||
RETURN_TYPES = ("IMAGE", "STRING", "STRING", "STRING")
|
||||
RETURN_NAMES = ("IMAGE", "image_path", "image_url", "image_data")
|
||||
FUNCTION = "download_image"
|
||||
CATEGORY = "JM-KLingAI-API"
|
||||
OUTPUT_NODE = True # 标记为可作为终端节点的节点
|
||||
OUTPUT_IS_LIST = (False, False, False) # 指示输出不是列表
|
||||
OUTPUT_IS_LIST = (False, False, False, False) # 指示输出不是列表
|
||||
|
||||
def get_next_sequence_number(self, directory, filename_prefix):
|
||||
"""
|
||||
@@ -107,7 +110,7 @@ class KLingAIImageDownloader:
|
||||
img_str = base64.b64encode(buffered.getvalue()).decode("utf-8")
|
||||
return f"data:image/png;base64,{img_str}"
|
||||
|
||||
def download_image(self, image_url, filename_prefix="KLingAI", custom_output_dir=""):
|
||||
def download_image(self, image_url, filename_prefix="KLingAI", custom_output_dir="", image_data=""):
|
||||
"""
|
||||
Download image from URL and save to local directory
|
||||
"""
|
||||
@@ -120,7 +123,7 @@ class KLingAIImageDownloader:
|
||||
print(error_msg)
|
||||
# 创建小的空白图像用于显示错误信息
|
||||
empty_tensor = torch.zeros((1, 64, 64, 3), dtype=torch.float32)
|
||||
return (empty_tensor, error_msg, image_url)
|
||||
return (empty_tensor, error_msg, image_url, "")
|
||||
|
||||
if not filename_prefix:
|
||||
filename_prefix = "KLingAI"
|
||||
@@ -195,6 +198,11 @@ class KLingAIImageDownloader:
|
||||
# 存储最后下载的图像以便在UI中显示
|
||||
self.last_downloaded_image = pil_image
|
||||
|
||||
# 转换为base64格式用于前端显示
|
||||
base64_data = self.image_to_base64(pil_image)
|
||||
self.image_data = base64_data
|
||||
print(f"生成base64图片数据,长度: {len(base64_data) if base64_data else 0}")
|
||||
|
||||
# 转换为numpy数组,并规范化到0-1范围
|
||||
image_array = np.array(pil_image).astype(np.float32) / 255.0
|
||||
|
||||
@@ -203,31 +211,31 @@ class KLingAIImageDownloader:
|
||||
print(f"转换为PyTorch张量,形状: {image_tensor.shape}")
|
||||
|
||||
print(f"成功加载图片,准备返回 - 张量形状: {image_tensor.shape}")
|
||||
return (image_tensor, rel_filepath, image_url)
|
||||
return (image_tensor, rel_filepath, image_url, base64_data)
|
||||
except Exception as e:
|
||||
print(f"图片加载错误: {str(e)}")
|
||||
# 创建小的空白图像
|
||||
empty_tensor = torch.zeros((1, 64, 64, 3), dtype=torch.float32)
|
||||
return (empty_tensor, rel_filepath, image_url)
|
||||
return (empty_tensor, rel_filepath, image_url, "")
|
||||
|
||||
except ValueError as ve:
|
||||
error_msg = f"参数错误: {str(ve)}"
|
||||
print(error_msg)
|
||||
# 创建小的空白图像
|
||||
empty_tensor = torch.zeros((1, 64, 64, 3), dtype=torch.float32)
|
||||
return (empty_tensor, error_msg, image_url)
|
||||
return (empty_tensor, error_msg, image_url, "")
|
||||
except requests.exceptions.RequestException as re:
|
||||
error_msg = f"下载错误: {str(re)}"
|
||||
print(error_msg)
|
||||
# 创建小的空白图像
|
||||
empty_tensor = torch.zeros((1, 64, 64, 3), dtype=torch.float32)
|
||||
return (empty_tensor, error_msg, image_url)
|
||||
return (empty_tensor, error_msg, image_url, "")
|
||||
except Exception as e:
|
||||
error_msg = f"图片下载错误: {str(e)}"
|
||||
print(error_msg)
|
||||
# 创建小的空白图像
|
||||
empty_tensor = torch.zeros((1, 64, 64, 3), dtype=torch.float32)
|
||||
return (empty_tensor, error_msg, image_url)
|
||||
return (empty_tensor, error_msg, image_url, "")
|
||||
|
||||
def save_image_preview_info(self, filepath):
|
||||
"""
|
||||
@@ -274,6 +282,6 @@ class KLingAIImageDownloader:
|
||||
|
||||
# 确保节点可以在没有连接的情况下运行
|
||||
@classmethod
|
||||
def IS_CHANGED(cls, image_url, filename_prefix="KLingAI", custom_output_dir=""):
|
||||
def IS_CHANGED(cls, image_url, filename_prefix="KLingAI", custom_output_dir="", image_data=""):
|
||||
# 返回当前时间,确保节点总是执行
|
||||
return time.time()
|
||||
Reference in New Issue
Block a user