Compare commits

...
7 Commits
Author SHA1 Message Date
audioscavenger a25b5091c3 release 2.70 JXL
modified:   README.md
    	modified:   pyproject.toml
    	modified:   requirements.txt
    	modified:   save_image_extended.py
    	modified:   web/js/help_popup.js
	modified:   README.md
	modified:   save_image_extended.py
2024-06-01 12:47:39 -07:00
audioscavenger c4aeb168b6 release 2.70 JXL
modified:   README.md
	modified:   pyproject.toml
	modified:   requirements.txt
	modified:   save_image_extended.py
	modified:   web/js/help_popup.js
2024-06-01 11:09:06 -07:00
audioscavenger 266cef3800 release 2.65 comfy-registry
modified:   README.md
    	modified:   save_image_extended.py
	modified:   README.md
	modified:   pyproject.toml
	modified:   save_image_extended.py
2024-05-30 08:14:36 -07:00
audioscavenger 18bc84204e release 2.6.5 comfy-registry
modified:   README.md
    	modified:   pyproject.toml
    	modified:   save_image_extended.py
	modified:   README.md
2024-05-29 21:32:48 -07:00
audioscavenger 569f4c1ec2 release 2.6.5 comfy-registry
modified:   README.md
	modified:   pyproject.toml
	modified:   save_image_extended.py
2024-05-29 18:12:37 -07:00
audioscavenger 40aeed0e3b release 2.65 comfy-registry
modified:   README.md
	modified:   save_image_extended.py
2024-05-29 18:09:21 -07:00
audioscavenger d72b8e5428 release 2.64 helpPopup
modified:   README.md
            	modified:   __init__.py
            	modified:   save_image_extended.py
        	modified:   web/js/help_popup.js
    	modified:   __init__.py
    	modified:   web/js/help_popup.js
