Giter Site home page Giter Site logo

audioscavenger / save-image-extended-comfyui Goto Github PK

View Code? Open in Web Editor NEW
37.0 1.0 4.0 2.03 MB

Save as AVIF, WebP, JPEG, customize the folder, sub-folders, and filenames of your images!

License: GNU General Public License v3.0

Python 70.40% JavaScript 29.60%
comfyui-nodes generative-ai

save-image-extended-comfyui's Introduction

💾 Save Image Extended for ComfyUI

Save as JXL, AVIF, WebP, JPEG, JPEG2k, customize the folder, sub-folders, and filenames of your images!

Supports those extensions: JXL AVIF WebP jpg jpeg j2k jp2 png gif tiff bmp

  • Customize the folder, sub-folders, and filenames of your images!
  • Save data about the generated job (sampler, prompts, models) as entries in a json (text) file, in each folder.
  • Use the values of ANY node's widget, by simply adding its badge number in the form id.widget_name
  • Warning: ComfyUI can only load prompts from PNG and WebP atm



Parameters / Usage

Attribute Description
filename_prefix String prefix added to files.
filename_keys Comma separated string with sampler parameters to add to filename. E.g: sampler_name, scheduler, cfg, denoise Added to filename in written order. resolution also works. vae_name model_name (upscale model), ckpt_name (checkpoint) are others that should work. Here you can try any parameter name of any node. As long as the parameter has the same variable name defined in the prompt object they should work. The same applies to foldername_keys.
foldername_prefix String prefix added to folders.
foldername_keys Comma separated string with sampler parameters to add to foldername. Add more subfolders by prepending "./" to the key name.
delimiter now a free field Delimiter = 1 character, can be anything your file system supports. Windows users should still use "/" for subfolders.
save_job_data If enabled, saves information about each job as entries in a jobs.json text file, inside the generated folder. Mulitple options for saving prompt, basic data, sampler settings, loaded models.
job_data_per_image When enabled, saves individual job data files for each image.
job_custom_text Custom string to save along with the job data. Right click the node and convert to input to connect with another node.
save_metadata Saves metadata into the image.
counter_digits Number of digits used for the image counter. 3 = image_001.png. Will adjust the counter if files are deleted. Looks for the highest number in the folder, does not fill gaps.
counter_position Image counter first or last in the filename.
one_counter_per_folder Toggles the counter. Either one counter per folder, or resets when a parameter/prompt changes.
image_preview Turns the image preview on and off.
output_ext File extension: PNG by default, or WEBP (coming soon).
quality Quality for JPEG/JXL/WebP/AVIF/J2K formats; default 90 (AVIF only needs 60 for same results).
named_keys Prefix each value by its key name: prefix-seed=123456-width=1024-etc-0001.avif
  • Unknown key names in filename_keys and foldername_keys are treated as custom strings
    • if you enter wrongNumber.attribute, you will get attribute in your filename.
  • Datetime UNIX format is now included! %Y-%m-%d or %F etc
  • default it output only the name for ckpt_name and control_net_name
    • use ckpt_path or control_net_path in case you have subfolders for those and want to use them as subfolders
  • using .custom_string will prevent appending delimiter, the dot will be the delimiter

Node inputs

  • images - The generated images.

Optional:

  • positive_text_opt - Optional string input for when using custom nodes for positive prompt text.
  • negative_text_opt - Optional string input for when using custom nodes for negative prompt text.

Automatic date/time conversion in file/folder names

Converts unix datetime formats:

Unix datetime Example Comment
%F or %Y-%m-%d 2024-05-22
%D 05/22/24 This effectively creates subfolders
%F %H-%M-%S 2024-05-22 09-13-58
%Y/%V 2024/21 year subfolder / ISO week number subfolder

Installation

Requirements:

There is a requirements.txt that will take care of that, but just in case:

  • python 10.6
  • piexif
  • imagecodecs
  • pillow
  • pillow-avif-plugin
  • pillow-jxl-plugin
pip install piexif pillow pillow-avif-plugin

For Jpeg XL / jxl it's more complicated. You cannot compile the wheel jxlpy on Windows. Therefore, we use an alternative: imagecodecs

pip install -U imagecodecs

Manual Download

  1. Open a terminal inside the 'custom_nodes' folder located in your ComfyUI installation dir
  2. Use the git clone command to clone the save-image-extended-comfyui repo under ComfyUI\custom_nodes\
git clone https://github.com/audioscavenger/save-image-extended-comfyui

Miscelaneous

JPEG XL is a heated debate on chromium forum and if true indeed that Google is working on WebP2, jxl is unlikely to take off any day soon. Proponents arguably declare with no proof, that jxl is better and faster than the current best codec: AVIF. But again, without support from the industry, it's going nowhere.

