mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-26 09:14:27 +03:00
Major rewrite of TIFF ImageFileDirectory.
Do not represent scalar tags as 1-element tuples. Keep tag type and count information in TiffTags.TAGS. Normalize data in ImageFileDirectory.__setitem__: wrap and unwrap tuples as needed, convert rationals to floats. (To ensure consistency, make the "tags" attribute private.) Interpret byte data as a series of integers rather than a bytearray (which should only map to the "undefined" type). On Python3, if a str is assigned to an "undefined" tag, encode it as ASCII. Note that a large number of tags have been removed from TiffTags.TAGS because I do not have time to figure out the type and count of each of them. They should be restored before this gets merged in. This obviously breaks backwards compatibility in a lot of ways...
This commit is contained in:
parent
aba7a34036
commit
974bcc074b
File diff suppressed because it is too large
Load Diff
373
PIL/TiffTags.py
373
PIL/TiffTags.py
|
@ -17,291 +17,132 @@
|
|||
# well-known TIFF tags.
|
||||
##
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
class TagInfo(namedtuple("_TagInfo", "value name type length enum")):
|
||||
__slots__ = []
|
||||
|
||||
def __new__(cls, value=None, name="unknown", type=4, length=0, enum=None):
|
||||
return super(TagInfo, cls).__new__(
|
||||
cls, value, name, type, length, enum or {})
|
||||
|
||||
def cvt_enum(self, value):
|
||||
return self.enum.get(value, value)
|
||||
|
||||
##
|
||||
# Map tag numbers (or tag number, tag value tuples) to tag names.
|
||||
# Map tag numbers to tag info.
|
||||
|
||||
TAGS = {
|
||||
|
||||
254: "NewSubfileType",
|
||||
255: "SubfileType",
|
||||
256: "ImageWidth",
|
||||
257: "ImageLength",
|
||||
258: "BitsPerSample",
|
||||
254: ("NewSubfileType", 4, 1),
|
||||
255: ("SubfileType", 3, 1),
|
||||
256: ("ImageWidth", 4, 1),
|
||||
257: ("ImageLength", 4, 1),
|
||||
258: ("BitsPerSample", 3, 0),
|
||||
259: ("Compression", 3, 1,
|
||||
{"Uncompressed": 1, "CCITT 1d": 2, "Group 3 Fax": 3, "Group 4 Fax": 4,
|
||||
"LZW": 5, "JPEG": 6, "PackBits": 32773}),
|
||||
|
||||
259: "Compression",
|
||||
(259, 1): "Uncompressed",
|
||||
(259, 2): "CCITT 1d",
|
||||
(259, 3): "Group 3 Fax",
|
||||
(259, 4): "Group 4 Fax",
|
||||
(259, 5): "LZW",
|
||||
(259, 6): "JPEG",
|
||||
(259, 32773): "PackBits",
|
||||
262: ("PhotometricInterpretation", 3, 1,
|
||||
{"WhiteIsZero": 0, "BlackIsZero": 1, "RGB": 2, "RBG Palette": 3,
|
||||
"Transparency Mask": 4, "CMYK": 5, "YCbCr": 6, "CieLAB": 8,
|
||||
"CFA": 32803, # TIFF/EP, Adobe DNG
|
||||
"LinearRaw": 32892}), # Adobe DNG
|
||||
263: ("Thresholding", 3, 1),
|
||||
264: ("CellWidth", 3, 1),
|
||||
265: ("CellHeight", 3, 1),
|
||||
266: ("FillOrder", 3, 1),
|
||||
269: ("DocumentName", 2, 1),
|
||||
|
||||
262: "PhotometricInterpretation",
|
||||
(262, 0): "WhiteIsZero",
|
||||
(262, 1): "BlackIsZero",
|
||||
(262, 2): "RGB",
|
||||
(262, 3): "RGB Palette",
|
||||
(262, 4): "Transparency Mask",
|
||||
(262, 5): "CMYK",
|
||||
(262, 6): "YCbCr",
|
||||
(262, 8): "CieLAB",
|
||||
(262, 32803): "CFA", # TIFF/EP, Adobe DNG
|
||||
(262, 32892): "LinearRaw", # Adobe DNG
|
||||
270: ("ImageDescription", 2, 1),
|
||||
271: ("Make", 2, 1),
|
||||
272: ("Model", 2, 1),
|
||||
273: ("StripOffsets", 4, 0),
|
||||
274: ("Orientation", 3, 1),
|
||||
277: ("SamplesPerPixel", 3, 1),
|
||||
278: ("RowsPerStrip", 4, 1),
|
||||
279: ("StripByteCounts", 4, 0),
|
||||
|
||||
263: "Thresholding",
|
||||
264: "CellWidth",
|
||||
265: "CellHeight",
|
||||
266: "FillOrder",
|
||||
269: "DocumentName",
|
||||
280: ("MinSampleValue", 4, 0),
|
||||
281: ("MaxSampleValue", 3, 0),
|
||||
282: ("XResolution", 5, 1),
|
||||
283: ("YResolution", 5, 1),
|
||||
284: ("PlanarConfiguration", 3, 1, {"Contigous": 1, "Separate": 2}),
|
||||
285: ("PageName", 2, 1),
|
||||
286: ("XPosition", 5, 1),
|
||||
287: ("YPosition", 5, 1),
|
||||
288: ("FreeOffsets", 4, 1),
|
||||
289: ("FreeByteCounts", 4, 1),
|
||||
|
||||
270: "ImageDescription",
|
||||
271: "Make",
|
||||
272: "Model",
|
||||
273: "StripOffsets",
|
||||
274: "Orientation",
|
||||
277: "SamplesPerPixel",
|
||||
278: "RowsPerStrip",
|
||||
279: "StripByteCounts",
|
||||
290: ("GrayResponseUnit", 3, 1),
|
||||
291: ("GrayResponseCurve", 3, 0),
|
||||
292: ("T4Options", 4, 1),
|
||||
293: ("T6Options", 4, 1),
|
||||
296: ("ResolutionUnit", 3, 1, {"inch": 1, "cm": 2}),
|
||||
297: ("PageNumber", 3, 2),
|
||||
|
||||
280: "MinSampleValue",
|
||||
281: "MaxSampleValue",
|
||||
282: "XResolution",
|
||||
283: "YResolution",
|
||||
284: "PlanarConfiguration",
|
||||
(284, 1): "Contigous",
|
||||
(284, 2): "Separate",
|
||||
301: ("TransferFunction", 3, 0),
|
||||
305: ("Software", 2, 1),
|
||||
306: ("DateTime", 2, 1),
|
||||
|
||||
285: "PageName",
|
||||
286: "XPosition",
|
||||
287: "YPosition",
|
||||
288: "FreeOffsets",
|
||||
289: "FreeByteCounts",
|
||||
315: ("Artist", 2, 1),
|
||||
316: ("HostComputer", 2, 1),
|
||||
317: ("Predictor", 3, 1),
|
||||
318: ("WhitePoint", 5, 2),
|
||||
319: ("PrimaryChromaticies", 3, 6),
|
||||
|
||||
290: "GrayResponseUnit",
|
||||
291: "GrayResponseCurve",
|
||||
292: "T4Options",
|
||||
293: "T6Options",
|
||||
296: "ResolutionUnit",
|
||||
297: "PageNumber",
|
||||
320: ("ColorMap", 3, 0),
|
||||
321: ("HalftoneHints", 3, 2),
|
||||
322: ("TileWidth", 4, 1),
|
||||
323: ("TileLength", 4, 1),
|
||||
324: ("TileOffsets", 4, 0),
|
||||
325: ("TileByteCounts", 4, 0),
|
||||
|
||||
301: "TransferFunction",
|
||||
305: "Software",
|
||||
306: "DateTime",
|
||||
332: ("InkSet", 3, 1),
|
||||
333: ("InkNames", 2, 1),
|
||||
334: ("NumberOfInks", 3, 1),
|
||||
336: ("DotRange", 3, 0),
|
||||
337: ("TargetPrinter", 2, 1),
|
||||
338: ("ExtraSamples", 1, 0),
|
||||
339: ("SampleFormat", 3, 0),
|
||||
|
||||
315: "Artist",
|
||||
316: "HostComputer",
|
||||
317: "Predictor",
|
||||
318: "WhitePoint",
|
||||
319: "PrimaryChromaticies",
|
||||
|
||||
320: "ColorMap",
|
||||
321: "HalftoneHints",
|
||||
322: "TileWidth",
|
||||
323: "TileLength",
|
||||
324: "TileOffsets",
|
||||
325: "TileByteCounts",
|
||||
|
||||
332: "InkSet",
|
||||
333: "InkNames",
|
||||
334: "NumberOfInks",
|
||||
336: "DotRange",
|
||||
337: "TargetPrinter",
|
||||
338: "ExtraSamples",
|
||||
339: "SampleFormat",
|
||||
|
||||
340: "SMinSampleValue",
|
||||
341: "SMaxSampleValue",
|
||||
342: "TransferRange",
|
||||
|
||||
347: "JPEGTables",
|
||||
340: ("SMinSampleValue", 12, 0),
|
||||
341: ("SMaxSampleValue", 12, 0),
|
||||
342: ("TransferRange", 3, 6),
|
||||
|
||||
# obsolete JPEG tags
|
||||
512: "JPEGProc",
|
||||
513: "JPEGInterchangeFormat",
|
||||
514: "JPEGInterchangeFormatLength",
|
||||
515: "JPEGRestartInterval",
|
||||
517: "JPEGLosslessPredictors",
|
||||
518: "JPEGPointTransforms",
|
||||
519: "JPEGQTables",
|
||||
520: "JPEGDCTables",
|
||||
521: "JPEGACTables",
|
||||
512: ("JPEGProc", 3, 1),
|
||||
513: ("JPEGInterchangeFormat", 4, 1),
|
||||
514: ("JPEGInterchangeFormatLength", 4, 1),
|
||||
515: ("JPEGRestartInterval", 3, 1),
|
||||
517: ("JPEGLosslessPredictors", 3, 0),
|
||||
518: ("JPEGPointTransforms", 3, 0),
|
||||
519: ("JPEGQTables", 4, 0),
|
||||
520: ("JPEGDCTables", 4, 0),
|
||||
521: ("JPEGACTables", 4, 0),
|
||||
|
||||
529: "YCbCrCoefficients",
|
||||
530: "YCbCrSubSampling",
|
||||
531: "YCbCrPositioning",
|
||||
532: "ReferenceBlackWhite",
|
||||
529: ("YCbCrCoefficients", 5, 3),
|
||||
530: ("YCbCrSubSampling", 3, 2),
|
||||
531: ("YCbCrPositioning", 3, 1),
|
||||
532: ("ReferenceBlackWhite", 4, 0),
|
||||
|
||||
# XMP
|
||||
700: "XMP",
|
||||
33432: ("Copyright", 2, 1),
|
||||
|
||||
33432: "Copyright",
|
||||
|
||||
# various extensions (should check specs for "official" names)
|
||||
33723: "IptcNaaInfo",
|
||||
34377: "PhotoshopInfo",
|
||||
|
||||
# Exif IFD
|
||||
34665: "ExifIFD",
|
||||
|
||||
# ICC Profile
|
||||
34675: "ICCProfile",
|
||||
|
||||
# Additional Exif Info
|
||||
33434: "ExposureTime",
|
||||
33437: "FNumber",
|
||||
34850: "ExposureProgram",
|
||||
34852: "SpectralSensitivity",
|
||||
34853: "GPSInfoIFD",
|
||||
34855: "ISOSpeedRatings",
|
||||
34856: "OECF",
|
||||
34864: "SensitivityType",
|
||||
34865: "StandardOutputSensitivity",
|
||||
34866: "RecommendedExposureIndex",
|
||||
34867: "ISOSpeed",
|
||||
34868: "ISOSpeedLatitudeyyy",
|
||||
34869: "ISOSpeedLatitudezzz",
|
||||
36864: "ExifVersion",
|
||||
36867: "DateTimeOriginal",
|
||||
36868: "DateTImeDigitized",
|
||||
37121: "ComponentsConfiguration",
|
||||
37122: "CompressedBitsPerPixel",
|
||||
37377: "ShutterSpeedValue",
|
||||
37378: "ApertureValue",
|
||||
37379: "BrightnessValue",
|
||||
37380: "ExposureBiasValue",
|
||||
37381: "MaxApertureValue",
|
||||
37382: "SubjectDistance",
|
||||
37383: "MeteringMode",
|
||||
37384: "LightSource",
|
||||
37385: "Flash",
|
||||
37386: "FocalLength",
|
||||
37396: "SubjectArea",
|
||||
37500: "MakerNote",
|
||||
37510: "UserComment",
|
||||
37520: "SubSec",
|
||||
37521: "SubSecTimeOriginal",
|
||||
37522: "SubsecTimeDigitized",
|
||||
40960: "FlashPixVersion",
|
||||
40961: "ColorSpace",
|
||||
40962: "PixelXDimension",
|
||||
40963: "PixelYDimension",
|
||||
40964: "RelatedSoundFile",
|
||||
40965: "InteroperabilityIFD",
|
||||
41483: "FlashEnergy",
|
||||
41484: "SpatialFrequencyResponse",
|
||||
41486: "FocalPlaneXResolution",
|
||||
41487: "FocalPlaneYResolution",
|
||||
41488: "FocalPlaneResolutionUnit",
|
||||
41492: "SubjectLocation",
|
||||
41493: "ExposureIndex",
|
||||
41495: "SensingMethod",
|
||||
41728: "FileSource",
|
||||
41729: "SceneType",
|
||||
41730: "CFAPattern",
|
||||
41985: "CustomRendered",
|
||||
41986: "ExposureMode",
|
||||
41987: "WhiteBalance",
|
||||
41988: "DigitalZoomRatio",
|
||||
41989: "FocalLengthIn35mmFilm",
|
||||
41990: "SceneCaptureType",
|
||||
41991: "GainControl",
|
||||
41992: "Contrast",
|
||||
41993: "Saturation",
|
||||
41994: "Sharpness",
|
||||
41995: "DeviceSettingDescription",
|
||||
41996: "SubjectDistanceRange",
|
||||
42016: "ImageUniqueID",
|
||||
42032: "CameraOwnerName",
|
||||
42033: "BodySerialNumber",
|
||||
42034: "LensSpecification",
|
||||
42035: "LensMake",
|
||||
42036: "LensModel",
|
||||
42037: "LensSerialNumber",
|
||||
42240: "Gamma",
|
||||
|
||||
# MP Info
|
||||
45056: "MPFVersion",
|
||||
45057: "NumberOfImages",
|
||||
45058: "MPEntry",
|
||||
45059: "ImageUIDList",
|
||||
45060: "TotalFrames",
|
||||
45313: "MPIndividualNum",
|
||||
45569: "PanOrientation",
|
||||
45570: "PanOverlap_H",
|
||||
45571: "PanOverlap_V",
|
||||
45572: "BaseViewpointNum",
|
||||
45573: "ConvergenceAngle",
|
||||
45574: "BaselineLength",
|
||||
45575: "VerticalDivergence",
|
||||
45576: "AxisDistance_X",
|
||||
45577: "AxisDistance_Y",
|
||||
45578: "AxisDistance_Z",
|
||||
45579: "YawAngle",
|
||||
45580: "PitchAngle",
|
||||
45581: "RollAngle",
|
||||
|
||||
# Adobe DNG
|
||||
50706: "DNGVersion",
|
||||
50707: "DNGBackwardVersion",
|
||||
50708: "UniqueCameraModel",
|
||||
50709: "LocalizedCameraModel",
|
||||
50710: "CFAPlaneColor",
|
||||
50711: "CFALayout",
|
||||
50712: "LinearizationTable",
|
||||
50713: "BlackLevelRepeatDim",
|
||||
50714: "BlackLevel",
|
||||
50715: "BlackLevelDeltaH",
|
||||
50716: "BlackLevelDeltaV",
|
||||
50717: "WhiteLevel",
|
||||
50718: "DefaultScale",
|
||||
50719: "DefaultCropOrigin",
|
||||
50720: "DefaultCropSize",
|
||||
50778: "CalibrationIlluminant1",
|
||||
50779: "CalibrationIlluminant2",
|
||||
50721: "ColorMatrix1",
|
||||
50722: "ColorMatrix2",
|
||||
50723: "CameraCalibration1",
|
||||
50724: "CameraCalibration2",
|
||||
50725: "ReductionMatrix1",
|
||||
50726: "ReductionMatrix2",
|
||||
50727: "AnalogBalance",
|
||||
50728: "AsShotNeutral",
|
||||
50729: "AsShotWhiteXY",
|
||||
50730: "BaselineExposure",
|
||||
50731: "BaselineNoise",
|
||||
50732: "BaselineSharpness",
|
||||
50733: "BayerGreenSplit",
|
||||
50734: "LinearResponseLimit",
|
||||
50735: "CameraSerialNumber",
|
||||
50736: "LensInfo",
|
||||
50737: "ChromaBlurRadius",
|
||||
50738: "AntiAliasStrength",
|
||||
50740: "DNGPrivateData",
|
||||
50741: "MakerNoteSafety",
|
||||
50780: "BestQualityScale",
|
||||
|
||||
# ImageJ
|
||||
50838: "ImageJMetaDataByteCounts", # private tag registered with Adobe
|
||||
50839: "ImageJMetaData", # private tag registered with Adobe
|
||||
# FIXME add more tags here
|
||||
50741: ("MakerNoteSafety", 3, 1, {0: "Unsafe", 1: "Safe"}),
|
||||
50780: ("BestQualityScale", 5, 1),
|
||||
# private tags registered with Adobe
|
||||
50838: ("ImageJMetaDataByteCounts", 4, 1),
|
||||
50839: ("ImageJMetaData", 7, 1)
|
||||
}
|
||||
|
||||
|
||||
for k, v in TAGS.items():
|
||||
TAGS[k] = TagInfo(k, *v)
|
||||
del k, v
|
||||
|
||||
|
||||
##
|
||||
# Map type numbers to type names.
|
||||
# Map type numbers to type names -- defined in ImageFileDirectory.
|
||||
|
||||
TYPES = {
|
||||
|
||||
1: "byte",
|
||||
2: "ascii",
|
||||
3: "short",
|
||||
4: "long",
|
||||
5: "rational",
|
||||
6: "signed byte",
|
||||
7: "undefined",
|
||||
8: "signed short",
|
||||
9: "signed long",
|
||||
10: "signed rational",
|
||||
11: "float",
|
||||
12: "double",
|
||||
|
||||
}
|
||||
TYPES = {}
|
||||
|
|
|
@ -142,9 +142,8 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
for tag, value in reloaded.items():
|
||||
if tag not in ignored:
|
||||
if tag.endswith('Resolution'):
|
||||
val = original[tag]
|
||||
self.assert_almost_equal(
|
||||
val[0][0]/val[0][1], value[0][0]/value[0][1],
|
||||
original[tag], value,
|
||||
msg="%s didn't roundtrip" % tag)
|
||||
else:
|
||||
self.assertEqual(
|
||||
|
@ -153,9 +152,8 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
for tag, value in original.items():
|
||||
if tag not in ignored:
|
||||
if tag.endswith('Resolution'):
|
||||
val = reloaded[tag]
|
||||
self.assert_almost_equal(
|
||||
val[0][0]/val[0][1], value[0][0]/value[0][1],
|
||||
original[tag], value,
|
||||
msg="%s didn't roundtrip" % tag)
|
||||
else:
|
||||
self.assertEqual(
|
||||
|
|
|
@ -74,11 +74,9 @@ class TestFileTiff(PillowTestCase):
|
|||
from PIL.TiffImagePlugin import X_RESOLUTION, Y_RESOLUTION
|
||||
filename = "Tests/images/pil168.tif"
|
||||
im = Image.open(filename)
|
||||
assert isinstance(im.tag.tags[X_RESOLUTION][0], tuple)
|
||||
assert isinstance(im.tag.tags[Y_RESOLUTION][0], tuple)
|
||||
# Try to read a file where X,Y_RESOLUTION are ints
|
||||
im.tag.tags[X_RESOLUTION] = (72,)
|
||||
im.tag.tags[Y_RESOLUTION] = (72,)
|
||||
im.tag[X_RESOLUTION] = (72,)
|
||||
im.tag[Y_RESOLUTION] = (72,)
|
||||
im._setup()
|
||||
self.assertEqual(im.info['dpi'], (72., 72.))
|
||||
|
||||
|
@ -228,10 +226,9 @@ class TestFileTiff(PillowTestCase):
|
|||
self.assertIsInstance(ret, dict)
|
||||
|
||||
self.assertEqual(
|
||||
ret, {256: (55,), 257: (43,), 258: (8, 8, 8, 8), 259: (1,),
|
||||
262: (2,), 296: (2,), 273: (8,), 338: (1,), 277: (4,),
|
||||
279: (9460,), 282: ((720000, 10000),),
|
||||
283: ((720000, 10000),), 284: (1,)})
|
||||
ret, {256: 55, 257: 43, 258: (8, 8, 8, 8), 259: 1, 262: 2, 296: 2,
|
||||
273: (8,), 338: (1,), 277: 4, 279: (9460,),
|
||||
282: 72.0, 283: 72.0, 284: 1})
|
||||
|
||||
def test__delitem__(self):
|
||||
# Arrange
|
||||
|
@ -255,7 +252,7 @@ class TestFileTiff(PillowTestCase):
|
|||
ret = ifd.load_byte(data)
|
||||
|
||||
# Assert
|
||||
self.assertEqual(ret, b"abc")
|
||||
self.assertEqual(ret, (97, 98, 99))
|
||||
|
||||
def test_load_string(self):
|
||||
# Arrange
|
||||
|
@ -310,38 +307,27 @@ class TestFileTiff(PillowTestCase):
|
|||
# Act / Assert
|
||||
self.assertRaises(EOFError, lambda: im.seek(1))
|
||||
|
||||
def test__cvt_res_int(self):
|
||||
def test__limit_rational_int(self):
|
||||
# Arrange
|
||||
from PIL.TiffImagePlugin import _cvt_res
|
||||
from PIL.TiffImagePlugin import _limit_rational
|
||||
value = 34
|
||||
|
||||
# Act
|
||||
ret = _cvt_res(value)
|
||||
ret = _limit_rational(value, 65536)
|
||||
|
||||
# Assert
|
||||
self.assertEqual(ret, (34, 1))
|
||||
|
||||
def test__cvt_res_float(self):
|
||||
def test__limit_rational_float(self):
|
||||
# Arrange
|
||||
from PIL.TiffImagePlugin import _cvt_res
|
||||
from PIL.TiffImagePlugin import _limit_rational
|
||||
value = 22.3
|
||||
|
||||
# Act
|
||||
ret = _cvt_res(value)
|
||||
ret = _limit_rational(value, 65536)
|
||||
|
||||
# Assert
|
||||
self.assertEqual(ret, (1461452, 65536))
|
||||
|
||||
def test__cvt_res_sequence(self):
|
||||
# Arrange
|
||||
from PIL.TiffImagePlugin import _cvt_res
|
||||
value = [0, 1]
|
||||
|
||||
# Act
|
||||
ret = _cvt_res(value)
|
||||
|
||||
# Assert
|
||||
self.assertEqual(ret, [0, 1])
|
||||
self.assertEqual(ret, (223, 10))
|
||||
|
||||
def test_4bit(self):
|
||||
# Arrange
|
||||
|
@ -388,8 +374,8 @@ class TestFileTiff(PillowTestCase):
|
|||
# Assert
|
||||
from PIL.TiffImagePlugin import X_RESOLUTION, Y_RESOLUTION
|
||||
im = Image.open(filename)
|
||||
self.assertEqual(im.tag.tags[X_RESOLUTION][0][0], 72)
|
||||
self.assertEqual(im.tag.tags[Y_RESOLUTION][0][0], 36)
|
||||
self.assertEqual(im.tag[X_RESOLUTION], 72)
|
||||
self.assertEqual(im.tag[Y_RESOLUTION], 36)
|
||||
|
||||
def test_deprecation_warning_with_spaces(self):
|
||||
# Arrange: use spaces
|
||||
|
@ -405,8 +391,8 @@ class TestFileTiff(PillowTestCase):
|
|||
# Assert
|
||||
from PIL.TiffImagePlugin import X_RESOLUTION, Y_RESOLUTION
|
||||
im = Image.open(filename)
|
||||
self.assertEqual(im.tag.tags[X_RESOLUTION][0][0], 36)
|
||||
self.assertEqual(im.tag.tags[Y_RESOLUTION][0][0], 72)
|
||||
self.assertEqual(im.tag[X_RESOLUTION], 36)
|
||||
self.assertEqual(im.tag[Y_RESOLUTION], 72)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
from __future__ import division
|
||||
|
||||
from helper import unittest, PillowTestCase, hopper
|
||||
|
||||
from PIL import Image, TiffImagePlugin, TiffTags
|
||||
|
||||
tag_ids = dict(zip(TiffTags.TAGS.values(), TiffTags.TAGS.keys()))
|
||||
tag_ids = {info.name: info.value for info in TiffTags.TAGS.values()}
|
||||
|
||||
|
||||
class TestFileTiffMetadata(PillowTestCase):
|
||||
|
@ -19,7 +21,6 @@ class TestFileTiffMetadata(PillowTestCase):
|
|||
textdata = basetextdata + " \xff"
|
||||
floatdata = 12.345
|
||||
doubledata = 67.89
|
||||
|
||||
info = TiffImagePlugin.ImageFileDirectory()
|
||||
|
||||
info[tag_ids['ImageJMetaDataByteCounts']] = len(textdata)
|
||||
|
@ -45,32 +46,25 @@ class TestFileTiffMetadata(PillowTestCase):
|
|||
def test_read_metadata(self):
|
||||
img = Image.open('Tests/images/hopper_g4.tif')
|
||||
|
||||
known = {'YResolution': ((4294967295, 113653537),),
|
||||
'PlanarConfiguration': (1,),
|
||||
known = {'YResolution': 4294967295 / 113653537,
|
||||
'PlanarConfiguration': 1,
|
||||
'BitsPerSample': (1,),
|
||||
'ImageLength': (128,),
|
||||
'Compression': (4,),
|
||||
'FillOrder': (1,),
|
||||
'RowsPerStrip': (128,),
|
||||
'ResolutionUnit': (3,),
|
||||
'PhotometricInterpretation': (0,),
|
||||
'ImageLength': 128,
|
||||
'Compression': 4,
|
||||
'FillOrder': 1,
|
||||
'RowsPerStrip': 128,
|
||||
'ResolutionUnit': 3,
|
||||
'PhotometricInterpretation': 0,
|
||||
'PageNumber': (0, 1),
|
||||
'XResolution': ((4294967295, 113653537),),
|
||||
'ImageWidth': (128,),
|
||||
'Orientation': (1,),
|
||||
'XResolution': 4294967295 / 113653537,
|
||||
'ImageWidth': 128,
|
||||
'Orientation': 1,
|
||||
'StripByteCounts': (1968,),
|
||||
'SamplesPerPixel': (1,),
|
||||
'StripOffsets': (8,),
|
||||
'SamplesPerPixel': 1,
|
||||
'StripOffsets': (8,)
|
||||
}
|
||||
|
||||
# self.assertEqual is equivalent,
|
||||
# but less helpful in telling what's wrong.
|
||||
named = img.tag.named()
|
||||
for tag, value in named.items():
|
||||
self.assertEqual(known[tag], value)
|
||||
|
||||
for tag, value in known.items():
|
||||
self.assertEqual(value, named[tag])
|
||||
self.assertEqual(known, img.tag.named())
|
||||
|
||||
def test_write_metadata(self):
|
||||
""" Test metadata writing through the python code """
|
||||
|
|
33
encode.c
33
encode.c
|
@ -721,7 +721,6 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
|
|||
pos = 0;
|
||||
}
|
||||
|
||||
|
||||
TRACE(("new tiff encoder %s fp: %d, filename: %s \n", compname, fp, filename));
|
||||
|
||||
encoder = PyImaging_EncoderNew(sizeof(TIFFSTATE));
|
||||
|
@ -737,11 +736,9 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// While fails on 64 bit machines, complains that pos is an int instead of a Py_ssize_t
|
||||
// while (PyDict_Next(dir, &pos, &key, &value)) {
|
||||
for (pos=0;pos<d_size;pos++){
|
||||
key = PyList_GetItem(keys,pos);
|
||||
value = PyList_GetItem(values,pos);
|
||||
for (pos = 0; pos < d_size; pos++) {
|
||||
key = PyList_GetItem(keys, pos);
|
||||
value = PyList_GetItem(values, pos);
|
||||
status = 0;
|
||||
TRACE(("Attempting to set key: %d\n", (int)PyInt_AsLong(key)));
|
||||
if (PyInt_Check(value)) {
|
||||
|
@ -749,24 +746,29 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
|
|||
status = ImagingLibTiffSetField(&encoder->state,
|
||||
(ttag_t) PyInt_AsLong(key),
|
||||
PyInt_AsLong(value));
|
||||
} else if(PyBytes_Check(value)) {
|
||||
} else if (PyFloat_Check(value)) {
|
||||
TRACE(("Setting from Float: %d, %f \n", (int)PyInt_AsLong(key),PyFloat_AsDouble(value)));
|
||||
status = ImagingLibTiffSetField(&encoder->state,
|
||||
(ttag_t) PyInt_AsLong(key),
|
||||
(float)PyFloat_AsDouble(value));
|
||||
} else if (PyBytes_Check(value)) {
|
||||
TRACE(("Setting from Bytes: %d, %s \n", (int)PyInt_AsLong(key),PyBytes_AsString(value)));
|
||||
status = ImagingLibTiffSetField(&encoder->state,
|
||||
(ttag_t) PyInt_AsLong(key),
|
||||
PyBytes_AsString(value));
|
||||
} else if(PyList_Check(value)) {
|
||||
} else if (PyTuple_Check(value)) {
|
||||
int len,i;
|
||||
float *floatav;
|
||||
int *intav;
|
||||
TRACE(("Setting from List: %d \n", (int)PyInt_AsLong(key)));
|
||||
len = (int)PyList_Size(value);
|
||||
TRACE(("Setting from Tuple: %d \n", (int)PyInt_AsLong(key)));
|
||||
len = (int)PyTuple_Size(value);
|
||||
if (len) {
|
||||
if (PyInt_Check(PyList_GetItem(value,0))) {
|
||||
if (PyInt_Check(PyTuple_GetItem(value,0))) {
|
||||
TRACE((" %d elements, setting as ints \n", len));
|
||||
intav = malloc(sizeof(int)*len);
|
||||
if (intav) {
|
||||
for (i=0;i<len;i++) {
|
||||
intav[i] = (int)PyInt_AsLong(PyList_GetItem(value,i));
|
||||
intav[i] = (int)PyInt_AsLong(PyTuple_GetItem(value,i));
|
||||
}
|
||||
status = ImagingLibTiffSetField(&encoder->state,
|
||||
(ttag_t) PyInt_AsLong(key),
|
||||
|
@ -778,7 +780,7 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
|
|||
floatav = malloc(sizeof(float)*len);
|
||||
if (floatav) {
|
||||
for (i=0;i<len;i++) {
|
||||
floatav[i] = (float)PyFloat_AsDouble(PyList_GetItem(value,i));
|
||||
floatav[i] = (float)PyFloat_AsDouble(PyTuple_GetItem(value,i));
|
||||
}
|
||||
status = ImagingLibTiffSetField(&encoder->state,
|
||||
(ttag_t) PyInt_AsLong(key),
|
||||
|
@ -787,11 +789,6 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if (PyFloat_Check(value)) {
|
||||
TRACE(("Setting from Float: %d, %f \n", (int)PyInt_AsLong(key),PyFloat_AsDouble(value)));
|
||||
status = ImagingLibTiffSetField(&encoder->state,
|
||||
(ttag_t) PyInt_AsLong(key),
|
||||
(float)PyFloat_AsDouble(value));
|
||||
} else {
|
||||
TRACE(("Unhandled type for key %d : %s \n",
|
||||
(int)PyInt_AsLong(key),
|
||||
|
|
Loading…
Reference in New Issue
Block a user