mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-11-11 04:07:21 +03:00
Merge pull request #4605 from radarhere/byte_tags
Writing TIFF tags: improved BYTE, added UNDEFINED
This commit is contained in:
commit
7d9ac36e42
|
@ -299,9 +299,6 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if libtiff and isinstance(value, bytes):
|
|
||||||
value = value.decode()
|
|
||||||
|
|
||||||
assert reloaded_value == value
|
assert reloaded_value == value
|
||||||
|
|
||||||
# Test with types
|
# Test with types
|
||||||
|
@ -322,6 +319,17 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
)
|
)
|
||||||
TiffImagePlugin.WRITE_LIBTIFF = False
|
TiffImagePlugin.WRITE_LIBTIFF = False
|
||||||
|
|
||||||
|
def test_xmlpacket_tag(self, tmp_path):
|
||||||
|
TiffImagePlugin.WRITE_LIBTIFF = True
|
||||||
|
|
||||||
|
out = str(tmp_path / "temp.tif")
|
||||||
|
hopper().save(out, tiffinfo={700: b"xmlpacket tag"})
|
||||||
|
TiffImagePlugin.WRITE_LIBTIFF = False
|
||||||
|
|
||||||
|
with Image.open(out) as reloaded:
|
||||||
|
if 700 in reloaded.tag_v2:
|
||||||
|
assert reloaded.tag_v2[700] == b"xmlpacket tag"
|
||||||
|
|
||||||
def test_int_dpi(self, tmp_path):
|
def test_int_dpi(self, tmp_path):
|
||||||
# issue #1765
|
# issue #1765
|
||||||
im = hopper("RGB")
|
im = hopper("RGB")
|
||||||
|
@ -667,6 +675,26 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
TiffImagePlugin.READ_LIBTIFF = False
|
TiffImagePlugin.READ_LIBTIFF = False
|
||||||
assert icc == icc_libtiff
|
assert icc == icc_libtiff
|
||||||
|
|
||||||
|
def test_write_icc(self, tmp_path):
|
||||||
|
def check_write(libtiff):
|
||||||
|
TiffImagePlugin.WRITE_LIBTIFF = libtiff
|
||||||
|
|
||||||
|
with Image.open("Tests/images/hopper.iccprofile.tif") as img:
|
||||||
|
icc_profile = img.info["icc_profile"]
|
||||||
|
|
||||||
|
out = str(tmp_path / "temp.tif")
|
||||||
|
img.save(out, icc_profile=icc_profile)
|
||||||
|
with Image.open(out) as reloaded:
|
||||||
|
assert icc_profile == reloaded.info["icc_profile"]
|
||||||
|
|
||||||
|
libtiffs = []
|
||||||
|
if Image.core.libtiff_support_custom_tags:
|
||||||
|
libtiffs.append(True)
|
||||||
|
libtiffs.append(False)
|
||||||
|
|
||||||
|
for libtiff in libtiffs:
|
||||||
|
check_write(libtiff)
|
||||||
|
|
||||||
def test_multipage_compression(self):
|
def test_multipage_compression(self):
|
||||||
with Image.open("Tests/images/compression.tif") as im:
|
with Image.open("Tests/images/compression.tif") as im:
|
||||||
|
|
||||||
|
|
|
@ -319,13 +319,13 @@ def test_empty_values():
|
||||||
|
|
||||||
def test_PhotoshopInfo(tmp_path):
|
def test_PhotoshopInfo(tmp_path):
|
||||||
with Image.open("Tests/images/issue_2278.tif") as im:
|
with Image.open("Tests/images/issue_2278.tif") as im:
|
||||||
assert len(im.tag_v2[34377]) == 1
|
assert len(im.tag_v2[34377]) == 70
|
||||||
assert isinstance(im.tag_v2[34377][0], bytes)
|
assert isinstance(im.tag_v2[34377], bytes)
|
||||||
out = str(tmp_path / "temp.tiff")
|
out = str(tmp_path / "temp.tiff")
|
||||||
im.save(out)
|
im.save(out)
|
||||||
with Image.open(out) as reloaded:
|
with Image.open(out) as reloaded:
|
||||||
assert len(reloaded.tag_v2[34377]) == 1
|
assert len(reloaded.tag_v2[34377]) == 70
|
||||||
assert isinstance(reloaded.tag_v2[34377][0], bytes)
|
assert isinstance(reloaded.tag_v2[34377], bytes)
|
||||||
|
|
||||||
|
|
||||||
def test_too_many_entries():
|
def test_too_many_entries():
|
||||||
|
|
|
@ -553,9 +553,10 @@ class ImageFileDirectory_v2(MutableMapping):
|
||||||
)
|
)
|
||||||
elif all(isinstance(v, float) for v in values):
|
elif all(isinstance(v, float) for v in values):
|
||||||
self.tagtype[tag] = TiffTags.DOUBLE
|
self.tagtype[tag] = TiffTags.DOUBLE
|
||||||
else:
|
elif all(isinstance(v, str) for v in values):
|
||||||
if all(isinstance(v, str) for v in values):
|
|
||||||
self.tagtype[tag] = TiffTags.ASCII
|
self.tagtype[tag] = TiffTags.ASCII
|
||||||
|
elif all(isinstance(v, bytes) for v in values):
|
||||||
|
self.tagtype[tag] = TiffTags.BYTE
|
||||||
|
|
||||||
if self.tagtype[tag] == TiffTags.UNDEFINED:
|
if self.tagtype[tag] == TiffTags.UNDEFINED:
|
||||||
values = [
|
values = [
|
||||||
|
@ -573,8 +574,10 @@ class ImageFileDirectory_v2(MutableMapping):
|
||||||
# Spec'd length == 1, Actual > 1, Warn and truncate. Formerly barfed.
|
# Spec'd length == 1, Actual > 1, Warn and truncate. Formerly barfed.
|
||||||
# No Spec, Actual length 1, Formerly (<4.2) returned a 1 element tuple.
|
# No Spec, Actual length 1, Formerly (<4.2) returned a 1 element tuple.
|
||||||
# Don't mess with the legacy api, since it's frozen.
|
# Don't mess with the legacy api, since it's frozen.
|
||||||
if (info.length == 1) or (
|
if (
|
||||||
info.length is None and len(values) == 1 and not legacy_api
|
(info.length == 1)
|
||||||
|
or self.tagtype[tag] == TiffTags.BYTE
|
||||||
|
or (info.length is None and len(values) == 1 and not legacy_api)
|
||||||
):
|
):
|
||||||
# Don't mess with the legacy api, since it's frozen.
|
# Don't mess with the legacy api, since it's frozen.
|
||||||
if legacy_api and self.tagtype[tag] in [
|
if legacy_api and self.tagtype[tag] in [
|
||||||
|
@ -1546,16 +1549,17 @@ def _save(im, fp, filename):
|
||||||
# Custom items are supported for int, float, unicode, string and byte
|
# Custom items are supported for int, float, unicode, string and byte
|
||||||
# values. Other types and tuples require a tagtype.
|
# values. Other types and tuples require a tagtype.
|
||||||
if tag not in TiffTags.LIBTIFF_CORE:
|
if tag not in TiffTags.LIBTIFF_CORE:
|
||||||
if (
|
if not Image.core.libtiff_support_custom_tags:
|
||||||
TiffTags.lookup(tag).type == TiffTags.UNDEFINED
|
|
||||||
or not Image.core.libtiff_support_custom_tags
|
|
||||||
):
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if tag in ifd.tagtype:
|
if tag in ifd.tagtype:
|
||||||
types[tag] = ifd.tagtype[tag]
|
types[tag] = ifd.tagtype[tag]
|
||||||
elif not (isinstance(value, (int, float, str, bytes))):
|
elif not (isinstance(value, (int, float, str, bytes))):
|
||||||
continue
|
continue
|
||||||
|
else:
|
||||||
|
type = TiffTags.lookup(tag).type
|
||||||
|
if type:
|
||||||
|
types[tag] = type
|
||||||
if tag not in atts and tag not in blocklist:
|
if tag not in atts and tag not in blocklist:
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
atts[tag] = value.encode("ascii", "replace") + b"\0"
|
atts[tag] = value.encode("ascii", "replace") + b"\0"
|
||||||
|
|
32
src/encode.c
32
src/encode.c
|
@ -761,12 +761,6 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PyBytes_Check(value) &&
|
|
||||||
(type == TIFF_BYTE || type == TIFF_UNDEFINED)) {
|
|
||||||
// For backwards compatibility
|
|
||||||
type = TIFF_ASCII;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PyTuple_Check(value)) {
|
if (PyTuple_Check(value)) {
|
||||||
Py_ssize_t len;
|
Py_ssize_t len;
|
||||||
len = PyTuple_Size(value);
|
len = PyTuple_Size(value);
|
||||||
|
@ -790,28 +784,24 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
|
||||||
|
|
||||||
if (!is_core_tag) {
|
if (!is_core_tag) {
|
||||||
// Register field for non core tags.
|
// Register field for non core tags.
|
||||||
|
if (type == TIFF_BYTE) {
|
||||||
|
is_var_length = 1;
|
||||||
|
}
|
||||||
if (ImagingLibTiffMergeFieldInfo(&encoder->state, type, key_int, is_var_length)) {
|
if (ImagingLibTiffMergeFieldInfo(&encoder->state, type, key_int, is_var_length)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_var_length) {
|
if (type == TIFF_BYTE || type == TIFF_UNDEFINED) {
|
||||||
|
status = ImagingLibTiffSetField(&encoder->state,
|
||||||
|
(ttag_t) key_int,
|
||||||
|
PyBytes_Size(value), PyBytes_AsString(value));
|
||||||
|
} else if (is_var_length) {
|
||||||
Py_ssize_t len,i;
|
Py_ssize_t len,i;
|
||||||
TRACE(("Setting from Tuple: %d \n", key_int));
|
TRACE(("Setting from Tuple: %d \n", key_int));
|
||||||
len = PyTuple_Size(value);
|
len = PyTuple_Size(value);
|
||||||
|
|
||||||
if (type == TIFF_BYTE) {
|
if (type == TIFF_SHORT) {
|
||||||
UINT8 *av;
|
|
||||||
/* malloc check ok, calloc checks for overflow */
|
|
||||||
av = calloc(len, sizeof(UINT8));
|
|
||||||
if (av) {
|
|
||||||
for (i=0;i<len;i++) {
|
|
||||||
av[i] = (UINT8)PyLong_AsLong(PyTuple_GetItem(value,i));
|
|
||||||
}
|
|
||||||
status = ImagingLibTiffSetField(&encoder->state, (ttag_t) key_int, len, av);
|
|
||||||
free(av);
|
|
||||||
}
|
|
||||||
} else if (type == TIFF_SHORT) {
|
|
||||||
UINT16 *av;
|
UINT16 *av;
|
||||||
/* malloc check ok, calloc checks for overflow */
|
/* malloc check ok, calloc checks for overflow */
|
||||||
av = calloc(len, sizeof(UINT16));
|
av = calloc(len, sizeof(UINT16));
|
||||||
|
@ -914,10 +904,6 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
|
||||||
status = ImagingLibTiffSetField(&encoder->state,
|
status = ImagingLibTiffSetField(&encoder->state,
|
||||||
(ttag_t) key_int,
|
(ttag_t) key_int,
|
||||||
(FLOAT64)PyFloat_AsDouble(value));
|
(FLOAT64)PyFloat_AsDouble(value));
|
||||||
} else if (type == TIFF_BYTE) {
|
|
||||||
status = ImagingLibTiffSetField(&encoder->state,
|
|
||||||
(ttag_t) key_int,
|
|
||||||
(UINT8)PyLong_AsLong(value));
|
|
||||||
} else if (type == TIFF_SBYTE) {
|
} else if (type == TIFF_SBYTE) {
|
||||||
status = ImagingLibTiffSetField(&encoder->state,
|
status = ImagingLibTiffSetField(&encoder->state,
|
||||||
(ttag_t) key_int,
|
(ttag_t) key_int,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user