I tested with compression 90 and it's good, with a caveat. The compression offered by pillow is 3x lower then Image Magick for the same level. No idea why.

Pillow cannot save Exif data in JPEG2000, nor can it compress it in any way. Who the heck is using JPEG2000 in 2024 anyway?

Disclaimer: Does not check for illegal characters entered in file or folder names. May not be compatible with every other custom node, depending on changes in the prompt object. Tested and working with default samplers, Efficiency nodes, UltimateSDUpscale, ComfyRoll, composer, NegiTools, and 45 other nodes.

Quality and compression settings: default is 90, 100 will activate lossless for AVIF and WEBP only.

Quick comparison of size per extension, for the same 512x512 picture, with similar visual quality:

Ext Compression Maker Size Compression
png max 9 PIL 413111 0%
j2k n/a PIL 395028 4%
jxl lossless PIL 301310 27%
jxl 90 PIL 179210 57%
jpeg 90 PIL 88554 79%
avif 90 Imagick 67272 84%
webp 90 Imagick 64416 84%
webp 90 PIL 64356 84%
avif 60 PIL 47353 89%
avif 60 Imagick 33691 92%

About extensions WebP AVIF JPEG JXL: ComfyUI can only load PNG and WebP atm... Feel free to ask ComfyUI team to add support for AVIF/jpeg/JXL!

The metadata Are included under the EXIF tags IFD below, as defined here WAS Node Suite also use those tags. They must be next to each other in order to Comfy to be able to load them with drag and drop.

Data EXIF Name String looks like
prompt 0x010f Make Prompt: {"5" ... }
workflow 0x010e ImageDescription Workflow: {"5" ... }

You can retrieve the prompt manually with exiftool, here are some example commands:

  • exiftool -Parameters -Prompt -Workflow image.png
  • exiftool -Parameters -UserComment -ImageDescription image.{jpg|jpeg|webp|avif|jxl}

ComfyUI cannot load lossless WebP atm. Feel free to try and fix pnginfo.js

Incompatible with extended-saveimage-comfyui - This node can be safely discarded, as it only offers WebP output. My node already adds JPEG and WebP.

You asked for it... Now you can select which node to get the widget values from! Formerly, this custom node would simply return the last value found: useless if you have multiple same nodes... To see node numbers in the UI, enable the badge IDs:

jobs.json sample: always generated and appended, not sure what it can be used for.



Happy saving!

RoadMap

Reboot by AudioscavengeR since 2024-05-05, original idea from @thedyze

I won't promise you the moon, but since I use this node myself, I will maintain it as much as I can. I do provide a way to contact me, and will accept PR and collabs. Once I feel like I don't have time to work on it, I will gladly transfer ownership or let collabs maintain it.

TODO:

  • accept multiple images as input
  • improve get_latest_counter: restarts when user renames files after the counter part.
  • offer to place the counter anywhere, as a key in filename_keys
  • keep same counter if extension changes?
  • files will be out of order if prefixes change... that is expected, but is this what we want?

release 2.76 💾

  • brought back resolution

release 2.75 💾

  • Prefix each value by its key name: prefix-seed=123456-width=1024-etc-0001.avif

release 2.74 💾

  • updated help popup and minor cosmetic fixes

release 2.73 💾

  • added ckpt_path and control_net_path in case you have subfolders for those: default it output only the name
  • complete fix of save_images() which allows for use of subfolders in filename_keys
  • tried VALIDATE_INPUTS() but all it does is checking 1 single value, no correction

release 2.70 💾

  • added JPEG-XL
  • added JPEG2000
  • fixed help popup text color in dark mode

release 2.65 💾

  • published in comfy-registry

release 2.64 💾

  • added Help at top-right corner, based off KJNodes

release 2.63 💾

  • fixed negative_prompt job save overwritten by positive_prompt
  • remove job_custom_text? no, some ppl use it apparently
  • remove jobs.json? no, some ppl use it apparently
  • ComfyRoll CR XY Save Grid Image: it offers jpeg webp tif - check how it embeds prompt - nope it does not

release 2.62 💾

  • prompt and workflow are saved in IFD 270 and 271 for better load compatibility
  • disabled jobs.json by default, this thingy seems useless to me

release 2.61 💾

  • added quality input

release 2.60 💾

  • added extensions jpeg, gif, tiff, bmp
  • added image_optimization (only for jpeg)
  • now saves prompt and workflow separately into 0x9286/UserComment and 0x010e/ImageDescription

release 2.51 💾

  • added unix datetime formats

