SaveImagePlus node adds output workflow and preview switch
This commit is contained in:
@@ -70,7 +70,7 @@ When this error has occurred, please check the network environment.
|
||||
## Update
|
||||
<font size="4">**If the dependency package error after updating, please reinstall the relevant dependency packages. </font><br />
|
||||
|
||||
|
||||
* [SaveImagePlus](#SaveImagePlus) node adds the output workflow to the json function, supports ```%date``` and ```%time``` to manually join the time to path and filename, and adds the preview switch.
|
||||
* Commit [SaveImagePlus](#SaveImagePlus) node,It can customize the directory where the picture is saved, add a timestamp to the file name, select the save format, set the image compression rate, set whether to save the workflow, and optionally add invisible watermarks to the picture.
|
||||
* Commit [AddBlindWaterMark](#AddBlindWaterMark), [ShowBlindWaterMark](#ShowBlindWaterMark) nodes, Add invisible watermark and decoded watermark to the picture. Commit [CreateQRCode](#CreateQRCode), [DecodeQRCode](#DecodeQRCode) nodes, It can generate two-dimensional code pictures and decode two-dimensional codes.
|
||||
* [ImageScaleRestoreV2](#ImageScaleRestoreV2), [ImageScaleByAspectRatioV2](#ImageScaleByAspectRatioV2), [ImageAutoCropV2](#ImageAutoCropV2) nodes add options for ```width``` and ```height```, which can specify width or height as fixed values.
|
||||
@@ -1099,18 +1099,25 @@ Node Options:
|
||||
|
||||
|
||||
### <a id="table1">SaveImagePlus</a>
|
||||
Enhanced save image node. You can customize the directory where the picture is saved, add a timestamp to the file name, select the save format, set the image compression rate, set whether to save the workflow, and optionally add invisible watermarks to the picture. (Add information in a way that is invisible to the naked eye, and use the ```ShowBlindWaterMark``` node to decode the watermark. )
|
||||

|
||||
Enhanced save image node. You can customize the directory where the picture is saved, add a timestamp to the file name, select the save format, set the image compression rate, set whether to save the workflow, and optionally add invisible watermarks to the picture. (Add information in a way that is invisible to the naked eye, and use the ```ShowBlindWaterMark``` node to decode the watermark). Optionally output the json file of the workflow.
|
||||
|
||||
Node Options:
|
||||

|
||||

|
||||
* iamge: The input image.
|
||||
* custom_path: User-defined directory, enter the directory name in the correct format. If empty, it is saved in the default output directory of ComfyUI. Note that when the file is set to save to the user directory, the picture preview cannot be seen, which is normal.
|
||||
* filename_prefix: The prefix of file name.
|
||||
* custom_path<sup>*</sup>: User-defined directory, enter the directory name in the correct format. If empty, it is saved in the default output directory of ComfyUI.
|
||||
* filename_prefix<sup>*</sup>: The prefix of file name.
|
||||
* timestamp: Timestamp the file name, opting for date, time to seconds, and time to milliseconds.
|
||||
* format: The format of image save. Currently available in ```png``` and ```jpg```. Note that only png format is supported for RGBA mode pictures.
|
||||
* quality: Image quality, the value range 10-100, the higher the value, the better the picture quality, the volume of the file also correspondingly increases.
|
||||
* meta_data: Whether to save metadata to png file, that is workflow information. Set this to false if you do not want the workflow to be leaked.
|
||||
* blind_watermark: The text entered here (does not support multilingualism) will be converted into a QR code and saved as an invisible watermark. Use ```ShowBlindWaterMark``` node can decode watermarks. Note that pictures with watermarks are recommended to be saved in png format, and lower-quality jpg format will cause watermark information to be lost.
|
||||
* save_workflow_as_json: Whether the output workflow is a json file at the same time (the output json is in the same directory as the picture).
|
||||
* preview: Preview switch.
|
||||
|
||||
<sup>*</sup> Enter```%date``` for the current date (YY-mm-dd) and ```%time``` for the current time (HH-MM-SS). You can enter ```/``` for subdirectories. For example, ```%date_%tiem/name``` will output the image to the ```YY-mm-dd_HH-MM-SS``` folder, with name as the file name prefix.
|
||||
|
||||
|
||||
|
||||
### <a id="table1">AddBlindWaterMark</a>
|
||||

|
||||
|
||||
+10
-6
@@ -70,7 +70,7 @@ git clone https://github.com/chflame163/ComfyUI_LayerStyle.git
|
||||
## 更新说明
|
||||
<font size="4">**如果本插件更新后出现依赖包错误,请重新安装相关依赖包。
|
||||
|
||||
|
||||
* [SaveImagePlus](#SaveImagePlus)节点增加输出工作流为json功能,支持使用```%date```和```%time```手动为保存路径和文件名加入时间,增加预览开关。
|
||||
* 添加 [SaveImagePlus](#SaveImagePlus)节点,可自定义保存图片的目录,文件名增加时间戳,选择保存格式,设置图片压缩率,设置是否保存工作流,以及可选给图片添加隐形水印。
|
||||
* 添加 [AddBlindWaterMark](#AddBlindWaterMark), [ShowBlindWaterMark](#ShowBlindWaterMark)节点,为图片增加隐形水印和解码水印。添加 [CreateQRCode](#CreateQRCode), [DecodeQRCode](#DecodeQRCode)节点,可生成二维码图片和解码二维码。
|
||||
* [ImageScaleRestoreV2](#ImageScaleRestoreV2), [ImageScaleByAspectRatioV2](#ImageScaleByAspectRatioV2), [ImageAutoCropV2](#ImageAutoCropV2)节点增加```width```和```height```选项,可指定宽度或高度为固定值。
|
||||
@@ -1087,18 +1087,23 @@ cropped_mask: 裁切后的遮罩。
|
||||
|
||||
|
||||
### <a id="table1">SaveImagePlus</a>
|
||||
增强版的保存图片节点。可自定义保存图片的目录,文件名增加时间戳,选择保存格式,设置图片压缩率,设置是否保存工作流,以及可选给图片添加隐形水印。(以肉眼无法觉察的方式添加信息,使用配套的```ShowBlindWaterMark```节点可以解码水印。)
|
||||

|
||||
增强版的保存图片节点。可自定义保存图片的目录,文件名增加时间戳,选择保存格式,设置图片压缩率,设置是否保存工作流,以及可选给图片添加隐形水印(以肉眼无法觉察的方式添加信息,使用配套的```ShowBlindWaterMark```节点可以解码水印)。可选择是否同时输出工作流的json文件。
|
||||
|
||||
节点选项说明:
|
||||

|
||||

|
||||
* iamge: 输入的图片。
|
||||
* custom_path: 用户自定义目录,请按正确的格式输入目录名。如果为空则保存在ComfyUI默认的output目录。注意当文件被设置为保存到用户目录时,无法看到图片预览,这是正常现象。
|
||||
* filename_prefix:文件名前缀。
|
||||
* custom_path<sup>*</sup>: 用户自定义目录,请按正确的格式输入目录名。如果为空则保存在ComfyUI默认的output目录。
|
||||
* filename_prefix<sup>*</sup>:文件名前缀。。
|
||||
* timestamp: 为文件名加上时间戳,可选择日期、时间到秒和时间到毫秒。
|
||||
* format:图片保存格式。目前提供png和jpg两种。注意RGBA模式的图片仅支持png格式。
|
||||
* quality:图片质量,数值范围10-100,数值越高,图片质量越好,文件的体积也对应增大。
|
||||
* meta_data:是否保存元数据即工作流信息到png文件。如果不希望泄露工作流,请把这里设置为false。
|
||||
* blind_watermark:这里输入的文字(不支持多语言)将被转换为二维码作为隐形水印保存,使用```ShowBlindWaterMark```节点可以解码水印。注意有水印的图片建议保存为png格式,质量较低的jpg格式将导致水印信息丢失。
|
||||
* save_workflow_as_json: 是否同时输出工作流为json文件(输出的json与图片在同一目录)。
|
||||
* preview: 预览开关。
|
||||
|
||||
<sup>*</sup>输入```%date```表示当前日期(YY-mm-dd),```%time```表示当前时间(HH-MM-SS)。可以输入```/```表示子目录。例如```%date_%tiem/name``` 将输出图片到```YY-mm-dd_HH-MM-SS```文件夹下,以name为文件名前缀。
|
||||
|
||||
### <a id="table1">AddBlindWaterMark</a>
|
||||

|
||||
@@ -1134,7 +1139,6 @@ cropped_mask: 裁切后的遮罩。
|
||||
|
||||
|
||||
|
||||
|
||||
# <a id="table1">LayerMask</a>
|
||||

|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 108 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 132 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
+68
-17
@@ -20,9 +20,11 @@ class SaveImagePlus:
|
||||
"filename_prefix": ("STRING", {"default": "comfyui"}),
|
||||
"timestamp": (["None", "second", "millisecond"],),
|
||||
"format": (["png", "jpg"],),
|
||||
"quality": ("INT", {"default": 100, "min": 10, "max": 100, "step": 1}),
|
||||
"quality": ("INT", {"default": 80, "min": 10, "max": 100, "step": 1}),
|
||||
"meta_data": ("BOOLEAN", {"default": False}),
|
||||
"blind_watermark": ("STRING", {"default": ""}),
|
||||
"save_workflow_as_json": ("BOOLEAN", {"default": False}),
|
||||
"preview": ("BOOLEAN", {"default": False}),
|
||||
},
|
||||
"hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"},
|
||||
}
|
||||
@@ -33,12 +35,19 @@ class SaveImagePlus:
|
||||
CATEGORY = '😺dzNodes/LayerUtility'
|
||||
|
||||
def save_image_plus(self, images, custom_path, filename_prefix, timestamp, format, quality,
|
||||
meta_data, blind_watermark, prompt=None, extra_pnginfo=None):
|
||||
|
||||
meta_data, blind_watermark, preview, save_workflow_as_json,
|
||||
prompt=None, extra_pnginfo=None):
|
||||
|
||||
now = datetime.datetime.now()
|
||||
custom_path = custom_path.replace("%date", now.strftime("%Y-%m-%d"))
|
||||
custom_path = custom_path.replace("%time", now.strftime("%H-%M-%S"))
|
||||
filename_prefix = filename_prefix.replace("%date", now.strftime("%Y-%m-%d"))
|
||||
filename_prefix = filename_prefix.replace("%time", now.strftime("%H-%M-%S"))
|
||||
filename_prefix += self.prefix_append
|
||||
full_output_folder, filename, counter, subfolder, filename_prefix = folder_paths.get_save_image_path(filename_prefix, self.output_dir, images[0].shape[1], images[0].shape[0])
|
||||
results = list()
|
||||
temp_sub_dir = generate_random_name('_savepreview_', '_temp', 16)
|
||||
temp_dir = os.path.join(folder_paths.get_temp_directory(), temp_sub_dir)
|
||||
for image in images:
|
||||
i = 255. * image.cpu().numpy()
|
||||
img = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8))
|
||||
@@ -77,39 +86,81 @@ class SaveImagePlus:
|
||||
metadata.add_text(x, json.dumps(extra_pnginfo[x]))
|
||||
|
||||
if timestamp == "millisecond":
|
||||
file = f'{filename}_{datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S-%f")[:-3]}.{format}'
|
||||
file = f'{filename}_{now.strftime("%Y-%m-%d_%H-%M-%S-%f")[:-3]}'
|
||||
elif timestamp == "second":
|
||||
file = f'{filename}_{datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}.{format}'
|
||||
file = f'{filename}_{now.strftime("%Y-%m-%d_%H-%M-%S")}'
|
||||
else:
|
||||
file = f'{filename}_{counter:05}.{format}'
|
||||
file = f'{filename}_{counter:05}'
|
||||
|
||||
|
||||
preview_filename = ""
|
||||
if not os.path.exists(custom_path):
|
||||
if custom_path != "":
|
||||
raise FileNotFoundError("custom_path is not a valid path")
|
||||
else:
|
||||
full_output_folder = os.path.normpath(custom_path)
|
||||
# save preview image to temp_dir
|
||||
if os.path.isdir(temp_dir):
|
||||
shutil.rmtree(temp_dir)
|
||||
try:
|
||||
os.makedirs(temp_dir)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
log(f"Error: {NODE_NAME} skipped, because unable to create temporary folder.", message_type='warning')
|
||||
try:
|
||||
preview_filename = os.path.join(generate_random_name('saveimage_preview_', '_temp', 16) + '.png')
|
||||
img.save(os.path.join(temp_dir, preview_filename))
|
||||
except Exception as e:
|
||||
print(e)
|
||||
log(f"Error: {NODE_NAME} skipped, because unable to create temporary file.", message_type='warning')
|
||||
|
||||
while os.path.isfile(os.path.join(full_output_folder, file)):
|
||||
# check if file exists, change filename
|
||||
while os.path.isfile(os.path.join(full_output_folder, f"{file}.{format}")):
|
||||
counter += 1
|
||||
if timestamp == "millisecond":
|
||||
file = f'{filename}_{datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S-%f")[:-3]}_{counter:05}.{format}'
|
||||
file = f'{filename}_{now.strftime("%Y-%m-%d_%H-%M-%S-%f")[:-3]}_{counter:05}'
|
||||
elif timestamp == "second":
|
||||
file = f'{filename}_{datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}_{counter:05}.{format}'
|
||||
file = f'{filename}_{now.strftime("%Y-%m-%d_%H-%M-%S")}_{counter:05}'
|
||||
else:
|
||||
file = f"{filename}_{counter:05}.{format}"
|
||||
file = f"{filename}_{counter:05}"
|
||||
|
||||
image_file_name = os.path.join(full_output_folder, f"{file}.{format}")
|
||||
json_file_name = os.path.join(full_output_folder, f"{file}.json")
|
||||
|
||||
if format == "png":
|
||||
img.save(os.path.join(full_output_folder, file), pnginfo=metadata, compress_level= (100 - quality) // 10)
|
||||
img.save(image_file_name, pnginfo=metadata, compress_level= (100 - quality) // 10)
|
||||
else:
|
||||
if img.mode == "RGBA":
|
||||
img = img.convert("RGB")
|
||||
img.save(os.path.join(full_output_folder, file), quality=quality)
|
||||
img.save(image_file_name, quality=quality)
|
||||
log(f"Saving image to {image_file_name}")
|
||||
|
||||
if save_workflow_as_json:
|
||||
try:
|
||||
workflow = (extra_pnginfo or {}).get('workflow')
|
||||
if workflow is None:
|
||||
log('No workflow found, skipping saving of JSON')
|
||||
with open(f'{json_file_name}.json', 'w') as workflow_file:
|
||||
json.dump(workflow, workflow_file)
|
||||
log(f'Saved workflow to {json_file_name}.json')
|
||||
except Exception as e:
|
||||
log(
|
||||
f'Failed to save workflow as json due to: {e}, proceeding with the remainder of saving execution', message_type="warning")
|
||||
|
||||
if preview:
|
||||
if custom_path == "":
|
||||
results.append({
|
||||
"filename": f"{file}.{format}",
|
||||
"subfolder": subfolder,
|
||||
"type": self.type
|
||||
})
|
||||
else:
|
||||
results.append({
|
||||
"filename": preview_filename,
|
||||
"subfolder": temp_sub_dir,
|
||||
"type": "temp"
|
||||
})
|
||||
|
||||
results.append({
|
||||
"filename": file,
|
||||
"subfolder": subfolder,
|
||||
"type": self.type
|
||||
})
|
||||
counter += 1
|
||||
|
||||
return { "ui": { "images": results } }
|
||||
|
||||
Reference in New Issue
Block a user