Unverified Commit 89237852 authored by AUTOMATIC1111's avatar AUTOMATIC1111 Committed by GitHub
Browse files

Merge pull request #5119 from 0xb8/master

Atomically rename saved image to avoid race condition with other processes
parents 59c2dfe1 185ab3cb
Loading
Loading
Loading
Loading
+29 −22
Original line number Diff line number Diff line
@@ -501,14 +501,11 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i
    image = params.image
    fullfn = params.filename
    info = params.pnginfo.get(pnginfo_section_name, None)
    fullfn_without_extension, extension = os.path.splitext(params.filename)

    def exif_bytes():
        return piexif.dump({
            "Exif": {
                piexif.ExifIFD.UserComment: piexif.helper.UserComment.dump(info or "", encoding="unicode")
            },
        })
    def _atomically_save_image(image_to_save, filename_without_extension, extension):
        # save image with .tmp extension to avoid race condition when another process detects new image in the directory
        temp_file_path = filename_without_extension + ".tmp"
        image_format = Image.registered_extensions()[extension]

        if extension.lower() == '.png':
            pnginfo_data = PngImagePlugin.PngInfo()
@@ -516,15 +513,27 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i
                for k, v in params.pnginfo.items():
                    pnginfo_data.add_text(k, str(v))

        image.save(fullfn, quality=opts.jpeg_quality, pnginfo=pnginfo_data)
            image_to_save.save(temp_file_path, format=image_format, quality=opts.jpeg_quality, pnginfo=pnginfo_data)

        elif extension.lower() in (".jpg", ".jpeg", ".webp"):
        image.save(fullfn, quality=opts.jpeg_quality)
            image_to_save.save(temp_file_path, format=image_format, quality=opts.jpeg_quality)

            if opts.enable_pnginfo and info is not None:
            piexif.insert(exif_bytes(), fullfn)
                exif_bytes = piexif.dump({
                    "Exif": {
                        piexif.ExifIFD.UserComment: piexif.helper.UserComment.dump(info or "", encoding="unicode")
                    },
                })

                piexif.insert(exif_bytes, temp_file_path)
        else:
        image.save(fullfn, quality=opts.jpeg_quality)
            image_to_save.save(temp_file_path, format=image_format, quality=opts.jpeg_quality)

        # atomically rename the file with correct extension
        os.replace(temp_file_path, filename_without_extension + extension)

    fullfn_without_extension, extension = os.path.splitext(params.filename)
    _atomically_save_image(image, fullfn_without_extension, extension)

    image.already_saved_as = fullfn

@@ -538,9 +547,7 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i
        elif oversize:
            image = image.resize((image.width * target_side_length // image.height, target_side_length), LANCZOS)

        image.save(fullfn_without_extension + ".jpg", quality=opts.jpeg_quality)
        if opts.enable_pnginfo and info is not None:
            piexif.insert(exif_bytes(), fullfn_without_extension + ".jpg")
        _atomically_save_image(image, fullfn_without_extension, ".jpg")

    if opts.save_txt and info is not None:
        txt_fullfn = f"{fullfn_without_extension}.txt"