Skip to content

Commit d728cd5

Browse files
committed
Allow libtiff to write COLORMAP tag
1 parent 7d9ac36 commit d728cd5

4 files changed

Lines changed: 34 additions & 4 deletions

File tree

Tests/test_file_libtiff.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ def test_additional_metadata(self, tmp_path):
203203
del core_items[tag]
204204
except KeyError:
205205
pass
206+
del core_items[320] # colormap is special, tested below
206207

207208
# Type codes:
208209
# 2: "ascii",
@@ -479,6 +480,18 @@ def test_cmyk_save(self, tmp_path):
479480
with Image.open(out) as im2:
480481
assert_image_equal(im, im2)
481482

483+
def test_palette_save(self, tmp_path):
484+
im = hopper("P")
485+
out = str(tmp_path / "temp.tif")
486+
487+
TiffImagePlugin.WRITE_LIBTIFF = True
488+
im.save(out)
489+
TiffImagePlugin.WRITE_LIBTIFF = False
490+
491+
with Image.open(out) as reloaded:
492+
# colormap/palette tag
493+
assert len(reloaded.tag_v2[320]) == 768
494+
482495
def xtest_bw_compression_w_rgb(self, tmp_path):
483496
""" This test passes, but when running all tests causes a failure due
484497
to output on stderr from the error thrown by libtiff. We need to

src/PIL/TiffImagePlugin.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1524,7 +1524,6 @@ def _save(im, fp, filename):
15241524
# BITSPERSAMPLE, etc), passing arrays with a different length will result in
15251525
# segfaults. Block these tags until we add extra validation.
15261526
blocklist = [
1527-
COLORMAP,
15281527
REFERENCEBLACKWHITE,
15291528
SAMPLEFORMAT,
15301529
STRIPBYTECOUNTS,

src/PIL/TiffTags.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,6 @@ def _populate():
483483
65537,
484484
}
485485

486-
LIBTIFF_CORE.remove(320) # Array of short, crashes
487486
LIBTIFF_CORE.remove(301) # Array of short, crashes
488487
LIBTIFF_CORE.remove(532) # Array of long, crashes
489488

src/encode.c

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -671,7 +671,7 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
671671
// This list also exists in TiffTags.py
672672
const int core_tags[] = {
673673
256, 257, 258, 259, 262, 263, 266, 269, 274, 277, 278, 280, 281, 340,
674-
341, 282, 283, 284, 286, 287, 296, 297, 321, 338, 32995, 32998, 32996,
674+
341, 282, 283, 284, 286, 287, 296, 297, 320, 321, 338, 32995, 32998, 32996,
675675
339, 32997, 330, 531, 530, 65537
676676
};
677677

@@ -801,7 +801,26 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
801801
TRACE(("Setting from Tuple: %d \n", key_int));
802802
len = PyTuple_Size(value);
803803

804-
if (type == TIFF_SHORT) {
804+
if (key_int == TIFFTAG_COLORMAP) {
805+
int stride = 256;
806+
if (len != 768) {
807+
PyErr_SetString(PyExc_ValueError, "Requiring 768 items for for Colormap");
808+
return NULL;
809+
}
810+
UINT16 *av;
811+
/* malloc check ok, calloc checks for overflow */
812+
av = calloc(len, sizeof(UINT16));
813+
if (av) {
814+
for (i=0;i<len;i++) {
815+
av[i] = (UINT16)PyLong_AsLong(PyTuple_GetItem(value,i));
816+
}
817+
status = ImagingLibTiffSetField(&encoder->state, (ttag_t) key_int,
818+
av,
819+
av + stride,
820+
av + stride * 2);
821+
free(av);
822+
}
823+
} else if (type == TIFF_SHORT) {
805824
UINT16 *av;
806825
/* malloc check ok, calloc checks for overflow */
807826
av = calloc(len, sizeof(UINT16));

0 commit comments

Comments
 (0)