diff --git a/Nodes/Outputs.py b/Nodes/Outputs.py index ccc3548..dada173 100644 --- a/Nodes/Outputs.py +++ b/Nodes/Outputs.py @@ -498,6 +498,7 @@ class PrimerePreviewImage(): "image_resize": ("INT", {"default": 0, "min": 0, "max": utility.MAX_RESOLUTION, "step": 64}), "image_quality": ("INT", {"default": 95,"min": 10, "max": 100, "step": 5}), "preview_target": (['Checkpoint', 'CSV Prompt', 'Lora', 'Lycoris', 'Hypernetwork', 'Embedding'],), + "preview_save_mode": (['Overwrite', 'Keep', 'Join horizontal', 'Join vertical'], {"default": "Overwrite"}), "images": ("IMAGE", ), }, diff --git a/__init__.py b/__init__.py index 6ced751..00924a2 100644 --- a/__init__.py +++ b/__init__.py @@ -25,7 +25,7 @@ frontend_source = os.path.join(here, 'front_end') is_frontend_symlinked = False ClientTime = datetime.now() -UpdateRequired = '2024-03-15 20:00:00' +UpdateRequired = '2024-03-17 20:00:00' if os.path.isdir(frontend_target) == True: try: diff --git a/components/primereserver.py b/components/primereserver.py index cbad847..134ffb7 100644 --- a/components/primereserver.py +++ b/components/primereserver.py @@ -31,6 +31,7 @@ routes = PromptServer.instance.routes async def primere_preview_post(request): post = await request.post() PreviewSaveResponse = None + SAVE_MODE = 'Create' PREVIEW_DATA = json.loads(post.get('previewdata')) # {'PreviewTarget': 'Checkpoint', 'PreviewTargetOriginal': 'Sci-fi\\colorful_v30.safetensors', 'extension': 'jpg', 'ImageName': 'ComfyUI_temp_pmzjp_00092_.png', 'ImagePath': 'H:\\ComfyUI\\output', 'SaveImageName': 'colorful_v30', 'maxWidth': 220, 'maxHeight': 220} IMG_SOURCE = os.path.join(PREVIEW_DATA['ImagePath'], PREVIEW_DATA['ImageName']) # H:\ComfyUI\output\ComfyUI_temp_pmzjp_00092_.png @@ -43,9 +44,9 @@ async def primere_preview_post(request): TARGET_FILE = os.path.join(TARGET_DIR, path, PREVIEW_DATA['SaveImageName'] + '.' + PREVIEW_DATA['extension']) # H:\ComfyUI\web\extensions\Primere\images\checkpoints\Sci-fi\colorful_v30_000_test.jpg if os.path.isfile(TARGET_FILE): - PreviewSaveResponse = "Preview file for " + PREVIEW_DATA['PreviewTargetOriginal'] + " replaced with current preview for " + PREVIEW_DATA['PreviewTarget'] + "." - else: - PreviewSaveResponse = "Preview file for " + PREVIEW_DATA['PreviewTargetOriginal'] + " created and saved for " + PREVIEW_DATA['PreviewTarget'] + "." + SAVE_MODE = PREVIEW_DATA['PrwSaveMode'] + + PreviewSaveResponse = "Preview file for " + PREVIEW_DATA['PreviewTargetOriginal'] + " used [" + SAVE_MODE + "] mode and saved for " + PREVIEW_DATA['PreviewTarget'] + "." if not os.path.isdir(FULL_TARGET_PATH): # H:\ComfyUI\web\extensions\Primere\images\checkpoints\Sci-fi Path(str(FULL_TARGET_PATH)).mkdir(parents = True, exist_ok = True) @@ -55,7 +56,29 @@ async def primere_preview_post(request): prw_img = Image.open(IMG_SOURCE).convert("RGB") newsize = (PREVIEW_DATA['maxWidth'], PREVIEW_DATA['maxHeight']) prw_img_resized = prw_img.resize(newsize) - prw_img_resized.save(TARGET_FILE, quality = 50, optimize = True) + + if os.path.isfile(TARGET_FILE): + match SAVE_MODE: + case "Overwrite": + prw_img_resized.save(TARGET_FILE, quality=50, optimize=True) + case "Keep": + PreviewSaveResponse = "Preview file not saved for [" + filename + "] because image already exist and selected [" + SAVE_MODE + "] mode." + case "Join horizontal": + prw_img_exist = Image.open(TARGET_FILE) + joined_img = utility.ImageConcat(prw_img_exist, prw_img, 1) + joined_img.save(TARGET_FILE, quality = 50, optimize = True) + + case "Join vertical": + prw_img_exist = Image.open(TARGET_FILE) + joined_img = utility.ImageConcat(prw_img_exist, prw_img, 0) + if joined_img.size[1] > 250: + heigth_ratio = joined_img.size[1] / 220 + new_width = round(joined_img.size[0] / heigth_ratio) + joined_img = joined_img.resize([new_width, 220]) + joined_img.save(TARGET_FILE, quality = 50, optimize = True) + else: + prw_img_resized.save(TARGET_FILE, quality = 50, optimize = True) + except Exception: PreviewSaveResponse = 'ERROR: Cannot save target image to: ' + str(FULL_TARGET_PATH) + ' for ' + PREVIEW_DATA['PreviewTarget'] + "." else: diff --git a/components/utility.py b/components/utility.py index a4129f5..f1c439b 100644 --- a/components/utility.py +++ b/components/utility.py @@ -693,3 +693,32 @@ def getLatentSize(samples): return (None, None) return (None, None) + +def MatchDimensions(width_1, height_1, width_2, height_2, axis_value): + if axis_value == 1: + rate = height_2 / height_1 + new_heigth = height_1 + new_width = width_2 / rate + else: + rate = width_2 / width_1 + new_width = width_1 + new_heigth = height_2 / rate + + return [round(new_width), round(new_heigth)] + +def ImageConcat(image1, image2, axis_value): + image1_size = image1.size + image2_size = image2.size + new_image_dim = MatchDimensions(image1_size[0], image1_size[1], image2_size[0], image2_size[1], axis_value) + img2_resized = image2.resize(new_image_dim) + + if axis_value == 1: + new_image = Image.new('RGB', (new_image_dim[0] + image1_size[0], image1_size[1]), (250, 250, 250)) + new_image.paste(image1, (0, 0)) + new_image.paste(img2_resized, (image1_size[0], 0)) + else: + new_image = Image.new('RGB', (image1_size[0], new_image_dim[1] + image1_size[1]), (250, 250, 250)) + new_image.paste(image1, (0, 0)) + new_image.paste(img2_resized, (0, image1_size[1])) + + return new_image diff --git a/front_end/primere_output.js b/front_end/primere_output.js index d4e939e..1d9bb11 100644 --- a/front_end/primere_output.js +++ b/front_end/primere_output.js @@ -6,6 +6,7 @@ let hasShownAlertForUpdatingInt = false; let ImagePath = null; let WorkflowData = {}; const realPath = "extensions/Primere"; +const prwPath = "extensions/PrimerePreviews"; let PreviewTarget = 'Checkpoint'; let PreviewTargetPreviousState = PreviewTarget; @@ -19,6 +20,8 @@ let TargetFileName = null; let LoadedNode = null; let TargetSelValues = ["select target..."]; let SelectedTarget = null; +let PreviewExist = false; +let PrwSaveMode = 'Overwrite'; const NodenameByType = { 'Checkpoint': 'PrimereVisualCKPT', @@ -29,6 +32,15 @@ const NodenameByType = { 'Embedding': 'PrimereVisualEmbedding' } +const NodesubdirByType = { + 'Checkpoint': 'checkpoints', + 'CSV Prompt': 'styles', + 'Lora': 'loras', + 'Lycoris': 'lycoris', + 'Hypernetwork': 'hypernetworks', + 'Embedding': 'embeddings' +} + app.registerExtension({ name: "Primere.PrimereOutputs", async beforeRegisterNodeDef(nodeType, nodeData, app) { @@ -348,7 +360,8 @@ class PreviewSaver { "SaveImageName": SaveImageName, "maxWidth": resampledWidth, "maxHeight": resampledHeight, - "TargetQuality": TargetQuality + "TargetQuality": TargetQuality, + "PrwSaveMode": PrwSaveMode })); } } else { @@ -382,6 +395,8 @@ function TargetListCreator(node) { } function ButtonLabelCreator(node) { + PreviewExist = false; + for (var px = 0; px < node.widgets.length; ++px) { if (node.widgets[px].name == 'preview_target') { PreviewTarget = node.widgets[px].value; @@ -401,6 +416,9 @@ function ButtonLabelCreator(node) { if (node.widgets[px].name == 'image_quality') { TargetQuality = node.widgets[px].value; } + if (node.widgets[px].name == 'preview_save_mode') { + PrwSaveMode = node.widgets[px].value; + } } var INIT_IMGTYPE_STRING = ""; @@ -431,7 +449,49 @@ function ButtonLabelCreator(node) { if (targetIndex > -1) { TargetFileName = WorkflowData[NodenameByType[PreviewTarget]][targetIndex]; } - buttontitle = 'Save preview as: [' + TargetFileName + '.jpg] to [' + PreviewTarget + '] folder.'; + + let prwpath_new = SelectedTarget.replaceAll('\\', '/'); + let dotLastIndex = prwpath_new.lastIndexOf('.'); + if (dotLastIndex > 1) { + var finalName = prwpath_new.substring(0, dotLastIndex); + } else { + var finalName = prwpath_new; + } + finalName = finalName.replaceAll(' ', "_"); + let previewName = finalName + '.jpg'; + var imgsrc = prwPath + '/images/' + NodesubdirByType[PreviewTarget] + '/' + previewName; + + let loadImage = src => + new Promise((resolve, reject) => { + let img_check = new Image(); + img_check.onload = () => resolve(img_check); + img_check.onerror = reject; + img_check.src = src; + console.log('*** *** ***'); + console.log(img_check.height); + console.log('*** *** ***'); + if (img_check.height > 0) { + PreviewExist = true; + } + }); + + loadImage(imgsrc).then(image_prw_test => + image_prw_test.complete + ); + + var imgExistLink = ""; + if (PreviewExist === true) { + let splittedMode = PrwSaveMode.split(' '); + var prw_mode = ''; + splittedMode.forEach(n => { + prw_mode += n[0] + }); + imgExistLink = ' [' + prw_mode.toUpperCase() + ']'; + } else { + imgExistLink = ' [C]'; + } + + buttontitle = 'Save preview as: [' + TargetFileName + '.jpg] to [' + PreviewTarget + '] folder.' + imgExistLink; } } else { buttontitle = 'Required node: [' + NodenameByType[PreviewTarget] + '] not available in workflow for target: [' + PreviewTarget + ']';