Merge pull request #3513 from radarhere/custom_tags

Added custom string TIFF tags
This commit is contained in:
Hugo 2018-12-29 16:47:16 +02:00 committed by GitHub
commit 7351363fe2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 46 additions and 25 deletions

View File

@ -235,7 +235,10 @@ class TestFileLibTiff(LibTiffTestCase):
def test_custom_metadata(self):
custom = {
37000: 4,
37001: 4.2
37001: 4.2,
37002: 'custom tag value',
37003: u'custom tag value',
37004: b'custom tag value'
}
libtiff_version = TiffImagePlugin._libtiff_version()
@ -256,6 +259,8 @@ class TestFileLibTiff(LibTiffTestCase):
reloaded = Image.open(out)
for tag, value in custom.items():
if libtiff and isinstance(value, bytes):
value = value.decode()
self.assertEqual(reloaded.tag_v2[tag], value)
def test_int_dpi(self):

View File

@ -557,26 +557,26 @@ class ImageFileDirectory_v2(MutableMapping):
else:
self.tagtype[tag] = 7
if all(isinstance(v, IFDRational) for v in values):
self.tagtype[tag] = 5
self.tagtype[tag] = TiffTags.RATIONAL
elif all(isinstance(v, int) for v in values):
if all(v < 2 ** 16 for v in values):
self.tagtype[tag] = 3
self.tagtype[tag] = TiffTags.SHORT
else:
self.tagtype[tag] = 4
self.tagtype[tag] = TiffTags.LONG
elif all(isinstance(v, float) for v in values):
self.tagtype[tag] = 12
self.tagtype[tag] = TiffTags.DOUBLE
else:
if py3:
if all(isinstance(v, str) for v in values):
self.tagtype[tag] = 2
self.tagtype[tag] = TiffTags.ASCII
else:
# Never treat data as binary by default on Python 2.
self.tagtype[tag] = 2
self.tagtype[tag] = TiffTags.ASCII
if self.tagtype[tag] == 7 and py3:
if self.tagtype[tag] == TiffTags.UNDEFINED and py3:
values = [value.encode("ascii", 'replace') if isinstance(
value, str) else value]
elif self.tagtype[tag] == 5:
elif self.tagtype[tag] == TiffTags.RATIONAL:
values = [float(v) if isinstance(v, int) else v
for v in values]
@ -592,7 +592,10 @@ class ImageFileDirectory_v2(MutableMapping):
if (info.length == 1) or \
(info.length is None and len(values) == 1 and not legacy_api):
# Don't mess with the legacy api, since it's frozen.
if legacy_api and self.tagtype[tag] in [5, 10]: # rationals
if legacy_api and self.tagtype[tag] in [
TiffTags.RATIONAL,
TiffTags.SIGNED_RATIONAL
]: # rationals
values = values,
try:
dest[tag], = values
@ -649,13 +652,13 @@ class ImageFileDirectory_v2(MutableMapping):
b"".join(self._pack(fmt, value) for value in values))
list(map(_register_basic,
[(3, "H", "short"),
(4, "L", "long"),
(6, "b", "signed byte"),
(8, "h", "signed short"),
(9, "l", "signed long"),
(11, "f", "float"),
(12, "d", "double")]))
[(TiffTags.SHORT, "H", "short"),
(TiffTags.LONG, "L", "long"),
(TiffTags.SIGNED_BYTE, "b", "signed byte"),
(TiffTags.SIGNED_SHORT, "h", "signed short"),
(TiffTags.SIGNED_LONG, "l", "signed long"),
(TiffTags.FLOAT, "f", "float"),
(TiffTags.DOUBLE, "d", "double")]))
@_register_loader(1, 1) # Basic type, except for the legacy API.
def load_byte(self, data, legacy_api=True):
@ -811,7 +814,10 @@ class ImageFileDirectory_v2(MutableMapping):
print("- value:", values)
# count is sum of lengths for string and arbitrary data
count = len(data) if typ in [2, 7] else len(values)
if typ in [TiffTags.ASCII, TiffTags.UNDEFINED]:
count = len(data)
else:
count = len(values)
# figure out if data fits into the entry
if len(data) <= 4:
entries.append((tag, typ, count, data.ljust(4, b"\0"), b""))
@ -1513,12 +1519,16 @@ def _save(im, fp, filename):
getattr(im, 'tag_v2', {}).items(),
legacy_ifd.items()):
# Libtiff can only process certain core items without adding
# them to the custom dictionary. Support has only been been added
# for int and float values
# them to the custom dictionary.
# Support for custom items has only been been added
# for int, float, unicode, string and byte values
if tag not in TiffTags.LIBTIFF_CORE:
if TiffTags.lookup(tag).type == TiffTags.UNDEFINED:
continue
if (distutils.version.StrictVersion(_libtiff_version()) <
distutils.version.StrictVersion("4.0")) \
or not (isinstance(value, int) or isinstance(value, float)):
or not (isinstance(value, (int, float, str, bytes)) or
(not py3 and isinstance(value, unicode))): # noqa: F821
continue
if tag not in atts and tag not in blocklist:
if isinstance(value, str if py3 else unicode): # noqa: F821
@ -1799,7 +1809,7 @@ class AppendingTiffWriter:
# local (not referenced with another offset)
self.rewriteLastShortToLong(offset)
self.f.seek(-10, os.SEEK_CUR)
self.writeShort(4) # rewrite the type to LONG
self.writeShort(TiffTags.LONG) # rewrite the type to LONG
self.f.seek(8, os.SEEK_CUR)
elif isShort:
self.rewriteLastShort(offset)

View File

@ -64,8 +64,12 @@ ASCII = 2
SHORT = 3
LONG = 4
RATIONAL = 5
SIGNED_BYTE = 6
UNDEFINED = 7
SIGNED_SHORT = 8
SIGNED_LONG = 9
SIGNED_RATIONAL = 10
FLOAT = 11
DOUBLE = 12
TAGS_V2 = {

View File

@ -885,9 +885,11 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
}
} else if (PyBytes_Check(value)) {
TRACE(("Setting from Bytes: %d, %s \n", key_int, PyBytes_AsString(value)));
status = ImagingLibTiffSetField(&encoder->state,
(ttag_t) PyInt_AsLong(key),
PyBytes_AsString(value));
if (is_core_tag || !ImagingLibTiffMergeFieldInfo(&encoder->state, TIFF_ASCII, key_int)) {
status = ImagingLibTiffSetField(&encoder->state,
(ttag_t) PyInt_AsLong(key),
PyBytes_AsString(value));
}
} else if (PyTuple_Check(value)) {
Py_ssize_t len,i;
float *floatav;