release 2.50 💾

  • added JXL support
  • added 'BOOLEAN' support

release 2.46 💾

  • bug discovered with rgthree's Ksampler Config: using steps_total as an input to a Ksampler, will issue the index of the output, instead of the steps value ("[nodeNum, 0]" instead of steps value). FIX: use steps_total instead of steps!
  • uncommented __all__ in init.py
  • potential bugfix in splitKey, len(splitKey) = 2 to identify actual "node.widget" format

release 2.45 💾

  • added 💾 in the name

release 2.44

  • so many bugfixes
  • complete rework of generate_custom_name to handle ALL the possible scenarios
  • bugfix: when using /name in foldername_keys, Comfy thinks you want to save outside the output folder

release 2.43

  • support for AVIF
  • added requirements.txt

release 2.42

  • fixed counter for variable file extensions length

release 2.41

  • bugfix WebP encoding: Comfy could partially read the prompt, but the way they implemented it was buggy. PR fix submitted.
  • WebP is indeed loaded properly like a PNG, if you apply the patch above to pnginfo.js and app.js`

release 2.4

  • integrate webp
  • integrate jpeg

release 2.3

  • for each keys, we return only the last value found in the prompt. Not the last Ksampler. Impossible to know which one is the last. Therefore, simply use this syntax: number.widget_name
  • filename_keys and foldername_keys become too large, switch to multiline
  • also removes subfolders from values found, when people use subfolders like SD15/pytorch_blah.pt etc
  • added what I was looking for the last 6 months in the first place: 123.attribute from nodes!
  • limit delimiter to 1 char, or file counter will get too complex

release 2.2

  • delimiter is now whatever you want, free field. Limited to 16 characters tho
  • all is instance methods, previously we had @staticmethods. Why? Don't know.
  • check get_latest_counter: does it still work with subfolders? yessir
  • bugfix: custom_name was not updated for int and floats

release 2.1

  • now accepts inexistant keys and use them as fixed strings
  • now accepts inexistant keys with / and use them as subfolders

release 2.0

  • Reboot on 2024-05-05

🎀 Licence

GPL 3.0

🍺 Buy me a beer

Like my work? This tool helped you? Want to sponsor more awesomeness like this?

save-image-extended-comfyui's People

Contributors

alulkesh avatar audioscavenger avatar thedyze avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

save-image-extended-comfyui's Issues

Doesn't appear compatible with rgthree ksamplerconfig

It doesn't seem able to read values that were passed from rgthree KSamplerConfig, through rgthree context node, and finally on to an Inspire KSamplerAdvanced.

For example, given the default filename keys of sampler_name, scheduler, cfg, steps, I'm getting a filename of sampler_name, scheduler, cfg, steps. Where 966 is the node id of the context node, and the integer looks like the index in the output of the context.

I'll try and cook up a simple workflow example that reproduces this.

Attribute Error while saving

Sorry to bother you, the node appears to be functioning just fine despite the error I'm just more annoyed the error comes up. Is there anyway to fix this?

!!! Exception during processing!!! 'int' object has no attribute 'endswith'
!!! Exception during processing!!! 'int' object has no attribute 'endswith'
Traceback (most recent call last):
  File "G:\StabilityMatrix\Data\Packages\ComfyUI\execution.py", line 151, in recursive_execute
    output_data, output_ui = get_output_data(obj, input_data_all)
  File "G:\StabilityMatrix\Data\Packages\ComfyUI\execution.py", line 81, in get_output_data
    return_values = map_node_over_list(obj, input_data_all, obj.FUNCTION, allow_interrupt=True)
  File "G:\StabilityMatrix\Data\Packages\ComfyUI\execution.py", line 74, in map_node_over_list
    results.append(getattr(obj, func)(**slice_dict(input_data_all, i)))
  File "G:\StabilityMatrix\Data\Packages\ComfyUI\custom_nodes\wx-save-image-extended-comfyui\save_image_extended.py", line 330, in save_images
    SaveImageExtended.save_job_to_json(save_job_data, prompt, filename_prefix, positive_text_opt, negative_text_opt, job_custom_text, resolution, output_path, 'jobs.json')
  File "G:\StabilityMatrix\Data\Packages\ComfyUI\custom_nodes\wx-save-image-extended-comfyui\save_image_extended.py", line 175, in save_job_to_json
    models = SaveImageExtended.find_parameter_values(['ckpt_name', 'loras', 'vae_name', 'model_name'], prompt)
  File "G:\StabilityMatrix\Data\Packages\ComfyUI\custom_nodes\wx-save-image-extended-comfyui\save_image_extended.py", line 131, in find_parameter_values
    SaveImageExtended.find_parameter_values(target_keys, value, found_values)
  File "G:\StabilityMatrix\Data\Packages\ComfyUI\custom_nodes\wx-save-image-extended-comfyui\save_image_extended.py", line 131, in find_parameter_values
    SaveImageExtended.find_parameter_values(target_keys, value, found_values)
  File "G:\StabilityMatrix\Data\Packages\ComfyUI\custom_nodes\wx-save-image-extended-comfyui\save_image_extended.py", line 120, in find_parameter_values
    if value.endswith('.safetensors'):
AttributeError: 'int' object has no attribute 'endswith'

Edit:
Okay this only seems to appear when "basic, models, sampler, prompt" is selected for job data

When using a specific Checkpoint Loader It is not saved under the Checkpoint name.

I'm using a node by creating a folder with a checkpoint name and saving it...
When using a specific Checkpoint Loader, {'content': As this item enters, it fails, and the folder is not saved.

The Checkpoint Loader is a node in pysssss.
https://github.com/pythongosssss/ComfyUI-Custom-Scripts

Is it something that can't be solved?

image

SaveImageExtended 2.76 error: An error occurred while creating the subfolder or saving the image: [WinError 267] 디렉터 리 이름이 올바르지 않습니다: "O:\\OneDrive\\AI\\Areum\\{'content': '1.Pureum" !!! Exception during processing!!! object of type 'NoneType' has no len() Traceback (most recent call last): File "A:\SynologyDrive\ComfyUI-webui\ComfyUI\execution.py", line 151, in recursive_execute output_data, output_ui = get_output_data(obj, input_data_all) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "A:\SynologyDrive\ComfyUI-webui\ComfyUI\execution.py", line 95, in get_output_data output_is_list = [False] * len(results[0]) ^^^^^^^^^^^^^^^ TypeError: object of type 'NoneType' has no len()

small bug that you save negative_text into prompt_keys_to_save['positive_prompt'], so that json file can not save positive prompt correctly

prompt_keys_to_save['positive_prompt'] = negative_text

            print("执行将positive_text存入prompt_keys_to_save['positive_prompt']")
            prompt_keys_to_save['positive_prompt'] = positive_text
            print("查看一下存入的目标变量是否正确:prompt_keys_to_save['positive_prompt'] ")
            print(prompt_keys_to_save['positive_prompt'])
          
          if negative_text is not None:
            print("进入了:if negative_text is not None:")
            if isinstance(negative_text, list):
              print("进入了:if isinstance(negative_text, list):")
              if len(negative_text) == 2:
                if isinstance(negative_text[0], str) and len(negative_text[0]) < 6:
                  if isinstance(negative_text[1], (int, float)):
                    continue
            print("执行将negative_text存入prompt_keys_to_save['positive_prompt']")
            **prompt_keys_to_save['negative_text'] = negative_text**

syntax error

Problem:
i had this error when running the extention for the first time on 18bc842 commit

Example:
WindowsTerminal_2g9GhJ1WRS

Code_Qp5Z0qpJOL

solution:
it's just a simple syntax error you can just convert it into a string or something or remove the last "."
version = 2.6.5 -> version = 2.6

Checkpoints in folders, when applied to filename, create subfolders when saving

As you can see below, my checkpoints are in folders. Since ckpt_name grabs the entire name, including the path, it creates subfolders.
 
image

image

Also, for some reason, it creates the file first then the subfolder in this case. It seems like it should have instead been:

FaceGen
└─ 2024-05-24
   └─ FaceGen-SDXL
      └─ .photo
         └─ sdxlHK_v09-0004.jpg

recursion errors with multiple checkpoints

i'm trying to do outpainting and use a second checkpoint for the outpainting and one for the base image
i'm using this as my folder name 25.ckpt_name, 50.ckpt_name, 31.lora_name, 30.lora_name,
it's giving me an error about recursion

SaveImageExtended 2.76 error: An error occurred while creating the subfolder or saving the image: [WinError 267] The directory name is invalid: "D:\\ai\\stabilitymatrix\\Data\\Packages\\ComfyUI\\output\\xl\\enjoyXLSuperRealistic_v50lightning-{'content': 'xl"
!!! Exception during processing!!! object of type 'NoneType' has no len()
Traceback (most recent call last):
  File "D:\ai\stabilitymatrix\Data\Packages\ComfyUI\execution.py", line 151, in recursive_execute
    output_data, output_ui = get_output_data(obj, input_data_all)
  File "D:\ai\stabilitymatrix\Data\Packages\ComfyUI\execution.py", line 95, in get_output_data
    output_is_list = [False] * len(results[0])
TypeError: object of type 'NoneType' has no len()

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.