From 3187024d8ca2d8e51c2789bdef7b6480346ed03e Mon Sep 17 00:00:00 2001 From: hMatoba Date: Sun, 3 Sep 2017 21:29:19 +0900 Subject: [PATCH 01/22] Add _exceptions.py --- piexif.pyproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/piexif.pyproj b/piexif.pyproj index 9141455..4b12880 100644 --- a/piexif.pyproj +++ b/piexif.pyproj @@ -35,7 +35,11 @@ Code + + + Code + Code From 3c6db0eae960fbe3faef1802eea1af65cbb9e3c8 Mon Sep 17 00:00:00 2001 From: hMatoba Date: Sun, 3 Sep 2017 21:29:41 +0900 Subject: [PATCH 02/22] Add tests for field "UserComment". --- piexif/_helper.py | 8 ++++++++ tests/s_test.py | 11 +++++++++++ 2 files changed, 19 insertions(+) create mode 100644 piexif/_helper.py diff --git a/piexif/_helper.py b/piexif/_helper.py new file mode 100644 index 0000000..bd01d29 --- /dev/null +++ b/piexif/_helper.py @@ -0,0 +1,8 @@ + +# return "str" +def dump_user_comment(string): + return None + +# return "bytes" +def load_user_comment(binary): + return None \ No newline at end of file diff --git a/tests/s_test.py b/tests/s_test.py index a76609f..a53e4b1 100644 --- a/tests/s_test.py +++ b/tests/s_test.py @@ -10,6 +10,7 @@ from PIL import Image import piexif from piexif import _common, ImageIFD, ExifIFD, GPSIFD, TAGS, InvalidImageDataError +from piexif import _helper print("piexif version: {0}".format(piexif.VERSION)) @@ -680,6 +681,16 @@ def test_merge_segments(self): o = io.BytesIO(new_data) Image.open(o).close() + def test_dump_user_comment(self): + string = "" + result = _helper.dump_user_comment(string) + self.assertEqual(b"foobar", result) + + def test_load_user_comment(self): + binary = b"" + result = _helper.load_user_comment(binary) + self.assertEqual("foobar", result) + def suite(): suite = unittest.TestSuite() From 08dc1ebe9e77aef12a12b2ec8ca331fc7263c88e Mon Sep 17 00:00:00 2001 From: hMatoba Date: Sun, 3 Sep 2017 22:46:10 +0900 Subject: [PATCH 03/22] Prepare to add types(SignedByte, SignedShort, DoubleFloat) --- piexif/_dump.py | 2 -- piexif/_exif.py | 11 ++++++++++- tests/s_test.py | 18 ++++++++++++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/piexif/_dump.py b/piexif/_dump.py index 5867fdc..f5035c6 100644 --- a/piexif/_dump.py +++ b/piexif/_dump.py @@ -67,8 +67,6 @@ def dump(exif_dict_original): if exif_is: exif_set = _dict_to_bytes(exif_ifd, "Exif", zeroth_length) exif_length = len(exif_set[0]) + interop_is * 12 + len(exif_set[1]) - #exif_bytes = b"".join(exif_set) - #exif_length = len(exif_bytes) else: exif_bytes = b"" exif_length = 0 diff --git a/piexif/_exif.py b/piexif/_exif.py index 1f91a8e..fcc2ef4 100644 --- a/piexif/_exif.py +++ b/piexif/_exif.py @@ -4,10 +4,13 @@ class TYPES: Short = 3 Long = 4 Rational = 5 + SByte = 6 Undefined = 7 + SShort = 8 SLong = 9 SRational = 10 Float = 11 + DFloat = 12 TAGS = { @@ -196,7 +199,10 @@ class TYPES: 51009: {'name': 'OpcodeList2', 'type': TYPES.Undefined}, 51022: {'name': 'OpcodeList3', 'type': TYPES.Undefined}, 60606: {'name': 'ZZZTestSlong1', 'type': TYPES.SLong}, - 60607: {'name': 'ZZZTestSlong2', 'type': TYPES.SLong}}, + 60607: {'name': 'ZZZTestSlong2', 'type': TYPES.SLong}, + 60608: {'name': 'ZZZTestSByte', 'type': TYPES.SByte}, + 60609: {'name': 'ZZZTestSShort', 'type': TYPES.SShort}, + 60610: {'name': 'ZZZTestDFloat', 'type': TYPES.DFloat},}, 'Exif': {33434: {'name': 'ExposureTime', 'type': TYPES.Rational}, 33437: {'name': 'FNumber', 'type': TYPES.Rational}, 34850: {'name': 'ExposureProgram', 'type': TYPES.Short}, @@ -503,6 +509,9 @@ class ImageIFD: NoiseProfile = 51041 ZZZTestSlong1 = 60606 ZZZTestSlong2 = 60607 + ZZZTestSByte = 60608 + ZZZTestSShort = 60609 + ZZZTestDFloat = 60610 class ExifIFD: diff --git a/tests/s_test.py b/tests/s_test.py index a53e4b1..a975586 100644 --- a/tests/s_test.py +++ b/tests/s_test.py @@ -346,6 +346,24 @@ def test_dump_and_load3(self): self.assertEqual(e["Exif"][ExifIFD.ISOSpeed], long_v[x]) self.assertEqual(e["GPS"][GPSIFD.GPSVersionID], byte_v[x]) + def test_dump_and_load_specials(self): + """test dump and load special types(SingedByte, SiginedShort, DoubleFloat)""" + self.assertEqual(1, None) + #exif_dict = {"0th":ZEROTH_IFD} + #exif_bytes = piexif.dump(exif_dict) + #im = Image.new("RGB", (8, 8)) + + #o = io.BytesIO() + #im.save(o, format="jpeg", exif=exif_bytes) + #im.close() + #o.seek(0) + #exif = piexif.load(o.getvalue()) + #zeroth_ifd = exif["0th"] + #self.assertDictEqual(ZEROTH_IFD, zeroth_ifd) + #self.assertDictEqual(EXIF_IFD, exif_ifd) + #self.assertDictEqual(GPS_IFD, gps_ifd) + + def test_roundtrip_files(self): files = glob.glob(os.path.join("tests", "images", "r_*.jpg")) for input_file in files: From 90f21f0a59b92b6b3e1866d43101aa1f933eb970 Mon Sep 17 00:00:00 2001 From: hMatoba Date: Mon, 4 Sep 2017 00:12:56 +0900 Subject: [PATCH 04/22] Edit test for new types. --- tests/s_test.py | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/tests/s_test.py b/tests/s_test.py index a975586..e7f046d 100644 --- a/tests/s_test.py +++ b/tests/s_test.py @@ -348,20 +348,28 @@ def test_dump_and_load3(self): def test_dump_and_load_specials(self): """test dump and load special types(SingedByte, SiginedShort, DoubleFloat)""" - self.assertEqual(1, None) - #exif_dict = {"0th":ZEROTH_IFD} - #exif_bytes = piexif.dump(exif_dict) - #im = Image.new("RGB", (8, 8)) - - #o = io.BytesIO() - #im.save(o, format="jpeg", exif=exif_bytes) - #im.close() - #o.seek(0) - #exif = piexif.load(o.getvalue()) - #zeroth_ifd = exif["0th"] - #self.assertDictEqual(ZEROTH_IFD, zeroth_ifd) - #self.assertDictEqual(EXIF_IFD, exif_ifd) - #self.assertDictEqual(GPS_IFD, gps_ifd) + zeroth_ifd_original = { + ImageIFD.ZZZTestSByte:-128, + ImageIFD.ZZZTestSShort:-32768, + ImageIFD.ZZZTestDFloat:1.0e-100, + } + exif_dict = {"0th":zeroth_ifd_original} + exif_bytes = piexif.dump(exif_dict) + + exif = piexif.load(exif_bytes) + zeroth_ifd = exif["0th"] + self.assertEqual( + zeroth_ifd_original[ImageIFD.ZZZTestSByte], + zeroth_ifd[ImageIFD.ZZZTestSByte] + ) + self.assertEqual( + zeroth_ifd_original[ImageIFD.ZZZTestSShort], + zeroth_ifd[ImageIFD.ZZZTestSShort] + ) + self.assertEqual( + zeroth_ifd_original[ImageIFD.ZZZTestDFloat], + zeroth_ifd[ImageIFD.ZZZTestDFloat] + ) def test_roundtrip_files(self): From d9a4fcb78bc6e50cabb6129092c129051b635f25 Mon Sep 17 00:00:00 2001 From: hMatoba Date: Tue, 5 Sep 2017 00:13:58 +0900 Subject: [PATCH 05/22] Edit test --- piexif/_exif.py | 2 +- tests/s_test.py | 59 +++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/piexif/_exif.py b/piexif/_exif.py index fcc2ef4..abdf0bc 100644 --- a/piexif/_exif.py +++ b/piexif/_exif.py @@ -235,7 +235,7 @@ class TYPES: 37386: {'name': 'FocalLength', 'type': TYPES.Rational}, 37396: {'name': 'SubjectArea', 'type': TYPES.Short}, 37500: {'name': 'MakerNote', 'type': TYPES.Undefined}, - 37510: {'name': 'UserComment', 'type': TYPES.Ascii}, + 37510: {'name': 'UserComment', 'type': TYPES.Undefined}, 37520: {'name': 'SubSecTime', 'type': TYPES.Ascii}, 37521: {'name': 'SubSecTimeOriginal', 'type': TYPES.Ascii}, 37522: {'name': 'SubSecTimeDigitized', 'type': TYPES.Ascii}, diff --git a/tests/s_test.py b/tests/s_test.py index e7f046d..4c7a296 100644 --- a/tests/s_test.py +++ b/tests/s_test.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- + import copy import glob import io @@ -708,14 +710,63 @@ def test_merge_segments(self): Image.open(o).close() def test_dump_user_comment(self): - string = "" + # ascii + header = b"\x41\x53\x43\x49\x49\x00\x00\x00" + string = u"abcd" + binary = header + string.encode("ascii") + result = _helper.dump_user_comment(string) + self.assertEqual(binary, result) + + # jis + header = b"\x4a\x49\x53\x00\x00\x00\x00\x00" + string = u"abcd" + binary = header + string.encode("jis") + result = _helper.dump_user_comment(string) + self.assertEqual(binary, result) + + # unicode + header = b"\x55\x4e\x49\x43\x4f\x44\x45\x00" + string = u"abcd" + binary = header + string.encode("unicode_escape") + result = _helper.dump_user_comment(string) + self.assertEqual(binary, result) + + # undefined + header = b"\x00\x00\x00\x00\x00\x00\x00\x00" + string = u"abcd" + binary = header + string.encode("latin") result = _helper.dump_user_comment(string) - self.assertEqual(b"foobar", result) + self.assertEqual(binary, result) + def test_load_user_comment(self): - binary = b"" + # ascii + header = b"\x41\x53\x43\x49\x49\x00\x00\x00" + string = u"abcd" + binary = header + string.encode("ascii") + result = _helper.load_user_comment(binary) + self.assertEqual(string, result) + + # jis + header = b"\x4a\x49\x53\x00\x00\x00\x00\x00" + string = u"abcd" + binary = header + string.encode("jis") + result = _helper.load_user_comment(binary) + self.assertEqual(string, result) + + # unicode + header = b"\x55\x4e\x49\x43\x4f\x44\x45\x00" + string = u"abcd" + binary = header + string.encode("unicode_escape") + result = _helper.load_user_comment(binary) + self.assertEqual(string, result) + + # undefined + header = b"\x00\x00\x00\x00\x00\x00\x00\x00" + string = u"abcd" + binary = header + string.encode("latin") result = _helper.load_user_comment(binary) - self.assertEqual("foobar", result) + self.assertEqual(string, result) def suite(): From 5a1299067fac5596cb6155f6c0a72b93afd60ea1 Mon Sep 17 00:00:00 2001 From: hMatoba Date: Tue, 5 Sep 2017 23:59:21 +0900 Subject: [PATCH 06/22] m --- tests/s_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/s_test.py b/tests/s_test.py index 4c7a296..cd601eb 100644 --- a/tests/s_test.py +++ b/tests/s_test.py @@ -727,7 +727,7 @@ def test_dump_user_comment(self): # unicode header = b"\x55\x4e\x49\x43\x4f\x44\x45\x00" string = u"abcd" - binary = header + string.encode("unicode_escape") + binary = header + string.encode("utf16") result = _helper.dump_user_comment(string) self.assertEqual(binary, result) @@ -757,7 +757,7 @@ def test_load_user_comment(self): # unicode header = b"\x55\x4e\x49\x43\x4f\x44\x45\x00" string = u"abcd" - binary = header + string.encode("unicode_escape") + binary = header + string.encode("utf16") result = _helper.load_user_comment(binary) self.assertEqual(string, result) From 9d89517f61a7fa45452f5d482686f11154eb2648 Mon Sep 17 00:00:00 2001 From: hMatoba Date: Wed, 6 Sep 2017 10:52:22 +0900 Subject: [PATCH 07/22] Update s_test.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UserCommentのエンコーディング"Unicode"がなにを指すのか(UTF16? UTF16BE? UTF16LE? UCS2?)わからないので保留。 --- tests/s_test.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/s_test.py b/tests/s_test.py index cd601eb..5c56c70 100644 --- a/tests/s_test.py +++ b/tests/s_test.py @@ -725,11 +725,11 @@ def test_dump_user_comment(self): self.assertEqual(binary, result) # unicode - header = b"\x55\x4e\x49\x43\x4f\x44\x45\x00" - string = u"abcd" - binary = header + string.encode("utf16") - result = _helper.dump_user_comment(string) - self.assertEqual(binary, result) + #header = b"\x55\x4e\x49\x43\x4f\x44\x45\x00" + #string = u"abcd" + #binary = header + string.encode("utf-16-be") + #result = _helper.dump_user_comment(string) + #self.assertEqual(binary, result) # undefined header = b"\x00\x00\x00\x00\x00\x00\x00\x00" @@ -755,11 +755,11 @@ def test_load_user_comment(self): self.assertEqual(string, result) # unicode - header = b"\x55\x4e\x49\x43\x4f\x44\x45\x00" - string = u"abcd" - binary = header + string.encode("utf16") - result = _helper.load_user_comment(binary) - self.assertEqual(string, result) + #header = b"\x55\x4e\x49\x43\x4f\x44\x45\x00" + #string = u"abcd" + #binary = header + string.encode("utf-16-be") + #result = _helper.load_user_comment(binary) + #self.assertEqual(string, result) # undefined header = b"\x00\x00\x00\x00\x00\x00\x00\x00" From 29fd4f7176a6e5d7ca1e39b2f10dd75cff60c4ee Mon Sep 17 00:00:00 2001 From: hMatoba Date: Fri, 8 Sep 2017 13:39:15 +0900 Subject: [PATCH 08/22] typo --- piexif/__init__.py | 2 +- piexif/_common.py | 2 +- piexif/{_exeptions.py => _exceptions.py} | 0 piexif/_insert.py | 2 +- piexif/_load.py | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) rename piexif/{_exeptions.py => _exceptions.py} (100%) diff --git a/piexif/__init__.py b/piexif/__init__.py index 46133d2..aa9d11a 100644 --- a/piexif/__init__.py +++ b/piexif/__init__.py @@ -4,7 +4,7 @@ from ._transplant import transplant from ._insert import insert from ._exif import * -from ._exeptions import * +from ._exceptions import * VERSION = '1.0.12' diff --git a/piexif/_common.py b/piexif/_common.py index f8ca2fd..28dc9f9 100644 --- a/piexif/_common.py +++ b/piexif/_common.py @@ -1,6 +1,6 @@ import struct -from ._exeptions import InvalidImageDataError +from ._exceptions import InvalidImageDataError def split_into_segments(data): diff --git a/piexif/_exeptions.py b/piexif/_exceptions.py similarity index 100% rename from piexif/_exeptions.py rename to piexif/_exceptions.py diff --git a/piexif/_insert.py b/piexif/_insert.py index 6df0eac..6e390c7 100644 --- a/piexif/_insert.py +++ b/piexif/_insert.py @@ -2,7 +2,7 @@ import struct from ._common import * -from ._exeptions import InvalidImageDataError +from ._exceptions import InvalidImageDataError def insert(exif, image, new_file=None): diff --git a/piexif/_load.py b/piexif/_load.py index 784faab..1c8e98f 100644 --- a/piexif/_load.py +++ b/piexif/_load.py @@ -1,7 +1,7 @@ import struct from ._common import * -from ._exeptions import InvalidImageDataError +from ._exceptions import InvalidImageDataError from ._exif import * From 45f3980cc619ae6680e4904d9b965c0f4fb2dea5 Mon Sep 17 00:00:00 2001 From: hMatoba Date: Fri, 8 Sep 2017 13:40:08 +0900 Subject: [PATCH 09/22] Changes path to helper functions --- piexif.pyproj | 4 ++-- piexif/{_helper.py => helper.py} | 0 tests/s_test.py | 38 +++++++++++++++----------------- 3 files changed, 20 insertions(+), 22 deletions(-) rename piexif/{_helper.py => helper.py} (100%) diff --git a/piexif.pyproj b/piexif.pyproj index 4b12880..20c6cde 100644 --- a/piexif.pyproj +++ b/piexif.pyproj @@ -35,9 +35,9 @@ Code - + - + Code diff --git a/piexif/_helper.py b/piexif/helper.py similarity index 100% rename from piexif/_helper.py rename to piexif/helper.py diff --git a/tests/s_test.py b/tests/s_test.py index 5c56c70..a974132 100644 --- a/tests/s_test.py +++ b/tests/s_test.py @@ -12,7 +12,7 @@ from PIL import Image import piexif from piexif import _common, ImageIFD, ExifIFD, GPSIFD, TAGS, InvalidImageDataError -from piexif import _helper +from piexif import helper print("piexif version: {0}".format(piexif.VERSION)) @@ -714,29 +714,28 @@ def test_dump_user_comment(self): header = b"\x41\x53\x43\x49\x49\x00\x00\x00" string = u"abcd" binary = header + string.encode("ascii") - result = _helper.dump_user_comment(string) + result = helper.dump_user_comment(string, "ascii") self.assertEqual(binary, result) # jis header = b"\x4a\x49\x53\x00\x00\x00\x00\x00" string = u"abcd" binary = header + string.encode("jis") - result = _helper.dump_user_comment(string) + result = helper.dump_user_comment(string, "jis") self.assertEqual(binary, result) # unicode - #header = b"\x55\x4e\x49\x43\x4f\x44\x45\x00" - #string = u"abcd" - #binary = header + string.encode("utf-16-be") - #result = _helper.dump_user_comment(string) - #self.assertEqual(binary, result) + header = b"\x55\x4e\x49\x43\x4f\x44\x45\x00" + string = u"abcd" + binary = header + string.encode("utf-16-be") + result = helper.dump_user_comment(string, "unicode") + self.assertEqual(binary, result) # undefined header = b"\x00\x00\x00\x00\x00\x00\x00\x00" string = u"abcd" binary = header + string.encode("latin") - result = _helper.dump_user_comment(string) - self.assertEqual(binary, result) + self.assertRaises(ValueError, helper.dump_user_comment(string, "undefined")) def test_load_user_comment(self): @@ -744,29 +743,28 @@ def test_load_user_comment(self): header = b"\x41\x53\x43\x49\x49\x00\x00\x00" string = u"abcd" binary = header + string.encode("ascii") - result = _helper.load_user_comment(binary) + result = helper.load_user_comment(binary) self.assertEqual(string, result) # jis header = b"\x4a\x49\x53\x00\x00\x00\x00\x00" string = u"abcd" binary = header + string.encode("jis") - result = _helper.load_user_comment(binary) + result = helper.load_user_comment(binary) self.assertEqual(string, result) # unicode - #header = b"\x55\x4e\x49\x43\x4f\x44\x45\x00" - #string = u"abcd" - #binary = header + string.encode("utf-16-be") - #result = _helper.load_user_comment(binary) - #self.assertEqual(string, result) + header = b"\x55\x4e\x49\x43\x4f\x44\x45\x00" + string = u"abcd" + binary = header + string.encode("utf-16-be") + result = helper.load_user_comment(binary) + self.assertEqual(string, result) # undefined header = b"\x00\x00\x00\x00\x00\x00\x00\x00" string = u"abcd" - binary = header + string.encode("latin") - result = _helper.load_user_comment(binary) - self.assertEqual(string, result) + binary = header + string.encode("ascii") + self.assertRaises(ValueError, load_user_comment(binary)) def suite(): From f90909e3a32eb1817394c12ab4bf4f30565bc384 Mon Sep 17 00:00:00 2001 From: hMatoba Date: Fri, 8 Sep 2017 16:45:08 +0900 Subject: [PATCH 10/22] Prepare to add some types to read and write. --- piexif/_dump.py | 12 ++++++++++++ piexif/_load.py | 28 ++++++++++++++++++++-------- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/piexif/_dump.py b/piexif/_dump.py index f5035c6..95ea039 100644 --- a/piexif/_dump.py +++ b/piexif/_dump.py @@ -263,6 +263,18 @@ def _value_to_bytes(raw_value, value_type, offset): value_str = raw_value + b"\x00" * (4 - length) except TypeError: raise ValueError("Got invalid type to convert.") + elif value_type == TYPES.SByte: # Signed Byte + # implement here + pass + elif value_type == TYPES.SShort: # Signed Short + # implement here + pass + elif value_type == TYPES.Float: + # implement here + pass + elif value_type == TYPES.DFloat: # Double + # implement here + pass length_str = struct.pack(">I", length) diff --git a/piexif/_load.py b/piexif/_load.py index 1c8e98f..fea50a7 100644 --- a/piexif/_load.py +++ b/piexif/_load.py @@ -133,20 +133,20 @@ def convert_value(self, val): length = val[1] value = val[2] - if t == 1: # BYTE + if t == TYPES.Byte: # BYTE if length > 4: pointer = struct.unpack(self.endian_mark + "L", value)[0] data = struct.unpack("B" * length, self.tiftag[pointer: pointer + length]) else: data = struct.unpack("B" * length, value[0:length]) - elif t == 2: # ASCII + elif t == TYPES.Ascii: # ASCII if length > 4: pointer = struct.unpack(self.endian_mark + "L", value)[0] data = self.tiftag[pointer: pointer+length - 1] else: data = value[0: length - 1] - elif t == 3: # SHORT + elif t == TYPES.Short: # SHORT if length > 2: pointer = struct.unpack(self.endian_mark + "L", value)[0] data = struct.unpack(self.endian_mark + "H" * length, @@ -154,7 +154,7 @@ def convert_value(self, val): else: data = struct.unpack(self.endian_mark + "H" * length, value[0:length * 2]) - elif t == 4: # LONG + elif t == TYPES.Long: # LONG if length > 1: pointer = struct.unpack(self.endian_mark + "L", value)[0] data = struct.unpack(self.endian_mark + "L" * length, @@ -162,7 +162,7 @@ def convert_value(self, val): else: data = struct.unpack(self.endian_mark + "L" * length, value) - elif t == 5: # RATIONAL + elif t == TYPES.Rational: # RATIONAL pointer = struct.unpack(self.endian_mark + "L", value)[0] if length > 1: data = tuple( @@ -180,13 +180,19 @@ def convert_value(self, val): struct.unpack(self.endian_mark + "L", self.tiftag[pointer + 4: pointer + 8] )[0]) - elif t == 7: # UNDEFINED BYTES + elif t == TYPES.SByte: # SIGNED BYTES + pass + # implement here + elif t == TYPES.Undefined: # UNDEFINED BYTES if length > 4: pointer = struct.unpack(self.endian_mark + "L", value)[0] data = self.tiftag[pointer: pointer+length] else: data = value[0:length] - elif t == 9: # SLONG + elif t == TYPES.Short: # SIGNED SHORT + pass + # implement here + elif t == TYPES.SLong: # SLONG if length > 1: pointer = struct.unpack(self.endian_mark + "L", value)[0] data = struct.unpack(self.endian_mark + "l" * length, @@ -194,7 +200,7 @@ def convert_value(self, val): else: data = struct.unpack(self.endian_mark + "l" * length, value) - elif t == 10: # SRATIONAL + elif t == TYPES.SRational: # SRATIONAL pointer = struct.unpack(self.endian_mark + "L", value)[0] if length > 1: data = tuple( @@ -210,6 +216,12 @@ def convert_value(self, val): struct.unpack(self.endian_mark + "l", self.tiftag[pointer + 4: pointer + 8] )[0]) + elif t == TYPES.Float: # FLOAT + pass + # implement here + elif t == TYPES.DFloat: # DOUBLE + pass + # implement here else: raise ValueError("Exif might be wrong. Got incorrect value " + "type to decode.\n" + From 0ff9d7ccd6be6ef35d7b33c8701a8409f464501f Mon Sep 17 00:00:00 2001 From: hMatoba Date: Sun, 10 Sep 2017 11:12:22 +0900 Subject: [PATCH 11/22] Add support for some types. Double, Float, Signed Byte, and Signed Short. --- piexif/_dump.py | 45 ++++++++++++++++++++++++++++++++++----------- piexif/_load.py | 33 ++++++++++++++++++++++++--------- tests/s_test.py | 25 +++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 20 deletions(-) diff --git a/piexif/_dump.py b/piexif/_dump.py index 95ea039..4617a69 100644 --- a/piexif/_dump.py +++ b/piexif/_dump.py @@ -161,18 +161,27 @@ def _get_thumbnail(jpeg): def _pack_byte(*args): return struct.pack("B" * len(args), *args) +def _pack_signed_byte(*args): + return struct.pack("b" * len(args), *args) def _pack_short(*args): return struct.pack(">" + "H" * len(args), *args) +def _pack_signed_short(*args): + return struct.pack(">" + "h" * len(args), *args) def _pack_long(*args): return struct.pack(">" + "L" * len(args), *args) - def _pack_slong(*args): return struct.pack(">" + "l" * len(args), *args) +def _pack_float(*args): + return struct.pack(">" + "f" * len(args), *args) + +def _pack_double(*args): + return struct.pack(">" + "d" * len(args), *args) + def _value_to_bytes(raw_value, value_type, offset): four_bytes_over = b"" @@ -264,18 +273,32 @@ def _value_to_bytes(raw_value, value_type, offset): except TypeError: raise ValueError("Got invalid type to convert.") elif value_type == TYPES.SByte: # Signed Byte - # implement here - pass + length = len(raw_value) + if length <= 4: + value_str = (_pack_signed_byte(*raw_value) + + b"\x00" * (4 - length)) + else: + value_str = struct.pack(">I", offset) + four_bytes_over = _pack_signed_byte(*raw_value) elif value_type == TYPES.SShort: # Signed Short - # implement here - pass + length = len(raw_value) + if length <= 2: + value_str = (_pack_signed_short(*raw_value) + + b"\x00\x00" * (2 - length)) + else: + value_str = struct.pack(">I", offset) + four_bytes_over = _pack_signed_short(*raw_value) elif value_type == TYPES.Float: - # implement here - pass + length = len(raw_value) + if length <= 1: + value_str = _pack_float(*raw_value) + else: + value_str = struct.pack(">I", offset) + four_bytes_over = _pack_float(*raw_value) elif value_type == TYPES.DFloat: # Double - # implement here - pass - + length = len(raw_value) + value_str = struct.pack(">I", offset) + four_bytes_over = _pack_double(*raw_value) length_str = struct.pack(">I", length) return length_str, value_str, four_bytes_over @@ -304,7 +327,7 @@ def _dict_to_bytes(ifd_dict, ifd, ifd_offset): type_str = struct.pack(">H", value_type) four_bytes_over = b"" - if isinstance(raw_value, numbers.Integral): + if isinstance(raw_value, numbers.Integral) or isinstance(raw_value, float): raw_value = (raw_value,) offset = TIFF_HEADER_LENGTH + entries_length + ifd_offset + len(values) diff --git a/piexif/_load.py b/piexif/_load.py index fea50a7..7d3b088 100644 --- a/piexif/_load.py +++ b/piexif/_load.py @@ -181,17 +181,26 @@ def convert_value(self, val): self.tiftag[pointer + 4: pointer + 8] )[0]) elif t == TYPES.SByte: # SIGNED BYTES - pass - # implement here + if length > 4: + pointer = struct.unpack(self.endian_mark + "L", value)[0] + data = struct.unpack("b" * length, + self.tiftag[pointer: pointer + length]) + else: + data = struct.unpack("b" * length, value[0:length]) elif t == TYPES.Undefined: # UNDEFINED BYTES if length > 4: pointer = struct.unpack(self.endian_mark + "L", value)[0] data = self.tiftag[pointer: pointer+length] else: data = value[0:length] - elif t == TYPES.Short: # SIGNED SHORT - pass - # implement here + elif t == TYPES.SShort: # SIGNED SHORT + if length > 2: + pointer = struct.unpack(self.endian_mark + "L", value)[0] + data = struct.unpack(self.endian_mark + "h" * length, + self.tiftag[pointer: pointer+length*2]) + else: + data = struct.unpack(self.endian_mark + "h" * length, + value[0:length * 2]) elif t == TYPES.SLong: # SLONG if length > 1: pointer = struct.unpack(self.endian_mark + "L", value)[0] @@ -217,11 +226,17 @@ def convert_value(self, val): self.tiftag[pointer + 4: pointer + 8] )[0]) elif t == TYPES.Float: # FLOAT - pass - # implement here + if length > 1: + pointer = struct.unpack(self.endian_mark + "L", value)[0] + data = struct.unpack(self.endian_mark + "f" * length, + self.tiftag[pointer: pointer+length*4]) + else: + data = struct.unpack(self.endian_mark + "f" * length, + value) elif t == TYPES.DFloat: # DOUBLE - pass - # implement here + pointer = struct.unpack(self.endian_mark + "L", value)[0] + data = struct.unpack(self.endian_mark + "d" * length, + self.tiftag[pointer: pointer+length*8]) else: raise ValueError("Exif might be wrong. Got incorrect value " + "type to decode.\n" + diff --git a/tests/s_test.py b/tests/s_test.py index a974132..ea57984 100644 --- a/tests/s_test.py +++ b/tests/s_test.py @@ -373,6 +373,31 @@ def test_dump_and_load_specials(self): zeroth_ifd[ImageIFD.ZZZTestDFloat] ) + def test_dump_and_load_specials2(self): + """test dump and load special types(SingedByte, SiginedShort, DoubleFloat)""" + zeroth_ifd_original = { + ImageIFD.ZZZTestSByte:(-128, -128), + ImageIFD.ZZZTestSShort:(-32768, -32768), + ImageIFD.ZZZTestDFloat:(1.0e-100, 1.0e-100), + } + exif_dict = {"0th":zeroth_ifd_original} + exif_bytes = piexif.dump(exif_dict) + + exif = piexif.load(exif_bytes) + zeroth_ifd = exif["0th"] + self.assertEqual( + zeroth_ifd_original[ImageIFD.ZZZTestSByte], + zeroth_ifd[ImageIFD.ZZZTestSByte] + ) + self.assertEqual( + zeroth_ifd_original[ImageIFD.ZZZTestSShort], + zeroth_ifd[ImageIFD.ZZZTestSShort] + ) + self.assertEqual( + zeroth_ifd_original[ImageIFD.ZZZTestDFloat], + zeroth_ifd[ImageIFD.ZZZTestDFloat] + ) + def test_roundtrip_files(self): files = glob.glob(os.path.join("tests", "images", "r_*.jpg")) From 96c3f9cbbef2167e04e7fbf8167109165c5e1aa1 Mon Sep 17 00:00:00 2001 From: hMatoba Date: Sun, 10 Sep 2017 11:24:17 +0900 Subject: [PATCH 12/22] Edit document. --- doc/appendices.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/appendices.rst b/doc/appendices.rst index dec742d..371598d 100644 --- a/doc/appendices.rst +++ b/doc/appendices.rst @@ -13,10 +13,14 @@ http://www.cipa.jp/std/documents/e/DC-008-2012_E.pdf +---------------+----------------------+ | BYTE | int | +---------------+----------------------+ +| SIGNED BYTE | int | ++---------------+----------------------+ | ASCII | str | +---------------+----------------------+ | SHORT | int | +---------------+----------------------+ +| SIGNED SHORT | int | ++---------------+----------------------+ | LONG | int | +---------------+----------------------+ | RATIONAL | (int, int) | @@ -25,6 +29,10 @@ http://www.cipa.jp/std/documents/e/DC-008-2012_E.pdf +---------------+----------------------+ | SRATIONAL | (int, int) | +---------------+----------------------+ +| FLOAT | float | ++---------------+----------------------+ +| DOUBLE | float | ++---------------+----------------------+ If value type is number(BYTE, SHORT, LONG, RATIONAL, or SRATIONAL) and value count is two or more number, it is expressed with tuple. From 3050df3de9c7b55eb56114159ab89cf88d78d91c Mon Sep 17 00:00:00 2001 From: Michael Penkov Date: Sun, 10 Sep 2017 12:00:44 +0900 Subject: [PATCH 13/22] adding requirements.txt --- requirements.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ad3cbfd --- /dev/null +++ b/requirements.txt @@ -0,0 +1,20 @@ +alabaster==0.7.10 +Babel==2.5.0 +certifi==2017.7.27.1 +chardet==3.0.4 +docutils==0.14 +idna==2.6 +imagesize==0.7.1 +Jinja2==2.9.6 +MarkupSafe==1.0 +olefile==0.44 +Pillow==4.2.1 +Pygments==2.2.0 +pytz==2017.2 +requests==2.18.4 +six==1.10.0 +snowballstemmer==1.2.1 +Sphinx==1.6.3 +sphinxcontrib-websupport==1.0.1 +typing==3.6.2 +urllib3==1.22 From c27f7c5c7cd851dcb46cd6c10eabe69f613e9955 Mon Sep 17 00:00:00 2001 From: Michael Penkov Date: Sun, 10 Sep 2017 12:02:01 +0900 Subject: [PATCH 14/22] Implement encoding/decoding helper for ASCII, JIS and Unicode https://gist.github.com/hMatoba/efdfd5c0d13a4ee1ca2d1d4094c53a31 --- piexif/_helper.py | 65 +++++++++++++++++++++++++++++++++++++++++++++++ tests/s_test.py | 64 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 piexif/_helper.py diff --git a/piexif/_helper.py b/piexif/_helper.py new file mode 100644 index 0000000..c8841e6 --- /dev/null +++ b/piexif/_helper.py @@ -0,0 +1,65 @@ +# +# Names of encodings that we publicly support. +# +ASCII = 'ascii' +JIS = 'jis' +UNICODE = 'unicode' +ENCODINGS = (ASCII, JIS, UNICODE) + +# +# The actual encodings accepted by the standard library differ slightly from +# the above. +# +_JIS = 'shift_jis' +_UNICODE = 'utf_16_be' + +_PREFIX_SIZE = 8 +# +# From Table 9: Character Codes and their Designation +# +_ASCII_PREFIX = b'\x41\x53\x43\x49\x49\x00\x00\x00' +_JIS_PREFIX = b'\x4a\x49\x53\x00\x00\x00\x00\x00' +_UNICODE_PREFIX = b'\x55\x4e\x49\x43\x4f\x44\x45\x00' +_UNDEFINED_PREFIX = b'\x00\x00\x00\x00\x00\x00\x00\x00' + + +def load(data): + """ + Convert "UserComment" value in exif format to str. + + :param bytes data: "UserComment" value from exif + :return: u"foobar" + :rtype: str(Unicode) + :raises: ValueError if the data does not conform to the EXIF specification, + or the encoding is unsupported. + """ + if len(data) < _PREFIX_SIZE: + raise ValueError('not enough data to decode UserComment') + prefix = data[:_PREFIX_SIZE] + body = data[_PREFIX_SIZE:] + if prefix == _UNDEFINED_PREFIX: + raise ValueError('prefix is UNDEFINED, unable to decode UserComment') + try: + encoding = { + _ASCII_PREFIX: ASCII, _JIS_PREFIX: _JIS, _UNICODE_PREFIX: _UNICODE, + }[prefix] + except KeyError: + raise ValueError('unable to determine appropriate encoding') + return body.decode(encoding, errors='replace') + + +def dump(data, encoding="ascii"): + """ + Convert str to appropriate format for "UserComment". + + :param data: Like u"foobar" + :param str encoding: "ascii", "jis", or "unicode" + :return: b"ASCII\x00\x00\x00foobar" + :rtype: bytes + :raises: ValueError if the encoding is unsupported. + """ + if encoding not in ENCODINGS: + raise ValueError('encoding %r must be one of %r' % (encoding, ENCODINGS)) + prefix = {ASCII: _ASCII_PREFIX, JIS: _JIS_PREFIX, UNICODE: _UNICODE_PREFIX}[encoding] + internal_encoding = {UNICODE: _UNICODE, JIS: _JIS}.get(encoding, encoding) + return prefix + data.encode(internal_encoding, errors='replace') diff --git a/tests/s_test.py b/tests/s_test.py index a974132..e0518a4 100644 --- a/tests/s_test.py +++ b/tests/s_test.py @@ -767,10 +767,72 @@ def test_load_user_comment(self): self.assertRaises(ValueError, load_user_comment(binary)) +class HelperTests(unittest.TestCase): + def test_headers(self): + """Are our headers the correct length?""" + self.assertEqual(len(_helper._ASCII_PREFIX), _helper._PREFIX_SIZE) + self.assertEqual(len(_helper._JIS_PREFIX), _helper._PREFIX_SIZE) + self.assertEqual(len(_helper._UNICODE_PREFIX), _helper._PREFIX_SIZE) + self.assertEqual(len(_helper._UNDEFINED_PREFIX), _helper._PREFIX_SIZE) + + def test_encode_ascii(self): + """Do we encode ASCII correctly?""" + text = 'hello world' + expected = b'\x41\x53\x43\x49\x49\x00\x00\x00hello world' + actual = _helper.dump(text, encoding='ascii') + self.assertEqual(expected, actual) + + def test_decode_ascii(self): + """Do we decode ASCII correctly?""" + binary = b'\x41\x53\x43\x49\x49\x00\x00\x00hello world' + expected = 'hello world' + actual = _helper.load(binary) + self.assertEqual(expected, actual) + + def test_encode_jis(self): + """Do we encode JIS correctly?""" + text = '\u3053\u3093\u306b\u3061\u306f\u4e16\u754c' + expected = b'\x4a\x49\x53\x00\x00\x00\x00\x00' + text.encode('shift_jis') + actual = _helper.dump(text, encoding='jis') + self.assertEqual(expected, actual) + + def test_decode_jis(self): + """Do we decode JIS correctly?""" + expected = '\u3053\u3093\u306b\u3061\u306f\u4e16\u754c' + binary = b'\x4a\x49\x53\x00\x00\x00\x00\x00' + expected.encode('shift_jis') + actual = _helper.load(binary) + self.assertEqual(expected, actual) + + def test_encode_unicode(self): + """Do we encode Unicode correctly?""" + text = '\u3053\u3093\u306b\u3061\u306f\u4e16\u754c' + expected = b'\x55\x4e\x49\x43\x4f\x44\x45\x00' + text.encode('utf_16_be') + actual = _helper.dump(text, encoding='unicode') + self.assertEqual(expected, actual) + + def test_decode_unicode(self): + """Do we decode Unicode correctly?""" + expected = '\u3053\u3093\u306b\u3061\u306f\u4e16\u754c' + binary = b'\x55\x4e\x49\x43\x4f\x44\x45\x00' + expected.encode('utf_16_be') + actual = _helper.load(binary) + self.assertEqual(expected, actual) + + def test_encode_bad_encoding(self): + """De we gracefully handle bad input when encoding?""" + self.assertRaises(ValueError, _helper.dump, 'hello world', 'koi-8r') + + def test_decode_bad_encoding(self): + """De we gracefully handle bad input when decoding?""" + self.assertRaises(ValueError, _helper.load, b'\x00\x00\x00\x00\x00\x00\x00\x00hello') + self.assertRaises(ValueError, _helper.load, b'\x12\x34\x56\x78\x9a\xbc\xde\xffhello') + self.assertRaises(ValueError, _helper.load, b'hello world') + + def suite(): suite = unittest.TestSuite() suite.addTests([unittest.makeSuite(UTests), - unittest.makeSuite(ExifTests)]) + unittest.makeSuite(ExifTests), + unittest.makeSuite(HelperTests)]) return suite From f0172f7e0e84144f677933d1293419a633372a16 Mon Sep 17 00:00:00 2001 From: Michael Penkov Date: Sun, 10 Sep 2017 12:11:00 +0900 Subject: [PATCH 15/22] rebasing onto dev branch --- piexif/_helper.py | 65 -------------------------------------------- piexif/helper.py | 69 ++++++++++++++++++++++++++++++++++++++++++++++- tests/s_test.py | 28 +++++++++---------- 3 files changed, 82 insertions(+), 80 deletions(-) delete mode 100644 piexif/_helper.py diff --git a/piexif/_helper.py b/piexif/_helper.py deleted file mode 100644 index c8841e6..0000000 --- a/piexif/_helper.py +++ /dev/null @@ -1,65 +0,0 @@ -# -# Names of encodings that we publicly support. -# -ASCII = 'ascii' -JIS = 'jis' -UNICODE = 'unicode' -ENCODINGS = (ASCII, JIS, UNICODE) - -# -# The actual encodings accepted by the standard library differ slightly from -# the above. -# -_JIS = 'shift_jis' -_UNICODE = 'utf_16_be' - -_PREFIX_SIZE = 8 -# -# From Table 9: Character Codes and their Designation -# -_ASCII_PREFIX = b'\x41\x53\x43\x49\x49\x00\x00\x00' -_JIS_PREFIX = b'\x4a\x49\x53\x00\x00\x00\x00\x00' -_UNICODE_PREFIX = b'\x55\x4e\x49\x43\x4f\x44\x45\x00' -_UNDEFINED_PREFIX = b'\x00\x00\x00\x00\x00\x00\x00\x00' - - -def load(data): - """ - Convert "UserComment" value in exif format to str. - - :param bytes data: "UserComment" value from exif - :return: u"foobar" - :rtype: str(Unicode) - :raises: ValueError if the data does not conform to the EXIF specification, - or the encoding is unsupported. - """ - if len(data) < _PREFIX_SIZE: - raise ValueError('not enough data to decode UserComment') - prefix = data[:_PREFIX_SIZE] - body = data[_PREFIX_SIZE:] - if prefix == _UNDEFINED_PREFIX: - raise ValueError('prefix is UNDEFINED, unable to decode UserComment') - try: - encoding = { - _ASCII_PREFIX: ASCII, _JIS_PREFIX: _JIS, _UNICODE_PREFIX: _UNICODE, - }[prefix] - except KeyError: - raise ValueError('unable to determine appropriate encoding') - return body.decode(encoding, errors='replace') - - -def dump(data, encoding="ascii"): - """ - Convert str to appropriate format for "UserComment". - - :param data: Like u"foobar" - :param str encoding: "ascii", "jis", or "unicode" - :return: b"ASCII\x00\x00\x00foobar" - :rtype: bytes - :raises: ValueError if the encoding is unsupported. - """ - if encoding not in ENCODINGS: - raise ValueError('encoding %r must be one of %r' % (encoding, ENCODINGS)) - prefix = {ASCII: _ASCII_PREFIX, JIS: _JIS_PREFIX, UNICODE: _UNICODE_PREFIX}[encoding] - internal_encoding = {UNICODE: _UNICODE, JIS: _JIS}.get(encoding, encoding) - return prefix + data.encode(internal_encoding, errors='replace') diff --git a/piexif/helper.py b/piexif/helper.py index bd01d29..4f07009 100644 --- a/piexif/helper.py +++ b/piexif/helper.py @@ -1,8 +1,75 @@ +# +# Names of encodings that we publicly support. +# +ASCII = 'ascii' +JIS = 'jis' +UNICODE = 'unicode' +ENCODINGS = (ASCII, JIS, UNICODE) + +# +# The actual encodings accepted by the standard library differ slightly from +# the above. +# +_JIS = 'shift_jis' +_UNICODE = 'utf_16_be' + +_PREFIX_SIZE = 8 +# +# From Table 9: Character Codes and their Designation +# +_ASCII_PREFIX = b'\x41\x53\x43\x49\x49\x00\x00\x00' +_JIS_PREFIX = b'\x4a\x49\x53\x00\x00\x00\x00\x00' +_UNICODE_PREFIX = b'\x55\x4e\x49\x43\x4f\x44\x45\x00' +_UNDEFINED_PREFIX = b'\x00\x00\x00\x00\x00\x00\x00\x00' + + +def load(data): + """ + Convert "UserComment" value in exif format to str. + + :param bytes data: "UserComment" value from exif + :return: u"foobar" + :rtype: str(Unicode) + :raises: ValueError if the data does not conform to the EXIF specification, + or the encoding is unsupported. + """ + if len(data) < _PREFIX_SIZE: + raise ValueError('not enough data to decode UserComment') + prefix = data[:_PREFIX_SIZE] + body = data[_PREFIX_SIZE:] + if prefix == _UNDEFINED_PREFIX: + raise ValueError('prefix is UNDEFINED, unable to decode UserComment') + try: + encoding = { + _ASCII_PREFIX: ASCII, _JIS_PREFIX: _JIS, _UNICODE_PREFIX: _UNICODE, + }[prefix] + except KeyError: + raise ValueError('unable to determine appropriate encoding') + return body.decode(encoding, errors='replace') + + +def dump(data, encoding="ascii"): + """ + Convert str to appropriate format for "UserComment". + + :param data: Like u"foobar" + :param str encoding: "ascii", "jis", or "unicode" + :return: b"ASCII\x00\x00\x00foobar" + :rtype: bytes + :raises: ValueError if the encoding is unsupported. + """ + if encoding not in ENCODINGS: + raise ValueError('encoding %r must be one of %r' % (encoding, ENCODINGS)) + prefix = {ASCII: _ASCII_PREFIX, JIS: _JIS_PREFIX, UNICODE: _UNICODE_PREFIX}[encoding] + internal_encoding = {UNICODE: _UNICODE, JIS: _JIS}.get(encoding, encoding) + return prefix + data.encode(internal_encoding, errors='replace') + # return "str" def dump_user_comment(string): return None + # return "bytes" def load_user_comment(binary): - return None \ No newline at end of file + return None diff --git a/tests/s_test.py b/tests/s_test.py index e0518a4..c818f2f 100644 --- a/tests/s_test.py +++ b/tests/s_test.py @@ -770,62 +770,62 @@ def test_load_user_comment(self): class HelperTests(unittest.TestCase): def test_headers(self): """Are our headers the correct length?""" - self.assertEqual(len(_helper._ASCII_PREFIX), _helper._PREFIX_SIZE) - self.assertEqual(len(_helper._JIS_PREFIX), _helper._PREFIX_SIZE) - self.assertEqual(len(_helper._UNICODE_PREFIX), _helper._PREFIX_SIZE) - self.assertEqual(len(_helper._UNDEFINED_PREFIX), _helper._PREFIX_SIZE) + self.assertEqual(len(helper._ASCII_PREFIX), helper._PREFIX_SIZE) + self.assertEqual(len(helper._JIS_PREFIX), helper._PREFIX_SIZE) + self.assertEqual(len(helper._UNICODE_PREFIX), helper._PREFIX_SIZE) + self.assertEqual(len(helper._UNDEFINED_PREFIX), helper._PREFIX_SIZE) def test_encode_ascii(self): """Do we encode ASCII correctly?""" text = 'hello world' expected = b'\x41\x53\x43\x49\x49\x00\x00\x00hello world' - actual = _helper.dump(text, encoding='ascii') + actual = helper.dump(text, encoding='ascii') self.assertEqual(expected, actual) def test_decode_ascii(self): """Do we decode ASCII correctly?""" binary = b'\x41\x53\x43\x49\x49\x00\x00\x00hello world' expected = 'hello world' - actual = _helper.load(binary) + actual = helper.load(binary) self.assertEqual(expected, actual) def test_encode_jis(self): """Do we encode JIS correctly?""" text = '\u3053\u3093\u306b\u3061\u306f\u4e16\u754c' expected = b'\x4a\x49\x53\x00\x00\x00\x00\x00' + text.encode('shift_jis') - actual = _helper.dump(text, encoding='jis') + actual = helper.dump(text, encoding='jis') self.assertEqual(expected, actual) def test_decode_jis(self): """Do we decode JIS correctly?""" expected = '\u3053\u3093\u306b\u3061\u306f\u4e16\u754c' binary = b'\x4a\x49\x53\x00\x00\x00\x00\x00' + expected.encode('shift_jis') - actual = _helper.load(binary) + actual = helper.load(binary) self.assertEqual(expected, actual) def test_encode_unicode(self): """Do we encode Unicode correctly?""" text = '\u3053\u3093\u306b\u3061\u306f\u4e16\u754c' expected = b'\x55\x4e\x49\x43\x4f\x44\x45\x00' + text.encode('utf_16_be') - actual = _helper.dump(text, encoding='unicode') + actual = helper.dump(text, encoding='unicode') self.assertEqual(expected, actual) def test_decode_unicode(self): """Do we decode Unicode correctly?""" expected = '\u3053\u3093\u306b\u3061\u306f\u4e16\u754c' binary = b'\x55\x4e\x49\x43\x4f\x44\x45\x00' + expected.encode('utf_16_be') - actual = _helper.load(binary) + actual = helper.load(binary) self.assertEqual(expected, actual) def test_encode_bad_encoding(self): """De we gracefully handle bad input when encoding?""" - self.assertRaises(ValueError, _helper.dump, 'hello world', 'koi-8r') + self.assertRaises(ValueError, helper.dump, 'hello world', 'koi-8r') def test_decode_bad_encoding(self): """De we gracefully handle bad input when decoding?""" - self.assertRaises(ValueError, _helper.load, b'\x00\x00\x00\x00\x00\x00\x00\x00hello') - self.assertRaises(ValueError, _helper.load, b'\x12\x34\x56\x78\x9a\xbc\xde\xffhello') - self.assertRaises(ValueError, _helper.load, b'hello world') + self.assertRaises(ValueError, helper.load, b'\x00\x00\x00\x00\x00\x00\x00\x00hello') + self.assertRaises(ValueError, helper.load, b'\x12\x34\x56\x78\x9a\xbc\xde\xffhello') + self.assertRaises(ValueError, helper.load, b'hello world') def suite(): From 36e16e3e0464479307095536670df9484e23b530 Mon Sep 17 00:00:00 2001 From: Michael Penkov Date: Sun, 10 Sep 2017 12:13:24 +0900 Subject: [PATCH 16/22] fixing my own tests after rebase --- piexif/helper.py | 14 ++------------ tests/s_test.py | 22 ++++++++++++---------- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/piexif/helper.py b/piexif/helper.py index 4f07009..f5afad1 100644 --- a/piexif/helper.py +++ b/piexif/helper.py @@ -23,7 +23,7 @@ _UNDEFINED_PREFIX = b'\x00\x00\x00\x00\x00\x00\x00\x00' -def load(data): +def load_user_comment(data): """ Convert "UserComment" value in exif format to str. @@ -48,7 +48,7 @@ def load(data): return body.decode(encoding, errors='replace') -def dump(data, encoding="ascii"): +def dump_user_comment(data, encoding="ascii"): """ Convert str to appropriate format for "UserComment". @@ -63,13 +63,3 @@ def dump(data, encoding="ascii"): prefix = {ASCII: _ASCII_PREFIX, JIS: _JIS_PREFIX, UNICODE: _UNICODE_PREFIX}[encoding] internal_encoding = {UNICODE: _UNICODE, JIS: _JIS}.get(encoding, encoding) return prefix + data.encode(internal_encoding, errors='replace') - - -# return "str" -def dump_user_comment(string): - return None - - -# return "bytes" -def load_user_comment(binary): - return None diff --git a/tests/s_test.py b/tests/s_test.py index c818f2f..d269d8f 100644 --- a/tests/s_test.py +++ b/tests/s_test.py @@ -779,53 +779,55 @@ def test_encode_ascii(self): """Do we encode ASCII correctly?""" text = 'hello world' expected = b'\x41\x53\x43\x49\x49\x00\x00\x00hello world' - actual = helper.dump(text, encoding='ascii') + actual = helper.dump_user_comment(text, encoding='ascii') self.assertEqual(expected, actual) def test_decode_ascii(self): """Do we decode ASCII correctly?""" binary = b'\x41\x53\x43\x49\x49\x00\x00\x00hello world' expected = 'hello world' - actual = helper.load(binary) + actual = helper.load_user_comment(binary) self.assertEqual(expected, actual) def test_encode_jis(self): """Do we encode JIS correctly?""" text = '\u3053\u3093\u306b\u3061\u306f\u4e16\u754c' expected = b'\x4a\x49\x53\x00\x00\x00\x00\x00' + text.encode('shift_jis') - actual = helper.dump(text, encoding='jis') + actual = helper.dump_user_comment(text, encoding='jis') self.assertEqual(expected, actual) def test_decode_jis(self): """Do we decode JIS correctly?""" expected = '\u3053\u3093\u306b\u3061\u306f\u4e16\u754c' binary = b'\x4a\x49\x53\x00\x00\x00\x00\x00' + expected.encode('shift_jis') - actual = helper.load(binary) + actual = helper.load_user_comment(binary) self.assertEqual(expected, actual) def test_encode_unicode(self): """Do we encode Unicode correctly?""" text = '\u3053\u3093\u306b\u3061\u306f\u4e16\u754c' expected = b'\x55\x4e\x49\x43\x4f\x44\x45\x00' + text.encode('utf_16_be') - actual = helper.dump(text, encoding='unicode') + actual = helper.dump_user_comment(text, encoding='unicode') self.assertEqual(expected, actual) def test_decode_unicode(self): """Do we decode Unicode correctly?""" expected = '\u3053\u3093\u306b\u3061\u306f\u4e16\u754c' binary = b'\x55\x4e\x49\x43\x4f\x44\x45\x00' + expected.encode('utf_16_be') - actual = helper.load(binary) + actual = helper.load_user_comment(binary) self.assertEqual(expected, actual) def test_encode_bad_encoding(self): """De we gracefully handle bad input when encoding?""" - self.assertRaises(ValueError, helper.dump, 'hello world', 'koi-8r') + self.assertRaises(ValueError, helper.dump_user_comment, 'hello world', 'koi-8r') def test_decode_bad_encoding(self): """De we gracefully handle bad input when decoding?""" - self.assertRaises(ValueError, helper.load, b'\x00\x00\x00\x00\x00\x00\x00\x00hello') - self.assertRaises(ValueError, helper.load, b'\x12\x34\x56\x78\x9a\xbc\xde\xffhello') - self.assertRaises(ValueError, helper.load, b'hello world') + self.assertRaises(ValueError, helper.load_user_comment, + b'\x00\x00\x00\x00\x00\x00\x00\x00hello') + self.assertRaises(ValueError, helper.load_user_comment, + b'\x12\x34\x56\x78\x9a\xbc\xde\xffhello') + self.assertRaises(ValueError, helper.load_user_comment, b'hello world') def suite(): From af8fc2a469154c1e288cd407853a55da2e3d1230 Mon Sep 17 00:00:00 2001 From: Michael Penkov Date: Sun, 10 Sep 2017 12:15:06 +0900 Subject: [PATCH 17/22] fixing some of the original tests from dev branch --- tests/s_test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/s_test.py b/tests/s_test.py index d269d8f..18ae644 100644 --- a/tests/s_test.py +++ b/tests/s_test.py @@ -720,7 +720,7 @@ def test_dump_user_comment(self): # jis header = b"\x4a\x49\x53\x00\x00\x00\x00\x00" string = u"abcd" - binary = header + string.encode("jis") + binary = header + string.encode("shift_jis") result = helper.dump_user_comment(string, "jis") self.assertEqual(binary, result) @@ -735,7 +735,7 @@ def test_dump_user_comment(self): header = b"\x00\x00\x00\x00\x00\x00\x00\x00" string = u"abcd" binary = header + string.encode("latin") - self.assertRaises(ValueError, helper.dump_user_comment(string, "undefined")) + self.assertRaises(ValueError, helper.dump_user_comment, string, "undefined") def test_load_user_comment(self): @@ -749,7 +749,7 @@ def test_load_user_comment(self): # jis header = b"\x4a\x49\x53\x00\x00\x00\x00\x00" string = u"abcd" - binary = header + string.encode("jis") + binary = header + string.encode("shift_jis") result = helper.load_user_comment(binary) self.assertEqual(string, result) @@ -764,7 +764,7 @@ def test_load_user_comment(self): header = b"\x00\x00\x00\x00\x00\x00\x00\x00" string = u"abcd" binary = header + string.encode("ascii") - self.assertRaises(ValueError, load_user_comment(binary)) + self.assertRaises(ValueError, helper.load_user_comment, binary) class HelperTests(unittest.TestCase): From 98f6fbb29818487d008707b9aea1826b1f3f649c Mon Sep 17 00:00:00 2001 From: hMatoba Date: Sun, 10 Sep 2017 12:25:51 +0900 Subject: [PATCH 18/22] Edit document. --- doc/helper.rst | 34 ++++++++++++++++++++++++++++++++++ doc/index.rst | 1 + 2 files changed, 35 insertions(+) create mode 100644 doc/helper.rst diff --git a/doc/helper.rst b/doc/helper.rst new file mode 100644 index 0000000..7de41a8 --- /dev/null +++ b/doc/helper.rst @@ -0,0 +1,34 @@ +================ +Helper Functions +================ + +UserComment +----------- +.. py:function:: piexif.helper.load(data) + + Convert "UserComment" value in exif format to str. + + :param bytes data: "UserComment" value from exif + :return: u"foobar" + :rtype: str(Unicode) + +:: + + exif_dict = piexif.load("foo.jpg") + user_comment = piexif.helper.load(exif_dict["Exif"][piexif.ExifIFD.UserComment]) + +.. py:function:: piexif.helper.dump(data, encoding="ascii") + + Convert str to appropriate format for "UserComment". + + :param data: Like u"foobar" + :param str encoding: "ascii", "jis", or "unicode" + :return: b"ASCII\x00\x00\x00foobar" + :rtype: bytes + +:: + + user_comment = piexif.helper.dump(u"Edit now.") + exif_dict = piexif.load("foo.jpg") + exif_dict["Exif"][piexif.ExifIFD.UserComment] = user_comment + exif_bytes = piexif.dump(exif_dict) diff --git a/doc/index.rst b/doc/index.rst index 060c18d..1811e82 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -19,6 +19,7 @@ To simplify exif manipulations with python. Writing, reading, and more... Piexif about installation functions + helper appendices sample changes From 2c348729dea43976f9513a19fec933760be0c7a1 Mon Sep 17 00:00:00 2001 From: hMatoba Date: Sun, 10 Sep 2017 21:41:05 +0900 Subject: [PATCH 19/22] Edit helpers' namespace. --- piexif/helper.py | 120 ++++++++++++++++++++++++----------------------- tests/s_test.py | 44 ++++++++--------- 2 files changed, 83 insertions(+), 81 deletions(-) diff --git a/piexif/helper.py b/piexif/helper.py index f5afad1..167b8e2 100644 --- a/piexif/helper.py +++ b/piexif/helper.py @@ -1,65 +1,67 @@ -# -# Names of encodings that we publicly support. -# -ASCII = 'ascii' -JIS = 'jis' -UNICODE = 'unicode' -ENCODINGS = (ASCII, JIS, UNICODE) +class UserComment: + # + # Names of encodings that we publicly support. + # + ASCII = 'ascii' + JIS = 'jis' + UNICODE = 'unicode' + ENCODINGS = (ASCII, JIS, UNICODE) -# -# The actual encodings accepted by the standard library differ slightly from -# the above. -# -_JIS = 'shift_jis' -_UNICODE = 'utf_16_be' + # + # The actual encodings accepted by the standard library differ slightly from + # the above. + # + _JIS = 'shift_jis' + _UNICODE = 'utf_16_be' -_PREFIX_SIZE = 8 -# -# From Table 9: Character Codes and their Designation -# -_ASCII_PREFIX = b'\x41\x53\x43\x49\x49\x00\x00\x00' -_JIS_PREFIX = b'\x4a\x49\x53\x00\x00\x00\x00\x00' -_UNICODE_PREFIX = b'\x55\x4e\x49\x43\x4f\x44\x45\x00' -_UNDEFINED_PREFIX = b'\x00\x00\x00\x00\x00\x00\x00\x00' + _PREFIX_SIZE = 8 + # + # From Table 9: Character Codes and their Designation + # + _ASCII_PREFIX = b'\x41\x53\x43\x49\x49\x00\x00\x00' + _JIS_PREFIX = b'\x4a\x49\x53\x00\x00\x00\x00\x00' + _UNICODE_PREFIX = b'\x55\x4e\x49\x43\x4f\x44\x45\x00' + _UNDEFINED_PREFIX = b'\x00\x00\x00\x00\x00\x00\x00\x00' + @classmethod + def load(cls, data): + """ + Convert "UserComment" value in exif format to str. -def load_user_comment(data): - """ - Convert "UserComment" value in exif format to str. + :param bytes data: "UserComment" value from exif + :return: u"foobar" + :rtype: str(Unicode) + :raises: ValueError if the data does not conform to the EXIF specification, + or the encoding is unsupported. + """ + if len(data) < cls._PREFIX_SIZE: + raise ValueError('not enough data to decode UserComment') + prefix = data[:cls._PREFIX_SIZE] + body = data[cls._PREFIX_SIZE:] + if prefix == cls._UNDEFINED_PREFIX: + raise ValueError('prefix is UNDEFINED, unable to decode UserComment') + try: + encoding = { + cls._ASCII_PREFIX: cls.ASCII, cls._JIS_PREFIX: cls._JIS, cls._UNICODE_PREFIX: cls._UNICODE, + }[prefix] + except KeyError: + raise ValueError('unable to determine appropriate encoding') + return body.decode(encoding, errors='replace') - :param bytes data: "UserComment" value from exif - :return: u"foobar" - :rtype: str(Unicode) - :raises: ValueError if the data does not conform to the EXIF specification, - or the encoding is unsupported. - """ - if len(data) < _PREFIX_SIZE: - raise ValueError('not enough data to decode UserComment') - prefix = data[:_PREFIX_SIZE] - body = data[_PREFIX_SIZE:] - if prefix == _UNDEFINED_PREFIX: - raise ValueError('prefix is UNDEFINED, unable to decode UserComment') - try: - encoding = { - _ASCII_PREFIX: ASCII, _JIS_PREFIX: _JIS, _UNICODE_PREFIX: _UNICODE, - }[prefix] - except KeyError: - raise ValueError('unable to determine appropriate encoding') - return body.decode(encoding, errors='replace') + @classmethod + def dump(cls, data, encoding="ascii"): + """ + Convert str to appropriate format for "UserComment". - -def dump_user_comment(data, encoding="ascii"): - """ - Convert str to appropriate format for "UserComment". - - :param data: Like u"foobar" - :param str encoding: "ascii", "jis", or "unicode" - :return: b"ASCII\x00\x00\x00foobar" - :rtype: bytes - :raises: ValueError if the encoding is unsupported. - """ - if encoding not in ENCODINGS: - raise ValueError('encoding %r must be one of %r' % (encoding, ENCODINGS)) - prefix = {ASCII: _ASCII_PREFIX, JIS: _JIS_PREFIX, UNICODE: _UNICODE_PREFIX}[encoding] - internal_encoding = {UNICODE: _UNICODE, JIS: _JIS}.get(encoding, encoding) - return prefix + data.encode(internal_encoding, errors='replace') + :param data: Like u"foobar" + :param str encoding: "ascii", "jis", or "unicode" + :return: b"ASCII\x00\x00\x00foobar" + :rtype: bytes + :raises: ValueError if the encoding is unsupported. + """ + print(dir(cls)) + if encoding not in cls.ENCODINGS: + raise ValueError('encoding %r must be one of %r' % (encoding, cls.ENCODINGS)) + prefix = {cls.ASCII: cls._ASCII_PREFIX, cls.JIS: cls._JIS_PREFIX, cls.UNICODE: cls._UNICODE_PREFIX}[encoding] + internal_encoding = {cls.UNICODE: cls._UNICODE, cls.JIS: cls._JIS}.get(encoding, encoding) + return prefix + data.encode(internal_encoding, errors='replace') diff --git a/tests/s_test.py b/tests/s_test.py index 79daf10..8baf3e2 100644 --- a/tests/s_test.py +++ b/tests/s_test.py @@ -739,28 +739,28 @@ def test_dump_user_comment(self): header = b"\x41\x53\x43\x49\x49\x00\x00\x00" string = u"abcd" binary = header + string.encode("ascii") - result = helper.dump_user_comment(string, "ascii") + result = helper.UserComment.dump(string, "ascii") self.assertEqual(binary, result) # jis header = b"\x4a\x49\x53\x00\x00\x00\x00\x00" string = u"abcd" binary = header + string.encode("shift_jis") - result = helper.dump_user_comment(string, "jis") + result = helper.UserComment.dump(string, "jis") self.assertEqual(binary, result) # unicode header = b"\x55\x4e\x49\x43\x4f\x44\x45\x00" string = u"abcd" binary = header + string.encode("utf-16-be") - result = helper.dump_user_comment(string, "unicode") + result = helper.UserComment.dump(string, "unicode") self.assertEqual(binary, result) # undefined header = b"\x00\x00\x00\x00\x00\x00\x00\x00" string = u"abcd" binary = header + string.encode("latin") - self.assertRaises(ValueError, helper.dump_user_comment, string, "undefined") + self.assertRaises(ValueError, helper.UserComment.dump, string, "undefined") def test_load_user_comment(self): @@ -768,91 +768,91 @@ def test_load_user_comment(self): header = b"\x41\x53\x43\x49\x49\x00\x00\x00" string = u"abcd" binary = header + string.encode("ascii") - result = helper.load_user_comment(binary) + result = helper.UserComment.load(binary) self.assertEqual(string, result) # jis header = b"\x4a\x49\x53\x00\x00\x00\x00\x00" string = u"abcd" binary = header + string.encode("shift_jis") - result = helper.load_user_comment(binary) + result = helper.UserComment.load(binary) self.assertEqual(string, result) # unicode header = b"\x55\x4e\x49\x43\x4f\x44\x45\x00" string = u"abcd" binary = header + string.encode("utf-16-be") - result = helper.load_user_comment(binary) + result = helper.UserComment.load(binary) self.assertEqual(string, result) # undefined header = b"\x00\x00\x00\x00\x00\x00\x00\x00" string = u"abcd" binary = header + string.encode("ascii") - self.assertRaises(ValueError, helper.load_user_comment, binary) + self.assertRaises(ValueError, helper.UserComment.load, binary) class HelperTests(unittest.TestCase): def test_headers(self): """Are our headers the correct length?""" - self.assertEqual(len(helper._ASCII_PREFIX), helper._PREFIX_SIZE) - self.assertEqual(len(helper._JIS_PREFIX), helper._PREFIX_SIZE) - self.assertEqual(len(helper._UNICODE_PREFIX), helper._PREFIX_SIZE) - self.assertEqual(len(helper._UNDEFINED_PREFIX), helper._PREFIX_SIZE) + self.assertEqual(len(helper.UserComment._ASCII_PREFIX), helper.UserComment._PREFIX_SIZE) + self.assertEqual(len(helper.UserComment._JIS_PREFIX), helper.UserComment._PREFIX_SIZE) + self.assertEqual(len(helper.UserComment._UNICODE_PREFIX), helper.UserComment._PREFIX_SIZE) + self.assertEqual(len(helper.UserComment._UNDEFINED_PREFIX), helper.UserComment._PREFIX_SIZE) def test_encode_ascii(self): """Do we encode ASCII correctly?""" text = 'hello world' expected = b'\x41\x53\x43\x49\x49\x00\x00\x00hello world' - actual = helper.dump_user_comment(text, encoding='ascii') + actual = helper.UserComment.dump(text, encoding='ascii') self.assertEqual(expected, actual) def test_decode_ascii(self): """Do we decode ASCII correctly?""" binary = b'\x41\x53\x43\x49\x49\x00\x00\x00hello world' expected = 'hello world' - actual = helper.load_user_comment(binary) + actual = helper.UserComment.load(binary) self.assertEqual(expected, actual) def test_encode_jis(self): """Do we encode JIS correctly?""" text = '\u3053\u3093\u306b\u3061\u306f\u4e16\u754c' expected = b'\x4a\x49\x53\x00\x00\x00\x00\x00' + text.encode('shift_jis') - actual = helper.dump_user_comment(text, encoding='jis') + actual = helper.UserComment.dump(text, encoding='jis') self.assertEqual(expected, actual) def test_decode_jis(self): """Do we decode JIS correctly?""" expected = '\u3053\u3093\u306b\u3061\u306f\u4e16\u754c' binary = b'\x4a\x49\x53\x00\x00\x00\x00\x00' + expected.encode('shift_jis') - actual = helper.load_user_comment(binary) + actual = helper.UserComment.load(binary) self.assertEqual(expected, actual) def test_encode_unicode(self): """Do we encode Unicode correctly?""" text = '\u3053\u3093\u306b\u3061\u306f\u4e16\u754c' expected = b'\x55\x4e\x49\x43\x4f\x44\x45\x00' + text.encode('utf_16_be') - actual = helper.dump_user_comment(text, encoding='unicode') + actual = helper.UserComment.dump(text, encoding='unicode') self.assertEqual(expected, actual) def test_decode_unicode(self): """Do we decode Unicode correctly?""" expected = '\u3053\u3093\u306b\u3061\u306f\u4e16\u754c' binary = b'\x55\x4e\x49\x43\x4f\x44\x45\x00' + expected.encode('utf_16_be') - actual = helper.load_user_comment(binary) + actual = helper.UserComment.load(binary) self.assertEqual(expected, actual) def test_encode_bad_encoding(self): """De we gracefully handle bad input when encoding?""" - self.assertRaises(ValueError, helper.dump_user_comment, 'hello world', 'koi-8r') + self.assertRaises(ValueError, helper.UserComment.dump, 'hello world', 'koi-8r') def test_decode_bad_encoding(self): """De we gracefully handle bad input when decoding?""" - self.assertRaises(ValueError, helper.load_user_comment, + self.assertRaises(ValueError, helper.UserComment.load, b'\x00\x00\x00\x00\x00\x00\x00\x00hello') - self.assertRaises(ValueError, helper.load_user_comment, + self.assertRaises(ValueError, helper.UserComment.load, b'\x12\x34\x56\x78\x9a\xbc\xde\xffhello') - self.assertRaises(ValueError, helper.load_user_comment, b'hello world') + self.assertRaises(ValueError, helper.UserComment.load, b'hello world') def suite(): From 40f12eaa2140ee550adbc01e15f60d2e58099bce Mon Sep 17 00:00:00 2001 From: hMatoba Date: Sun, 10 Sep 2017 21:48:59 +0900 Subject: [PATCH 20/22] m --- piexif/helper.py | 1 - 1 file changed, 1 deletion(-) diff --git a/piexif/helper.py b/piexif/helper.py index 167b8e2..0e4d10c 100644 --- a/piexif/helper.py +++ b/piexif/helper.py @@ -59,7 +59,6 @@ def dump(cls, data, encoding="ascii"): :rtype: bytes :raises: ValueError if the encoding is unsupported. """ - print(dir(cls)) if encoding not in cls.ENCODINGS: raise ValueError('encoding %r must be one of %r' % (encoding, cls.ENCODINGS)) prefix = {cls.ASCII: cls._ASCII_PREFIX, cls.JIS: cls._JIS_PREFIX, cls.UNICODE: cls._UNICODE_PREFIX}[encoding] From 9c9eadfb5f100d7216916e8bb6db62b3d2713e6e Mon Sep 17 00:00:00 2001 From: hMatoba Date: Sun, 10 Sep 2017 21:50:47 +0900 Subject: [PATCH 21/22] Edit document. --- doc/helper.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/doc/helper.rst b/doc/helper.rst index 7de41a8..86531ff 100644 --- a/doc/helper.rst +++ b/doc/helper.rst @@ -4,7 +4,7 @@ Helper Functions UserComment ----------- -.. py:function:: piexif.helper.load(data) +.. py:function:: piexif.helper.UserComment.load(data) Convert "UserComment" value in exif format to str. @@ -14,10 +14,12 @@ UserComment :: + import piexif + import piexif.helper exif_dict = piexif.load("foo.jpg") - user_comment = piexif.helper.load(exif_dict["Exif"][piexif.ExifIFD.UserComment]) + user_comment = piexif.helper.UserComment.load(exif_dict["Exif"][piexif.ExifIFD.UserComment]) -.. py:function:: piexif.helper.dump(data, encoding="ascii") +.. py:function:: piexif.helper.UserComment.dump(data, encoding="ascii") Convert str to appropriate format for "UserComment". @@ -28,7 +30,9 @@ UserComment :: - user_comment = piexif.helper.dump(u"Edit now.") + import piexif + import piexif.helper + user_comment = piexif.helper.UserComment.dump(u"Edit now.") exif_dict = piexif.load("foo.jpg") exif_dict["Exif"][piexif.ExifIFD.UserComment] = user_comment exif_bytes = piexif.dump(exif_dict) From 6374931e63fa84cdeece824a231f7bd5e284937c Mon Sep 17 00:00:00 2001 From: hMatoba Date: Sun, 10 Sep 2017 21:53:18 +0900 Subject: [PATCH 22/22] ver 1.0.13 --- doc/changes.rst | 6 ++++++ piexif/__init__.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/doc/changes.rst b/doc/changes.rst index 0491af6..184358f 100644 --- a/doc/changes.rst +++ b/doc/changes.rst @@ -1,6 +1,12 @@ Changelog ========= +1.0.13 +------ + +- Added helper function to read and write "UserComment". +- Added to support for SignedByte, SigendShort, Float, and Double. + 1.0.12 ------ diff --git a/piexif/__init__.py b/piexif/__init__.py index aa9d11a..600f499 100644 --- a/piexif/__init__.py +++ b/piexif/__init__.py @@ -7,4 +7,4 @@ from ._exceptions import * -VERSION = '1.0.12' +VERSION = '1.0.13'