mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-11-04 01:47:47 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			493 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			493 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
from __future__ import annotations
 | 
						|
 | 
						|
import io
 | 
						|
import struct
 | 
						|
from pathlib import Path
 | 
						|
 | 
						|
import pytest
 | 
						|
 | 
						|
from PIL import Image, TiffImagePlugin, TiffTags
 | 
						|
from PIL.TiffImagePlugin import IFDRational
 | 
						|
 | 
						|
from .helper import assert_deep_equal, hopper
 | 
						|
 | 
						|
TAG_IDS: dict[str, int] = {
 | 
						|
    info.name: info.value
 | 
						|
    for info in TiffTags.TAGS_V2.values()
 | 
						|
    if info.value is not None
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
def test_rt_metadata(tmp_path: Path) -> None:
 | 
						|
    """Test writing arbitrary metadata into the tiff image directory
 | 
						|
    Use case is ImageJ private tags, one numeric, one arbitrary
 | 
						|
    data.  https://github.com/python-pillow/Pillow/issues/291
 | 
						|
    """
 | 
						|
 | 
						|
    img = hopper()
 | 
						|
 | 
						|
    # Behaviour change: re #1416
 | 
						|
    # Pre ifd rewrite, ImageJMetaData was being written as a string(2),
 | 
						|
    # Post ifd rewrite, it's defined as arbitrary bytes(7). It should
 | 
						|
    # roundtrip with the actual bytes, rather than stripped text
 | 
						|
    # of the premerge tests.
 | 
						|
    #
 | 
						|
    # For text items, we still have to decode('ascii','replace') because
 | 
						|
    # the tiff file format can't take 8 bit bytes in that field.
 | 
						|
 | 
						|
    base_text_data = "This is some arbitrary metadata for a text field"
 | 
						|
    bin_data = base_text_data.encode("ascii") + b" \xff"
 | 
						|
    text_data = base_text_data + " " + chr(255)
 | 
						|
    reloaded_text_data = base_text_data + " ?"
 | 
						|
    float_data = 12.345
 | 
						|
    double_data = 67.89
 | 
						|
    info = TiffImagePlugin.ImageFileDirectory()
 | 
						|
 | 
						|
    ImageJMetaData = TAG_IDS["ImageJMetaData"]
 | 
						|
    ImageJMetaDataByteCounts = TAG_IDS["ImageJMetaDataByteCounts"]
 | 
						|
    ImageDescription = TAG_IDS["ImageDescription"]
 | 
						|
 | 
						|
    info[ImageJMetaDataByteCounts] = len(bin_data)
 | 
						|
    info[ImageJMetaData] = bin_data
 | 
						|
    info[TAG_IDS["RollAngle"]] = float_data
 | 
						|
    info.tagtype[TAG_IDS["RollAngle"]] = 11
 | 
						|
    info[TAG_IDS["YawAngle"]] = double_data
 | 
						|
    info.tagtype[TAG_IDS["YawAngle"]] = 12
 | 
						|
 | 
						|
    info[ImageDescription] = text_data
 | 
						|
 | 
						|
    f = str(tmp_path / "temp.tif")
 | 
						|
 | 
						|
    img.save(f, tiffinfo=info)
 | 
						|
 | 
						|
    with Image.open(f) as loaded:
 | 
						|
        assert loaded.tag[ImageJMetaDataByteCounts] == (len(bin_data),)
 | 
						|
        assert loaded.tag_v2[ImageJMetaDataByteCounts] == (len(bin_data),)
 | 
						|
 | 
						|
        assert loaded.tag[ImageJMetaData] == bin_data
 | 
						|
        assert loaded.tag_v2[ImageJMetaData] == bin_data
 | 
						|
 | 
						|
        assert loaded.tag[ImageDescription] == (reloaded_text_data,)
 | 
						|
        assert loaded.tag_v2[ImageDescription] == reloaded_text_data
 | 
						|
 | 
						|
        loaded_float = loaded.tag[TAG_IDS["RollAngle"]][0]
 | 
						|
        assert round(abs(loaded_float - float_data), 5) == 0
 | 
						|
        loaded_double = loaded.tag[TAG_IDS["YawAngle"]][0]
 | 
						|
        assert round(abs(loaded_double - double_data), 7) == 0
 | 
						|
 | 
						|
    # check with 2 element ImageJMetaDataByteCounts, issue #2006
 | 
						|
 | 
						|
    info[ImageJMetaDataByteCounts] = (8, len(bin_data) - 8)
 | 
						|
    img.save(f, tiffinfo=info)
 | 
						|
    with Image.open(f) as loaded:
 | 
						|
        assert loaded.tag[ImageJMetaDataByteCounts] == (8, len(bin_data) - 8)
 | 
						|
        assert loaded.tag_v2[ImageJMetaDataByteCounts] == (8, len(bin_data) - 8)
 | 
						|
 | 
						|
 | 
						|
def test_read_metadata() -> None:
 | 
						|
    with Image.open("Tests/images/hopper_g4.tif") as img:
 | 
						|
        assert {
 | 
						|
            "YResolution": IFDRational(4294967295, 113653537),
 | 
						|
            "PlanarConfiguration": 1,
 | 
						|
            "BitsPerSample": (1,),
 | 
						|
            "ImageLength": 128,
 | 
						|
            "Compression": 4,
 | 
						|
            "FillOrder": 1,
 | 
						|
            "RowsPerStrip": 128,
 | 
						|
            "ResolutionUnit": 3,
 | 
						|
            "PhotometricInterpretation": 0,
 | 
						|
            "PageNumber": (0, 1),
 | 
						|
            "XResolution": IFDRational(4294967295, 113653537),
 | 
						|
            "ImageWidth": 128,
 | 
						|
            "Orientation": 1,
 | 
						|
            "StripByteCounts": (1968,),
 | 
						|
            "SamplesPerPixel": 1,
 | 
						|
            "StripOffsets": (8,),
 | 
						|
        } == img.tag_v2.named()
 | 
						|
 | 
						|
        assert {
 | 
						|
            "YResolution": ((4294967295, 113653537),),
 | 
						|
            "PlanarConfiguration": (1,),
 | 
						|
            "BitsPerSample": (1,),
 | 
						|
            "ImageLength": (128,),
 | 
						|
            "Compression": (4,),
 | 
						|
            "FillOrder": (1,),
 | 
						|
            "RowsPerStrip": (128,),
 | 
						|
            "ResolutionUnit": (3,),
 | 
						|
            "PhotometricInterpretation": (0,),
 | 
						|
            "PageNumber": (0, 1),
 | 
						|
            "XResolution": ((4294967295, 113653537),),
 | 
						|
            "ImageWidth": (128,),
 | 
						|
            "Orientation": (1,),
 | 
						|
            "StripByteCounts": (1968,),
 | 
						|
            "SamplesPerPixel": (1,),
 | 
						|
            "StripOffsets": (8,),
 | 
						|
        } == img.tag.named()
 | 
						|
 | 
						|
 | 
						|
def test_write_metadata(tmp_path: Path) -> None:
 | 
						|
    """Test metadata writing through the python code"""
 | 
						|
    with Image.open("Tests/images/hopper.tif") as img:
 | 
						|
        f = str(tmp_path / "temp.tiff")
 | 
						|
        del img.tag[278]
 | 
						|
        img.save(f, tiffinfo=img.tag)
 | 
						|
 | 
						|
        original = img.tag_v2.named()
 | 
						|
 | 
						|
    with Image.open(f) as loaded:
 | 
						|
        reloaded = loaded.tag_v2.named()
 | 
						|
 | 
						|
    ignored = ["StripByteCounts", "RowsPerStrip", "PageNumber", "StripOffsets"]
 | 
						|
 | 
						|
    for tag, value in reloaded.items():
 | 
						|
        if tag in ignored:
 | 
						|
            continue
 | 
						|
        if isinstance(original[tag], tuple) and isinstance(
 | 
						|
            original[tag][0], IFDRational
 | 
						|
        ):
 | 
						|
            # Need to compare element by element in the tuple,
 | 
						|
            # not comparing tuples of object references
 | 
						|
            assert_deep_equal(
 | 
						|
                original[tag],
 | 
						|
                value,
 | 
						|
                f"{tag} didn't roundtrip, {original[tag]}, {value}",
 | 
						|
            )
 | 
						|
        else:
 | 
						|
            assert (
 | 
						|
                original[tag] == value
 | 
						|
            ), f"{tag} didn't roundtrip, {original[tag]}, {value}"
 | 
						|
 | 
						|
    for tag, value in original.items():
 | 
						|
        if tag not in ignored:
 | 
						|
            assert value == reloaded[tag], f"{tag} didn't roundtrip"
 | 
						|
 | 
						|
 | 
						|
def test_change_stripbytecounts_tag_type(tmp_path: Path) -> None:
 | 
						|
    out = str(tmp_path / "temp.tiff")
 | 
						|
    with Image.open("Tests/images/hopper.tif") as im:
 | 
						|
        info = im.tag_v2
 | 
						|
        del info[278]
 | 
						|
 | 
						|
        # Resize the image so that STRIPBYTECOUNTS will be larger than a SHORT
 | 
						|
        im = im.resize((500, 500))
 | 
						|
        info[TiffImagePlugin.IMAGEWIDTH] = im.width
 | 
						|
 | 
						|
        # STRIPBYTECOUNTS can be a SHORT or a LONG
 | 
						|
        info.tagtype[TiffImagePlugin.STRIPBYTECOUNTS] = TiffTags.SHORT
 | 
						|
 | 
						|
        im.save(out, tiffinfo=info)
 | 
						|
 | 
						|
    with Image.open(out) as reloaded:
 | 
						|
        assert reloaded.tag_v2.tagtype[TiffImagePlugin.STRIPBYTECOUNTS] == TiffTags.LONG
 | 
						|
 | 
						|
 | 
						|
def test_save_multiple_stripoffsets() -> None:
 | 
						|
    ifd = TiffImagePlugin.ImageFileDirectory_v2()
 | 
						|
    ifd[TiffImagePlugin.STRIPOFFSETS] = (123, 456)
 | 
						|
    assert ifd.tagtype[TiffImagePlugin.STRIPOFFSETS] == TiffTags.LONG
 | 
						|
 | 
						|
    # all values are in little-endian
 | 
						|
    assert ifd.tobytes() == (
 | 
						|
        # number of tags == 1
 | 
						|
        b"\x01\x00"
 | 
						|
        # tag id (2 bytes), type (2 bytes), count (4 bytes), value (4 bytes)
 | 
						|
        # TiffImagePlugin.STRIPOFFSETS, TiffTags.LONG, 2, 18
 | 
						|
        # where STRIPOFFSETS is 273, LONG is 4
 | 
						|
        # and 18 is the offset of the tag data
 | 
						|
        b"\x11\x01\x04\x00\x02\x00\x00\x00\x12\x00\x00\x00"
 | 
						|
        # end of entries
 | 
						|
        b"\x00\x00\x00\x00"
 | 
						|
        # 26 is the total number of bytes output,
 | 
						|
        # the offset for any auxiliary strip data that will then be appended
 | 
						|
        # (123 + 26, 456 + 26) == (149, 482)
 | 
						|
        b"\x95\x00\x00\x00\xe2\x01\x00\x00"
 | 
						|
    )
 | 
						|
 | 
						|
 | 
						|
def test_no_duplicate_50741_tag() -> None:
 | 
						|
    assert TAG_IDS["MakerNoteSafety"] == 50741
 | 
						|
    assert TAG_IDS["BestQualityScale"] == 50780
 | 
						|
 | 
						|
 | 
						|
def test_iptc(tmp_path: Path) -> None:
 | 
						|
    out = str(tmp_path / "temp.tiff")
 | 
						|
    with Image.open("Tests/images/hopper.Lab.tif") as im:
 | 
						|
        im.save(out)
 | 
						|
 | 
						|
 | 
						|
@pytest.mark.parametrize("value, expected", ((b"test", "test"), (1, "1")))
 | 
						|
def test_writing_other_types_to_ascii(
 | 
						|
    value: bytes | int, expected: str, tmp_path: Path
 | 
						|
) -> None:
 | 
						|
    info = TiffImagePlugin.ImageFileDirectory_v2()
 | 
						|
 | 
						|
    tag = TiffTags.TAGS_V2[271]
 | 
						|
    assert tag.type == TiffTags.ASCII
 | 
						|
 | 
						|
    info[271] = value
 | 
						|
 | 
						|
    im = hopper()
 | 
						|
    out = str(tmp_path / "temp.tiff")
 | 
						|
    im.save(out, tiffinfo=info)
 | 
						|
 | 
						|
    with Image.open(out) as reloaded:
 | 
						|
        assert reloaded.tag_v2[271] == expected
 | 
						|
 | 
						|
 | 
						|
@pytest.mark.parametrize("value", (1, IFDRational(1)))
 | 
						|
def test_writing_other_types_to_bytes(value: int | IFDRational, tmp_path: Path) -> None:
 | 
						|
    im = hopper()
 | 
						|
    info = TiffImagePlugin.ImageFileDirectory_v2()
 | 
						|
 | 
						|
    tag = TiffTags.TAGS_V2[700]
 | 
						|
    assert tag.type == TiffTags.BYTE
 | 
						|
 | 
						|
    info[700] = value
 | 
						|
 | 
						|
    out = str(tmp_path / "temp.tiff")
 | 
						|
    im.save(out, tiffinfo=info)
 | 
						|
 | 
						|
    with Image.open(out) as reloaded:
 | 
						|
        assert reloaded.tag_v2[700] == b"\x01"
 | 
						|
 | 
						|
 | 
						|
@pytest.mark.parametrize("value", (1, IFDRational(1)))
 | 
						|
def test_writing_other_types_to_undefined(
 | 
						|
    value: int | IFDRational, tmp_path: Path
 | 
						|
) -> None:
 | 
						|
    im = hopper()
 | 
						|
    info = TiffImagePlugin.ImageFileDirectory_v2()
 | 
						|
 | 
						|
    tag = TiffTags.TAGS_V2[33723]
 | 
						|
    assert tag.type == TiffTags.UNDEFINED
 | 
						|
 | 
						|
    info[33723] = value
 | 
						|
 | 
						|
    out = str(tmp_path / "temp.tiff")
 | 
						|
    im.save(out, tiffinfo=info)
 | 
						|
 | 
						|
    with Image.open(out) as reloaded:
 | 
						|
        assert reloaded.tag_v2[33723] == b"1"
 | 
						|
 | 
						|
 | 
						|
def test_undefined_zero(tmp_path: Path) -> None:
 | 
						|
    # Check that the tag has not been changed since this test was created
 | 
						|
    tag = TiffTags.TAGS_V2[45059]
 | 
						|
    assert tag.type == TiffTags.UNDEFINED
 | 
						|
    assert tag.length == 0
 | 
						|
 | 
						|
    info = TiffImagePlugin.ImageFileDirectory(b"II*\x00\x08\x00\x00\x00")
 | 
						|
    info[45059] = b"test"
 | 
						|
 | 
						|
    # Assert that the tag value does not change by setting it to itself
 | 
						|
    original = info[45059]
 | 
						|
    info[45059] = info[45059]
 | 
						|
    assert info[45059] == original
 | 
						|
 | 
						|
 | 
						|
def test_empty_metadata() -> None:
 | 
						|
    f = io.BytesIO(b"II*\x00\x08\x00\x00\x00")
 | 
						|
    head = f.read(8)
 | 
						|
    info = TiffImagePlugin.ImageFileDirectory(head)
 | 
						|
    # Should not raise struct.error.
 | 
						|
    with pytest.warns(UserWarning):
 | 
						|
        info.load(f)
 | 
						|
 | 
						|
 | 
						|
def test_iccprofile(tmp_path: Path) -> None:
 | 
						|
    # https://github.com/python-pillow/Pillow/issues/1462
 | 
						|
    out = str(tmp_path / "temp.tiff")
 | 
						|
    with Image.open("Tests/images/hopper.iccprofile.tif") as im:
 | 
						|
        im.save(out)
 | 
						|
 | 
						|
    with Image.open(out) as reloaded:
 | 
						|
        assert not isinstance(im.info["icc_profile"], tuple)
 | 
						|
        assert im.info["icc_profile"] == reloaded.info["icc_profile"]
 | 
						|
 | 
						|
 | 
						|
def test_iccprofile_binary() -> None:
 | 
						|
    # https://github.com/python-pillow/Pillow/issues/1526
 | 
						|
    # We should be able to load this,
 | 
						|
    # but probably won't be able to save it.
 | 
						|
 | 
						|
    with Image.open("Tests/images/hopper.iccprofile_binary.tif") as im:
 | 
						|
        assert im.tag_v2.tagtype[34675] == 1
 | 
						|
        assert im.info["icc_profile"]
 | 
						|
 | 
						|
 | 
						|
def test_iccprofile_save_png(tmp_path: Path) -> None:
 | 
						|
    with Image.open("Tests/images/hopper.iccprofile.tif") as im:
 | 
						|
        outfile = str(tmp_path / "temp.png")
 | 
						|
        im.save(outfile)
 | 
						|
 | 
						|
 | 
						|
def test_iccprofile_binary_save_png(tmp_path: Path) -> None:
 | 
						|
    with Image.open("Tests/images/hopper.iccprofile_binary.tif") as im:
 | 
						|
        outfile = str(tmp_path / "temp.png")
 | 
						|
        im.save(outfile)
 | 
						|
 | 
						|
 | 
						|
def test_exif_div_zero(tmp_path: Path) -> None:
 | 
						|
    im = hopper()
 | 
						|
    info = TiffImagePlugin.ImageFileDirectory_v2()
 | 
						|
    info[41988] = TiffImagePlugin.IFDRational(0, 0)
 | 
						|
 | 
						|
    out = str(tmp_path / "temp.tiff")
 | 
						|
    im.save(out, tiffinfo=info, compression="raw")
 | 
						|
 | 
						|
    with Image.open(out) as reloaded:
 | 
						|
        assert 0 == reloaded.tag_v2[41988].numerator
 | 
						|
        assert 0 == reloaded.tag_v2[41988].denominator
 | 
						|
 | 
						|
 | 
						|
def test_ifd_unsigned_rational(tmp_path: Path) -> None:
 | 
						|
    im = hopper()
 | 
						|
    info = TiffImagePlugin.ImageFileDirectory_v2()
 | 
						|
 | 
						|
    max_long = 2**32 - 1
 | 
						|
 | 
						|
    # 4 bytes unsigned long
 | 
						|
    numerator = max_long
 | 
						|
 | 
						|
    info[41493] = TiffImagePlugin.IFDRational(numerator, 1)
 | 
						|
 | 
						|
    out = str(tmp_path / "temp.tiff")
 | 
						|
    im.save(out, tiffinfo=info, compression="raw")
 | 
						|
 | 
						|
    with Image.open(out) as reloaded:
 | 
						|
        assert max_long == reloaded.tag_v2[41493].numerator
 | 
						|
        assert 1 == reloaded.tag_v2[41493].denominator
 | 
						|
 | 
						|
    # out of bounds of 4 byte unsigned long
 | 
						|
    numerator = max_long + 1
 | 
						|
 | 
						|
    info[41493] = TiffImagePlugin.IFDRational(numerator, 1)
 | 
						|
 | 
						|
    out = str(tmp_path / "temp.tiff")
 | 
						|
    im.save(out, tiffinfo=info, compression="raw")
 | 
						|
 | 
						|
    with Image.open(out) as reloaded:
 | 
						|
        assert max_long == reloaded.tag_v2[41493].numerator
 | 
						|
        assert 1 == reloaded.tag_v2[41493].denominator
 | 
						|
 | 
						|
 | 
						|
def test_ifd_signed_rational(tmp_path: Path) -> None:
 | 
						|
    im = hopper()
 | 
						|
    info = TiffImagePlugin.ImageFileDirectory_v2()
 | 
						|
 | 
						|
    # pair of 4 byte signed longs
 | 
						|
    numerator = 2**31 - 1
 | 
						|
    denominator = -(2**31)
 | 
						|
 | 
						|
    info[37380] = TiffImagePlugin.IFDRational(numerator, denominator)
 | 
						|
 | 
						|
    out = str(tmp_path / "temp.tiff")
 | 
						|
    im.save(out, tiffinfo=info, compression="raw")
 | 
						|
 | 
						|
    with Image.open(out) as reloaded:
 | 
						|
        assert numerator == reloaded.tag_v2[37380].numerator
 | 
						|
        assert denominator == reloaded.tag_v2[37380].denominator
 | 
						|
 | 
						|
    numerator = -(2**31)
 | 
						|
    denominator = 2**31 - 1
 | 
						|
 | 
						|
    info[37380] = TiffImagePlugin.IFDRational(numerator, denominator)
 | 
						|
 | 
						|
    out = str(tmp_path / "temp.tiff")
 | 
						|
    im.save(out, tiffinfo=info, compression="raw")
 | 
						|
 | 
						|
    with Image.open(out) as reloaded:
 | 
						|
        assert numerator == reloaded.tag_v2[37380].numerator
 | 
						|
        assert denominator == reloaded.tag_v2[37380].denominator
 | 
						|
 | 
						|
    # out of bounds of 4 byte signed long
 | 
						|
    numerator = -(2**31) - 1
 | 
						|
    denominator = 1
 | 
						|
 | 
						|
    info[37380] = TiffImagePlugin.IFDRational(numerator, denominator)
 | 
						|
 | 
						|
    out = str(tmp_path / "temp.tiff")
 | 
						|
    im.save(out, tiffinfo=info, compression="raw")
 | 
						|
 | 
						|
    with Image.open(out) as reloaded:
 | 
						|
        assert 2**31 - 1 == reloaded.tag_v2[37380].numerator
 | 
						|
        assert -1 == reloaded.tag_v2[37380].denominator
 | 
						|
 | 
						|
 | 
						|
def test_ifd_signed_long(tmp_path: Path) -> None:
 | 
						|
    im = hopper()
 | 
						|
    info = TiffImagePlugin.ImageFileDirectory_v2()
 | 
						|
 | 
						|
    info[37000] = -60000
 | 
						|
 | 
						|
    out = str(tmp_path / "temp.tiff")
 | 
						|
    im.save(out, tiffinfo=info, compression="raw")
 | 
						|
 | 
						|
    with Image.open(out) as reloaded:
 | 
						|
        assert reloaded.tag_v2[37000] == -60000
 | 
						|
 | 
						|
 | 
						|
def test_empty_values() -> None:
 | 
						|
    data = io.BytesIO(
 | 
						|
        b"II*\x00\x08\x00\x00\x00\x03\x00\x1a\x01\x05\x00\x00\x00\x00\x00"
 | 
						|
        b"\x00\x00\x00\x00\x1b\x01\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00"
 | 
						|
        b"\x98\x82\x02\x00\x07\x00\x00\x002\x00\x00\x00\x00\x00\x00\x00a "
 | 
						|
        b"text\x00\x00"
 | 
						|
    )
 | 
						|
    head = data.read(8)
 | 
						|
    info = TiffImagePlugin.ImageFileDirectory_v2(head)
 | 
						|
    info.load(data)
 | 
						|
    # Should not raise ValueError.
 | 
						|
    info_dict = dict(info)
 | 
						|
    assert 33432 in info_dict
 | 
						|
 | 
						|
 | 
						|
def test_photoshop_info(tmp_path: Path) -> None:
 | 
						|
    with Image.open("Tests/images/issue_2278.tif") as im:
 | 
						|
        assert len(im.tag_v2[34377]) == 70
 | 
						|
        assert isinstance(im.tag_v2[34377], bytes)
 | 
						|
        out = str(tmp_path / "temp.tiff")
 | 
						|
        im.save(out)
 | 
						|
    with Image.open(out) as reloaded:
 | 
						|
        assert len(reloaded.tag_v2[34377]) == 70
 | 
						|
        assert isinstance(reloaded.tag_v2[34377], bytes)
 | 
						|
 | 
						|
 | 
						|
def test_too_many_entries() -> None:
 | 
						|
    ifd = TiffImagePlugin.ImageFileDirectory_v2()
 | 
						|
 | 
						|
    #    277: ("SamplesPerPixel", SHORT, 1),
 | 
						|
    ifd._tagdata[277] = struct.pack("<hh", 4, 4)
 | 
						|
    ifd.tagtype[277] = TiffTags.SHORT
 | 
						|
 | 
						|
    # Should not raise ValueError.
 | 
						|
    with pytest.warns(UserWarning):
 | 
						|
        assert ifd[277] == 4
 | 
						|
 | 
						|
 | 
						|
def test_tag_group_data() -> None:
 | 
						|
    base_ifd = TiffImagePlugin.ImageFileDirectory_v2()
 | 
						|
    interop_ifd = TiffImagePlugin.ImageFileDirectory_v2(group=40965)
 | 
						|
    for ifd in (base_ifd, interop_ifd):
 | 
						|
        ifd[2] = "test"
 | 
						|
        ifd[256] = 10
 | 
						|
 | 
						|
    assert base_ifd.tagtype[256] == 4
 | 
						|
    assert interop_ifd.tagtype[256] != base_ifd.tagtype[256]
 | 
						|
 | 
						|
    assert interop_ifd.tagtype[2] == 7
 | 
						|
    assert base_ifd.tagtype[2] != interop_ifd.tagtype[256]
 | 
						|
 | 
						|
 | 
						|
def test_empty_subifd(tmp_path: Path) -> None:
 | 
						|
    out = str(tmp_path / "temp.jpg")
 | 
						|
 | 
						|
    im = hopper()
 | 
						|
    exif = im.getexif()
 | 
						|
    exif[TiffImagePlugin.EXIFIFD] = {}
 | 
						|
    im.save(out, exif=exif)
 | 
						|
 | 
						|
    with Image.open(out) as reloaded:
 | 
						|
        exif = reloaded.getexif()
 | 
						|
        assert exif.get_ifd(TiffImagePlugin.EXIFIFD) == {}
 |