python-pillow / Pillow

Python Imaging Library (Fork)
https://python-pillow.org
Other
12.32k stars 2.23k forks source link

Saving Multi-frame TIFF Images with different DPI #8552

Closed ricaun closed 1 week ago

ricaun commented 1 week ago

I trying to save a Tiff file with multiple images with different dpi.

Looks like is only possible to set one dpi for the whole tiff file, and after looking in the python code for the tiff _save, does not seen to have a way to use the current dpi for each frame.

Here is a code sample that I'm using the join two PNG with different dpi in a single tiff file, and after opening the output tiff file the dpi of the append_images is lost.

from PIL import Image

# Function to load PNG images, and save as multi-page TIFF
def save_as_multipage_tiff_with_dpi(output_filename, png_files_with_dpi):
    images = []

    # Load each PNG file and convert to RGB if needed, then append to images list
    for filename in png_files_with_dpi:
        img = Image.open(filename).convert("RGB")
        print(f"Png {img} {img.info['dpi']}")
        images.append(img)

    # Save the images as a multi-page TIFF with specified DPI
    images[0].save(
        output_filename,
        save_all=True,
        append_images=images[1:],
        dpi=images[0].info['dpi'],
        format="TIFF"
    )

    # Open output file
    with Image.open(output_filename) as img:
        for frame in range(img.n_frames):
            img.seek(frame)
            print(f"Frame {img} {img.info['dpi']}")

output_tiff_file = 'multi_page_output.tiff'
png_files_with_dpi = [
    'image-96dpi.png',
    'image-192dpi.png',
]
save_as_multipage_tiff_with_dpi(output_tiff_file, png_files_with_dpi)

This is the output for that code:

Png <PIL.Image.Image image mode=RGB size=32x32 at 0x201FEC3AF30> (96, 96)
Png <PIL.Image.Image image mode=RGB size=64x64 at 0x201FE88AF00> (192, 192)
Frame <PIL.TiffImagePlugin.TiffImageFile image mode=RGB size=32x32 at 0x201FECD8260> (96, 96)
Frame <PIL.TiffImagePlugin.TiffImageFile image mode=RGB size=64x64 at 0x201FECD8260> (96, 96)

Both frames in the tiff have the same 96 dpi, I need to be 96 and 192, like the source images.

radarhere commented 1 week ago

Hi. See what you think of this.

from PIL import Image, TiffImagePlugin

output_filename = "out.tiff"
images = [
    Image.new("RGB", (100, 100)),
    Image.new("RGB", (100, 100))
]
images[0].info["dpi"] = (100, 100)
images[1].info["dpi"] = (50, 50)

with TiffImagePlugin.AppendingTiffWriter(output_filename, new=True) as tf:
    for im in images:
        im.save(tf, dpi=im.info["dpi"])
        tf.newFrame()

# Open output file
with Image.open(output_filename) as img:
    for frame in range(img.n_frames):
        img.seek(frame)
        print(f"Frame {img} {img.info['dpi']}")
ricaun commented 1 week ago

Yes! Great!

TiffImagePlugin.AppendingTiffWriter works perfectly, exactly what I was looking for.

Thanks for the sample, helps a lot!