comfyanonymous / ComfyUI

The most powerful and modular stable diffusion GUI, api and backend with a graph/nodes interface.
https://www.comfy.org/
GNU General Public License v3.0
42.63k stars 4.51k forks source link

HDR Images Error: Image file is truncated #2692

Open ckao10301 opened 5 months ago

ckao10301 commented 5 months ago

Error message below when doing image to image:

Reproduce:

  1. Use attached image in "Load Image" node. Sample workflow attached. IMG_0666

  2. Run

  3. Error shows

Error occurred when executing LoadImage:

image file is truncated (0 bytes not processed)

File "C:\Users\ckao1\OneDrive\Desktop\stable swarm\StableSwarmUI\dlbackend\comfy\ComfyUI\execution.py", line 155, in recursive_execute output_data, output_ui = get_output_data(obj, input_data_all) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\ckao1\OneDrive\Desktop\stable swarm\StableSwarmUI\dlbackend\comfy\ComfyUI\execution.py", line 85, in get_output_data return_values = map_node_over_list(obj, input_data_all, obj.FUNCTION, allow_interrupt=True) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\ckao1\OneDrive\Desktop\stable swarm\StableSwarmUI\dlbackend\comfy\ComfyUI\execution.py", line 78, in map_node_over_list results.append(getattr(obj, func)(**slice_dict(input_data_all, i))) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\ckao1\OneDrive\Desktop\stable swarm\StableSwarmUI\dlbackend\comfy\ComfyUI\nodes.py", line 1473, in load_image i = ImageOps.exif_transpose(i) ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\ckao1\OneDrive\Desktop\stable swarm\StableSwarmUI\dlbackend\comfy\python_embeded\Lib\site-packages\PIL\ImageOps.py", line 602, in exif_transpose transposed_image = image.transpose(method) ^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\ckao1\OneDrive\Desktop\stable swarm\StableSwarmUI\dlbackend\comfy\python_embeded\Lib\site-packages\PIL\Image.py", line 2810, in transpose self.load() File "C:\Users\ckao1\OneDrive\Desktop\stable swarm\StableSwarmUI\dlbackend\comfy\python_embeded\Lib\site-packages\PIL\ImageFile.py", line 266, in load raise OSError(msg) sdxlimage2imageworkflow.json

thjan commented 4 months ago

I got a similar issue today and although I do not have a direct solution but here is what I found in the hope it could help.

Short answer: Open your file with an image manipulation tool (gimp for example) and export it, you should be able to use it now.

Long answer:

The problem lies in this code from LoadImage in node.py in the code:

        for i in ImageSequence.Iterator(img):
            i = ImageOps.exif_transpose(i)
            if i.mode == 'I':
                i = i.point(lambda i: i * (1 / 255))

When an HDR image is saved, the jpg file contains on top of the photo a gain map smaller than the image itself. You can check if this exists using tools for examining exif data on your image. For my example image with exiftool exiftool test.jpg will show this:

MPF Version                     : 0100
Number Of Images                : 2
MP Image Flags                  : (none)
MP Image Format                 : JPEG
MP Image Type                   : Undefined
MP Image Length                 : 98010
MP Image Start                  : 2862294
Dependent Image 1 Entry Number  : 0
Dependent Image 2 Entry Number  : 0
Image Width                     : 3072
Image Height                    : 4080
Encoding Process                : Baseline DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:2:0 (2 2)
Hdr Plus Makernote              : (Binary data 68736 bytes, use -b option to extract)

Back to our problematic code snippet, the ImageSequence.Iterator will try to give you two images since two are contained in the file without properly handling the size difference between the two images (the gain map is smaller than the original image). There is an option for Pillow to ignore truncated files, which makes you able to visualize this gain map with the following code snippet:

from PIL import ImageFile, Image, ImageSequence
ImageFile.LOAD_TRUNCATED_IMAGES = True

image = Image.open("test.jpg")
print(f"{image.format = }")
idx = 0
for i in ImageSequence.Iterator(image):
    print(f"{i.size = }\n{i.mode = }\n")
    try:
        i.save(f"{idx}.jpg")
        idx += 1
    except: 
        pass

You can note in the output here that the format is indeed MPO instead of jpg as the extension suggests, and here is the result:

image

Now this might allow you to either prevent this kind of file to be loaded by detecting and fixing it through code (in a custom node or preprocessing) but I am not certain how to graciously handle this in comfyui itself.

ckao10301 commented 4 months ago

@thjan thanks for the great write up. I hope that comfy can provide an update to handle HDR images, but for now I will do a manual conversion before.

fofr commented 4 months ago

Great explanation @thjan, I am also running into this issue on https://github.com/fofr/cog-face-to-many.

time-river commented 4 months ago

The reason is that the pic size is so big exceeding the PIL limination. You can trigger the same error using the following code:

from PIL import Image, ImageOps, ImageSequence

img = Image.open(image_path)
for i in ImageSequence.Iterator(img):
    ImageOps.exif_transpose(i)

How to address it? The simple way is reducing the pic size. https://github.com/fofr/cog-face-to-many/issues/1

ckao10301 commented 3 months ago

@time-river if you mean file size (MB), I don't see that as the cause. This file is 3MB, and I don't have problems with other images up to 20 MB. I think conversion is the best answer for now