2024-05-29 18:03:20 -07:00
8 changed files with 124 additions and 37 deletions
+25
View File
@@ -0,0 +1,25 @@
name: "Publish To Registry"
description: "Publish Custom Nodes to Registry."
inputs:
personal_access_token:
description: "Personal Access Token for authenticating to the Registry"
required: true
runs:
using: "composite"
steps:
- name: Checkout Custom Node Repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Install comfy-cli
shell: bash
run: |
pip install comfy-cli
- name: Publish Node
shell: bash
run: |
comfy --skip-prompt --no-enable-telemetry env
comfy node publish --token ${{ inputs.personal_access_token }}
+44 -10
View File
@@ -1,7 +1,7 @@
# 💾 Save Image Extended for ComfyUI
Save as AVIF, WebP, JPEG, customize the folder, sub-folders, and filenames of your images!
Save as JXL, AVIF, WebP, JPEG, JPEG2000, customize the folder, sub-folders, and filenames of your images!
Supports those extensions: **AVIF WebP JXL jpg jpeg png gif tiff bmp**
Supports those extensions: **JXL AVIF WebP jpg jpeg j2k jp2 png gif tiff bmp**
<p align="center">
<img src="assets/save-image-extended-comfyui-example.png" />
@@ -10,7 +10,7 @@ Supports those extensions: **AVIF WebP JXL jpg jpeg 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_
* Promt saved in jpeg and AVIF, but ComfyUI can only load PNG and WebP atm
* Warning: ComfyUI can only load prompts from PNG and WebP atm
<br>
@@ -71,17 +71,19 @@ 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 need to install and compile the wheel jxlpy, and therefore, need a valid and functional MSVC installation.
For Jpeg XL / jxl it's more complicated. You cannot compile the wheel jxlpy on Windows. Therefore, we use an alternative: [imagecodecs](https://pypi.org/project/imagecodecs/)
```
pip install jxlpy
pip install -U imagecodecs
```
### Manual Download
@@ -92,18 +94,35 @@ git clone https://github.com/audioscavenger/save-image-extended-comfyui
```
## Miscelaneous
#
[JPEG XL is a heated debate on chromium forum](https://issues.chromium.org/issues/40168998#comment85) 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 75, 100 will activate **lossless** for AVIF and WEBP only.
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 picture, AVIF quality=60, WebP quality=75, jpeg quality=91 (and yes, AVIF still looks better then WebP):
Quick comparison of size per extension, for the same 512x512 picture, with similar visual quality:
| Ext | Compression | Maker | Size |
| --- | --- | --- | --- |
| png | max 9 | PIL | 413111 |
| j2k | n/a | PIL | 395028 |
| jxl | lossless | PIL | 301310 |
| jxl | 90 | PIL | 179210 |
| jpeg | 90 | PIL | 88554 |
| avif | 90 | Imagick | 67272 |
| webp | 90 | Imagick | 64416 |
| webp | 90 | PIL | 64356 |
| avif | 60 | PIL | 47353 |
| avif | 60 | Imagick | 33691 |
<p align="center">
<img src="assets/save-image-extended-sizes-comparison.png" />
</p>
#
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!
@@ -157,6 +176,14 @@ TODO:
- [ ] 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.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
@@ -235,3 +262,10 @@ TODO:
## :ribbon: Licence
[GPL 3.0](https://choosealicense.com/licenses/gpl-3.0/)
## :beer: Buy me a beer
Like my work? This tool helped you? Want to sponsor more awesomeness like this?
<p align="center">
<a href="https://www.paypal.com/donate/?hosted_button_id=CD7P7PK3WP8WU"><img src="/assets/paypal-Donate-QR-Code.png" /></a>
</p>
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
View File
Binary file not shown.
+15
View File
@@ -0,0 +1,15 @@
[project]
name = "save-image-extended-comfyui"
description = "Save as AVIF, WebP, JPEG, customize the folder, sub-folders, and filenames of your images!"
version = "2.70"
license = "LICENCE"
dependencies = ["piexif", "imagecodecs", "pillow", "pillow-avif-plugin", "pillow-jxl-plugin"]
[project.urls]
Repository = "https://github.com/audioscavenger/save-image-extended-comfyui"
# Used by Comfy Registry https://comfyregistry.org
[tool.comfy]
PublisherId = "audioscavenger"
DisplayName = "save-image-extended-comfyui"
Icon = ""
+4
View File
@@ -1,3 +1,7 @@
piexif
# jpegxl support: imagecodecs will bring libjxl 0.9.0
imagecodecs
pillow
pillow-avif-plugin
pillow-jxl-plugin
+34 -26
View File
@@ -11,7 +11,7 @@ import pprint
import piexif
import piexif.helper
version = 2.64
version = 2.70
avif_supported = False
jxl_supported = False
@@ -23,20 +23,24 @@ except:
print(f"\033[92m[save_image_extended]\033[0m AVIF is not supported. To add it: pip install pillow pillow-avif-plugin\033[0m")
pass
else:
print(f"\033[92m[save_image_extended] AVIF is supported! Woohoo!\033[0m")
print(f"\033[92m[save_image_extended] AVIF is supported! Woohoo!\033[0m")
avif_supported = True
# Jxl requires jxlpy wheel to be compiled, and a valid MSVC environment, which is complex task
try:
from jxlpy import JXLImagePlugin
# jxlpy is in early stages of development. None one has ever compiled it on Windows AFAIK
# from jxlpy import JXLImagePlugin
# from imagecodecs import (jpegxl_encode, jpegxl_decode, jpegxl_check, jpegxl_version, JPEGXL)
import pillow_jxl
except:
print(f"\033[92m[save_image_extended]\033[0m JXL is not supported. To add it: pip install jxlpy\033[0m")
print(f"\033[92m[save_image_extended]\033[0m You will need a valid MSVC env to build the wheel\033[0m")
pass
else:
print(f"\033[92m[save_image_extended] JPEGXL is supported! YeePee!\033[0m")
jxl_supported = True
# PIL must be loaded after pillow_avif
# PIL must be loaded after pillow plugins
from PIL import Image, ExifTags
from PIL.PngImagePlugin import PngInfo
@@ -66,11 +70,12 @@ class SaveImageExtended:
png_compress_level = 9
avif_quality = 60
webp_quality = 75
jpeg_quality = 91
jxl_quality = 91
webp_quality = 90
jpeg_quality = 90
jxl_quality = 90
j2k_quality = 90
# tiff_quality has no impact unless you start meddling with the compressions algorithms
tiff_quality = 91
tiff_quality = 90
# optimize_image only works for jpeg, with like just 2% reduction in size
optimize_image = True
@@ -90,14 +95,15 @@ class SaveImageExtended:
image_preview = True
extToRemove = ['.safetensors', '.ckpt', '.pt', '.bin', '.pth']
output_ext = '.webp'
output_exts = ['.webp', '.png', '.jpg', '.jpeg', '.gif', '.tiff', '.bmp']
quality = 75
output_exts = ['.webp', '.png', '.jpg', '.jpeg', '.j2k', '.jp2', '.gif', '.tiff', '.bmp']
quality = 90
print(f"\033[92m[save_image_extended]\033[0m version: {version}\033[0m")
if jxl_supported:
output_exts.insert(0, '.jxl')
# if pillow_avif not in sys.modules:
if avif_supported:
# no matter what people say, jxl is far away from being integrated in browsers. I bet on AVIF.
output_exts.insert(0, '.avif')
def __init__(self):
@@ -474,7 +480,7 @@ class SaveImageExtended:
metadata.update(extra_pnginfo)
## For Comfy to load an image, it need a PNG tag at the root: Prompt={prompt}
## For AVIF WebP Jpeg, it's only Exif that's available... and UserComment is the best choice.
## For AVIF WebP Jpeg JXL, it's only Exif that's available... and UserComment is the best choice.
## This method gives good results, as long as you save the prompt/workflow in 2 separate Exif tags
## Otherwise, [ExifTool] will issue Warning: Invalid EXIF text encoding for UserComment
@@ -534,34 +540,36 @@ class SaveImageExtended:
return exif_dat
def save_image(self, image_path, img, prompt, save_metadata=save_metadata, extra_pnginfo=None, quality=75):
def save_image(self, image_path, img, prompt, save_metadata=save_metadata, extra_pnginfo=None, quality=90):
# print(f"debug save_images: image_path={image_path}")
output_ext = os.path.splitext(os.path.basename(image_path))[1]
metadata = None
kwargs = dict()
# TODO: see if convert_hdr_to_8bit=False make a change
# https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html
# match is python 3.10+
if output_ext in ['.avif']:
if output_ext in ['.avif', '.webp', '.jxl']:
if save_metadata: kwargs["exif"] = self.get_metadata_exif(img, prompt, extra_pnginfo)
kwargs["quality"] = quality
if quality == 100: kwargs["lossless"] = True
elif output_ext in ['.webp']:
if quality == 100:
kwargs["lossless"] = True
else:
kwargs["quality"] = quality
if output_ext in ['.j2k', '.jp2', '.jpc', '.jpf', '.jpx', '.j2c']:
if save_metadata: kwargs["exif"] = self.get_metadata_exif(img, prompt, extra_pnginfo)
kwargs["quality"] = quality
if quality == 100: kwargs["lossless"] = True
if quality < 100:
kwargs["irreversible"] = True
# there is no such thing as compression level in JPEG2000. Read https://comprimato.com/blog/2017/06/22/bitrate-control-quality-layers-jpeg2000/
# kwargs["quality_mode"] = 'rates' or 'dB'
# kwargs["quality_layers"] = [0,1,2] no refence online. i tried all values from 0 to 100 and no change in filesize
else:
kwargs["quality"] = quality
elif output_ext in ['.jpg', '.jpeg']:
if save_metadata: kwargs["exif"] = self.get_metadata_exif(img, prompt, extra_pnginfo)
# https://stackoverflow.com/questions/19303621/why-is-the-quality-of-jpeg-images-produced-by-pil-so-poor
kwargs["subsampling"] = 0
kwargs["quality"] = quality
kwargs["optimize"] = self.optimize_image
elif output_ext in ['.jxl']:
if save_metadata: kwargs["exif"] = self.get_metadata_exif(img, prompt, extra_pnginfo)
kwargs["quality"] = quality
if quality == 100: kwargs["lossless"] = True
elif output_ext in ['.tiff']:
# tiff: i suspect no quality either
kwargs["quality"] = quality
kwargs["optimize"] = self.optimize_image
elif output_ext in ['.png', '.gif']:
# png/gif: no quality
+2 -1
View File
@@ -74,6 +74,7 @@ const create_documentation_stylesheet = () => {
let styleTag = document.head.querySelector(tag)
// color: var(--fg-color); will be black even in dark mode... bug but i can't tell where it comes from
if (!styleTag) {
styleTag = document.createElement('style')
styleTag.type = 'text/css'
@@ -82,7 +83,7 @@ const create_documentation_stylesheet = () => {
.sie-documentation-popup {
background: var(--comfy-menu-bg);
position: absolute;
color: var(--fg-color);
color: white;
font: 12px monospace;
line-height: 1.5em;
padding: 10px;