Skip to content

Commit c9095cb

Browse files
authored
Support writing IFD, SIGNED_RATIONAL and InkNames TIFF tags (#9276)
2 parents 416f023 + 82cdaa4 commit c9095cb

File tree

3 files changed

+38
-12
lines changed

3 files changed

+38
-12
lines changed

Tests/test_file_libtiff.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,35 @@ def test_subifd(self, tmp_path: Path) -> None:
355355
# Should not segfault
356356
im.save(outfile)
357357

358+
@pytest.mark.parametrize("tagtype", (TiffTags.SIGNED_RATIONAL, TiffTags.IFD))
359+
def test_tag_type(
360+
self, tagtype: int, monkeypatch: pytest.MonkeyPatch, tmp_path: Path
361+
) -> None:
362+
monkeypatch.setattr(TiffImagePlugin, "WRITE_LIBTIFF", True)
363+
364+
ifd = TiffImagePlugin.ImageFileDirectory_v2()
365+
ifd[37000] = 100
366+
ifd.tagtype[37000] = tagtype
367+
368+
out = tmp_path / "temp.tif"
369+
im = Image.new("L", (1, 1))
370+
im.save(out, tiffinfo=ifd)
371+
372+
with Image.open(out) as reloaded:
373+
assert reloaded.tag_v2[37000] == 100
374+
375+
def test_inknames_tag(
376+
self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path
377+
) -> None:
378+
monkeypatch.setattr(TiffImagePlugin, "WRITE_LIBTIFF", True)
379+
380+
out = tmp_path / "temp.tif"
381+
hopper("L").save(out, tiffinfo={333: "name\x00"})
382+
383+
with Image.open(out) as reloaded:
384+
assert isinstance(reloaded, TiffImagePlugin.TiffImageFile)
385+
assert reloaded.tag_v2[333] in ("name", "name\x00")
386+
358387
def test_whitepoint_tag(
359388
self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path
360389
) -> None:

src/PIL/TiffTags.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,6 @@ def _populate() -> None:
558558
LIBTIFF_CORE.remove(255) # We don't have support for subfiletypes
559559
LIBTIFF_CORE.remove(322) # We don't have support for writing tiled images with libtiff
560560
LIBTIFF_CORE.remove(323) # Tiled images
561-
LIBTIFF_CORE.remove(333) # Ink Names either
562561

563562
# Note to advanced users: There may be combinations of these
564563
# parameters and values that when added properly, will work and

src/encode.c

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -668,10 +668,10 @@ PyImaging_LibTiffEncoderNew(PyObject *self, PyObject *args) {
668668
int key_int, status, is_core_tag, is_var_length, num_core_tags, i;
669669
TIFFDataType type = TIFF_NOTYPE;
670670
// This list also exists in TiffTags.py
671-
const int core_tags[] = {256, 257, 258, 259, 262, 263, 266, 269, 274,
672-
277, 278, 280, 281, 340, 341, 282, 283, 284,
673-
286, 287, 296, 297, 320, 321, 338, 32995, 32998,
674-
32996, 339, 32997, 330, 531, 530, 65537, 301, 532};
671+
const int core_tags[] = {256, 257, 258, 259, 262, 263, 266, 269, 274, 277,
672+
278, 280, 281, 282, 283, 284, 286, 287, 296, 297,
673+
301, 320, 321, 330, 333, 338, 339, 340, 341, 530,
674+
531, 532, 32995, 32996, 32997, 32998, 65537};
675675

676676
Py_ssize_t tags_size;
677677
PyObject *item;
@@ -821,7 +821,8 @@ PyImaging_LibTiffEncoderNew(PyObject *self, PyObject *args) {
821821
}
822822
}
823823

824-
if (type == TIFF_BYTE || type == TIFF_UNDEFINED) {
824+
if (type == TIFF_BYTE || type == TIFF_UNDEFINED ||
825+
key_int == TIFFTAG_INKNAMES) {
825826
status = ImagingLibTiffSetField(
826827
&encoder->state,
827828
(ttag_t)key_int,
@@ -973,7 +974,7 @@ PyImaging_LibTiffEncoderNew(PyObject *self, PyObject *args) {
973974
status = ImagingLibTiffSetField(
974975
&encoder->state, (ttag_t)key_int, (UINT16)PyLong_AsLong(value)
975976
);
976-
} else if (type == TIFF_LONG) {
977+
} else if (type == TIFF_LONG || type == TIFF_IFD) {
977978
status = ImagingLibTiffSetField(
978979
&encoder->state, (ttag_t)key_int, (UINT32)PyLong_AsLong(value)
979980
);
@@ -989,10 +990,6 @@ PyImaging_LibTiffEncoderNew(PyObject *self, PyObject *args) {
989990
status = ImagingLibTiffSetField(
990991
&encoder->state, (ttag_t)key_int, (FLOAT32)PyFloat_AsDouble(value)
991992
);
992-
} else if (type == TIFF_DOUBLE) {
993-
status = ImagingLibTiffSetField(
994-
&encoder->state, (ttag_t)key_int, (FLOAT64)PyFloat_AsDouble(value)
995-
);
996993
} else if (type == TIFF_SBYTE) {
997994
status = ImagingLibTiffSetField(
998995
&encoder->state, (ttag_t)key_int, (INT8)PyLong_AsLong(value)
@@ -1001,7 +998,8 @@ PyImaging_LibTiffEncoderNew(PyObject *self, PyObject *args) {
1001998
status = ImagingLibTiffSetField(
1002999
&encoder->state, (ttag_t)key_int, PyBytes_AsString(value)
10031000
);
1004-
} else if (type == TIFF_RATIONAL) {
1001+
} else if (type == TIFF_DOUBLE || type == TIFF_SRATIONAL ||
1002+
type == TIFF_RATIONAL) {
10051003
status = ImagingLibTiffSetField(
10061004
&encoder->state, (ttag_t)key_int, (FLOAT64)PyFloat_AsDouble(value)
10071005
);

0 commit comments

Comments
 (0)