{ "info": { "author": "Bruno THOORENS", "author_email": "bruno.thoorens@free.fr", "bugtrack_url": null, "classifiers": [ "Development Status :: 6 - Mature", "Environment :: Console", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 3", "Topic :: Multimedia :: Graphics" ], "description": "``Tyf`` package provides simple way to view and edit Exif data from \n``TIFF`` and ``JPEG`` files.\n\nChanges\n=======\n\n1.3.2\n\n+ ``JpegFile`` API change\n+ ``JpegFile`` keeps XMP metadata as ``xml.etree.ElementTree.Element`` object\n+ ``Ifd`` class manage to translate tags\n+ added ``find`` and ``place`` method to ``Ifd`` class\n+ encoders / decoders improvements\n\n1.3.1\n\n+ encoders / decoders bugfix\n+ added ``__iter__`` to ``Ifd`` class\n\n>>> jpg = Tyf.open(\"test.jpg\")\n>>> for v in jpg.ifd0: print(v)\n...\n('ImageWidth', 2560)\n('ImageLength', 1920)\n[...]\n('GPSProcessingMethod', b'NETWORK')\n('GPSDateStamp', datetime.datetime(2015, 12, 29, 0, 0))\n\n1.3.0\n\n+ bugfix issue #10\n+ sub ifd API change (sub ifd recursivity added)\n\n>>> jpg.ifd0\n{256: , 257: , 34853: , 34665: , 306: , 271: , 272: , 305: , 274: :: Normal, 531: :: Centered, 33432: , 40092: }\n>>> jpg.ifd0.exif\n{36864: , 37377: , 37378: , 36867: , 36868: , 37381: , 37510: , 37383: :: Center Weighted Average, 37385: :: Flash did not fire, 37386: , 41986: :: Auto exposure, 40963: , 37380: , 33434: , 33437: , 34850: :: Aperture priority, 409\n61: :: RGB, 41990: :: Standard, 34855: , 41987: :: Auto white balance, 37379: , 40962: }\n>>> jpg.ifd0.gps\n{0: , 1: :: North latitude, 2: , 3: :: East longitude, 4: , 5: :: Below sea level, 6: , 7: , 16: :: Magnetic direction, 17: , 27: , 29: }\n\n1.2.5\n\n+ bugfix issue #5\n+ bugfix issue #6\n\n1.2.4\n\n+ added ``set_location`` and ``get_location`` to ``Ifd`` class\n\n>>> from Tyf.ifd import Ifd\n>>> ifd = Ifd()\n>>> ifd.set_location(-4.362746, 48.958474, -152.2356)\n>>> for tag in ifd.tags(): print(tag)\n...\n :: 'North latitude'\n\n :: 'West longitude'\n\n :: 'Below sea level'\n\n>>> ifd.get_location()\n(-4.362746, 48.958474, -152.2356)\n\n1.2.3\n\n+ bugfix for ``Tyf.Image.save`` method\n+ added ``__PY3__`` variable for verion testing\n\n1.2.2\n\n+ bugfix for ``Tyf.gkd.Gkd.to_ifd`` method\n\n1.2.1\n\n+ bugfix for issue #1\n\n1.2.0\n\n+ ``PIL`` (``pillow``) integration for JPEG images\n\n1.1.3\n\n+ added ``load_location`` & ``dump_location`` to ``Ifd`` class\n+ added ``dump_exif`` & ``load_exif`` to ``JpegFile`` class\n\n1.1.2\n\n+ ``JpegFile`` class now handle JPEG and TIFF thumbnail\n+ added ``save_thumbnail`` method for ``JpegFile`` class\n+ ``TiffFile`` raster data loaded only if needed or on demand\n+ added ``load_raster`` method for ``TiffFile`` class\n+ ``_2`` encoder fix (ascii encoder)\n+ code tweaks\n\n1.1.1\n\n+ added hability to read custom sub IFD\n+ ``_5`` encoder fix (rational encoder)\n+ ``__repr__`` format update\n+ removed ``thumbnail`` property for ``JpegFile`` class\n\n1.1b0\n\n+ added encoders / decoders\n+ added ``ifd1`` property to ``JpegFile`` class\n+ added ``exif_ifd`` property to ``Ifd`` class\n+ added ``gps_ifd`` property to ``Ifd`` class\n\n1.0b1\n\n+ fixed bug with Exif data modified by windows explorer\n+ added XP tags\n\n1.0b0\n\n+ added ``gkd`` property for ``TiffFile`` class\n+ added ``exif`` property for ``JpegFile`` class\n+ read/write ifd and exif data\n+ ``TiffFile`` concatenation using ``+`` operator (i.e. multi image ``TIFF`` file)\n\n0.9a1\n\n+ multiple IFD management with ``TiffFile`` class\n+ added ``save`` method for ``JpegFile`` and ``TiffFile`` classes\n+ full ``JPEG`` Exif read (IFD0 and IFD1 for ``0xffe1`` marker)\n+ added ``thumbnail`` property for ``JpegFile`` class\n\n0.8a4\n\n+ first consistant release\n\nQuick view\n==========\n\n>>> import Tyf\n\n``Tag``\n-------\n\n>>> import Tyf\n>>> t = Tyf.ifd.Tag(\"GPSLongitude\")\n>>> t.digest(4.362743)\n>>> t\n\n>>> t = Tyf.ifd.Tag(\"GPSLongitude\", value=4.362743)\n>>> t\n\n>>> t.type\n5\n>>> t.count\n3\n>>> t.value\n(4, 1, 21, 1, 114687, 2500)\n>>> t.decode()\n4.362743\n>>> t = Tyf.ifd.Tag(\"KeyTest\")\n\n\n``Ifd``\n-------\n\n>>> from Tyf import tags\n>>> ifd = Tyf.ifd.Ifd(tag_family=[tags.bTT, tags.xTT, tags.pTT])\n>>> ifd[\"Copyright\"] = \"Bruno THOORENS\"\n>>> ifd\n>>> ifd\n{33432: }\n>>> gps_ifd = ifd[\"GPS IFD\"] # create \"GPS IFD\" sub ifd in ifd\n>>> gps_ifd.append(t)\n>>> gps_ifd # t is no more orphan\n{4: }\n>>> gps_ifd[\"GPSLongitudeRef\"] = gps_ifd[\"GPSLongitude\"]\n>>> gps_ifd[\"GPSLatitude\"] = gps_ifd[\"GPSLatitudeRef\"] = 48.958474\n>>> gps_ifd\n{1: :: North latitude, 2: , 3: :: East \nlongitude, 4: }\n>>> ifd.dump_location(\"./pypi_test_location\", format=\"jpg\", size=\"512x256\")\n\n.. image:: https://raw.githubusercontent.com/Moustikitos/tyf/master/test/pypi_test_location.jpg\n\nThumbnail location can be dumped from google ``staticmap`` API if all latitude and longitude tags exist.\n\n>>> for tag in ifd.tags(): print(tag)\n...\n\n\n :: North latitude\n\n :: East longitude\n\n\n``to_buffer``\n-------------\n\n>>> from io import BytesIO as StringIO\n>>> s = StringIO()\n>>> Tyf.to_buffer(ifd, s, offset=0)\n195\n>>> s.getvalue()\nb'\\x02\\x00\\x98\\x82\\x02\\x00\\x0f\\x00\\x00\\x00\\x1e\\x00\\x00\\x00%\\x88\\x04\\x00\\x01\\x00\\x00\\x00-\\\nx00\\x00\\x00\\x00\\x00\\x00\\x00Bruno THOORENS\\x00\\x04\\x00\\x01\\x00\\x02\\x00\\x02\\x00\\x00\\x00N\\x0\n0\\x00\\x00\\x02\\x00\\x05\\x00\\x03\\x00\\x00\\x00c\\x00\\x00\\x00\\x03\\x00\\x02\\x00\\x02\\x00\\x00\\x00E\\x\n00\\x00\\x00\\x04\\x00\\x05\\x00\\x03\\x00\\x00\\x00{\\x00\\x00\\x00\\x00\\x00\\x00\\x000\\x00\\x00\\x00\\x01\\\nx00\\x00\\x009\\x00\\x00\\x00\\x01\\x00\\x00\\x00\\xf5\\x94\\x00\\x00\\xe2\\x04\\x00\\x00\\x04\\x00\\x00\\x00\\\nx01\\x00\\x00\\x00\\x15\\x00\\x00\\x00\\x01\\x00\\x00\\x00\\xff\\xbf\\x01\\x00\\xc4\\t\\x00\\x00'\n\n``from_buffer``\n---------------\n\n>>> s.seek(0)\n0\n>>> ifd1 = Tyf.ifd.Ifd(tag_family=[tags.bTT, tags.xTT, tags.pTT])\n>>> Tyf.from_buffer(ifd1, s, offset=0)\n0\n>>> ifd1\n{33432: , 34853: }\n>>> ifd1.gps_ifd\n{1: :: 'North latitude', 2: , 3: :: 'Ea\nst longitude', 4: }\n>>> for tag in ifd1.tags(): print(tag)\n...\n\n\n :: North latitude\n\n :: East longitude\n\n>>> ifd1[\"GPS IFD\"][\"GPSLongitude\"]\n4.362743\n\n``open``\n--------\n\n``Tyf`` package exports ``open`` function. It returns ``JpegFile`` or \n``TiffFile`` class that enables metadata reading and writing.\n\n>>> import Tyf\n>>> jpg = Tyf.open(r\".\\IMG_20150730_210115.jpg\")\n>>> tif = Tyf.open(r\".\\CEA.tif\")\n>>> isinstance(jpg, list)\nTrue\n>>> isinstance(tif, list)\nTrue\n\n``JpegFile``\n------------\n\n``JpegFile`` class is an list mapping all marker found in ``JPEG`` file.\nValues are stored as binary data except ``0xffe1`` one stored as a ``TiffFile``\ninstance or a ``bytes`` object (XMP data).\n\n>>> type(jpg.ifd)\n\n>>> len(jpg.ifd)\n2\n>>> jpg.ifd0 # shortcut to jpg.ifd[0]\n{256: , 305: , 274: :: Normal, 531: :: Centered, 34853: , 257: , 34665: , 306: , 272: , 271: }\n>>> jpg.ifd1 # shortcut to jpg.ifd[1]\n{256: , 257: ,\n 274: :: Normal, 259: :: JPEG, 513: , 296: :: Inch, 282: , 283: , 514: }\n>>>jpg.xmp\n\n\nAll information, including GPS and Exif IFD are available using ``.tags()`` \nmethod of its first item\n\n>>> for tag in jpg.ifd0.tags(): print(tag)\n...\n\n\n[...]\n\n\n\nJPEG or TIFF thumbnail embeded in JPEG file can be extracted into a single file\n\n>>> jpg.save_thumbnail(\".\\test_thumb\") # file extension will be appended automaticaly\n\n.. image:: https://raw.githubusercontent.com/Moustikitos/tyf/master/test/test_thumb.jpg\n\nAnd because ``JpegFile.ifd0`` is actually a shortcut to a ``Tyf.ifd.Ifd`` instance :\n\n>>> jpg.ifd0.dump_location(\"./pypi_test_location1\", format=\"jpg\")\n\n.. image:: https://raw.githubusercontent.com/Moustikitos/tyf/master/test/pypi_test_location1.jpg\n\n``TiffFile``\n------------\n\n``TiffFile`` class is a list of IFD found in ``TIFF`` file. Each IFD is a dictionary\ncontaining tag-value pair.\n\n>>> for tag in tif[0].tags(): print(tag)\n...\n\n\n[...]\n\n\n\nIf asked (or needed), any raster data found will be loaded.\n\n>>> tif.has_raster\nTrue\n>>> tif.raster_loaded\nFalse\n>>> tif.load_raster()\n>>> tif.raster_loaded\nTrue\n\nGeotiff data can also be extracted from IFD.\n\n>>> geotiff = tif.gkd\n>>> for tag in geotiff[0].tags(): print(tag) # geotiff from the first ifd\n...\n :: Projection Coordinate System\n :: Raster pixel is area\n\n :: NAD27\n[...]\n\n\n>>> mt = geotiff[0].getModelTransformation()\n>>> mt(50, 50) # compute pixel coordinates\n(-25492.059935252837, 4252883.436953031, 0.0, 1.0)\n\n``PIL`` integration\n-------------------\n\n>>> from Tyf import Image\n>>> img = Tyf.Image.open(r\".\\IMG_20150730_210115.jpg\")\n>>> img\n\n>>> exf = img._getexif()\n>>> exf\n[{256: , 305: , 274: :: Normal, 531: :: Centered, 34853: , 257: , 34665: , 306: , 272: , 271: }, {256: , 257: , 274: :: Normal, 259: :: JPEG, 513: , 296: :: Inch,\n 282: , 283: , 514: }]\n>>> exf.__class__\n\n>>> exf[0][\"UserComment\"] = \"Simple commentaire\"\n>>> exf[0][\"Copyright\"] = \"Bruno THOORENS\"\n>>> img.save(r\".\\test.jpg\", ifd=exf) # write JPEG image with exif\n\nSupport this project\n====================\n\n.. image:: http://bruno.thoorens.free.fr/img/gratipay.png\n :target: https://gratipay.com/tyf\n\n---\n\n.. image:: http://bruno.thoorens.free.fr/img/bitcoin.png\n\n3Jgib9SQiDLYML7QKBYtJUkHq2nyG6Z63D", "description_content_type": null, "docs_url": "https://pythonhosted.org/Tyf/", "download_url": "https://github.com/Moustikitos/tyf", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://bruno.thoorens.free.fr", "keywords": "ifd,tiff,jpeg,exif,gps,geotiff,PIL,Pillow", "license": "Copyright 2015-2016, THOORENS Bruno, BSD licence", "maintainer": null, "maintainer_email": null, "name": "Tyf", "package_url": "https://pypi.org/project/Tyf/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/Tyf/", "project_urls": { "Download": "https://github.com/Moustikitos/tyf", "Homepage": "http://bruno.thoorens.free.fr" }, "release_url": "https://pypi.org/project/Tyf/1.3.2/", "requires_dist": null, "requires_python": null, "summary": "Pythonic way to read and edit IFD and EXIF tags.", "version": "1.3.2" }, "last_serial": 2534924, "releases": { "1.1.3": [ { "comment_text": "", "digests": { "md5": "79c2268b75457c5bdbc8caa14d3fd24b", "sha256": "9a1c702b5b43e47ea56d16cc31da6b6747ae3b351903791ba2d9049dcabb9e83" }, "downloads": -1, "filename": "Tyf-1.1.3-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "79c2268b75457c5bdbc8caa14d3fd24b", "packagetype": "bdist_wheel", "python_version": "3.5", "requires_python": null, "size": 45360, "upload_time": "2016-01-06T11:03:20", "url": "https://files.pythonhosted.org/packages/9d/ec/df597c4329e96d153a5a6247362fb9bff51a7793ff6e319008420f755819/Tyf-1.1.3-py2.py3-none-any.whl" } ], "1.2.0": [ { "comment_text": "", "digests": { "md5": "404a8e538956da2556158f5699d35365", "sha256": "4a067987feebd4cc7b30ff10e5392aa2a6cd39a797ccfa5a3a68bd1d1da08ff8" }, "downloads": -1, "filename": "Tyf-1.2.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "404a8e538956da2556158f5699d35365", "packagetype": "bdist_wheel", "python_version": "3.5", "requires_python": null, "size": 46172, "upload_time": "2016-01-23T20:41:07", "url": "https://files.pythonhosted.org/packages/df/b3/2698b8681f2545f28e40d0da9ea7a441084409c8433294afe7ed9623aca7/Tyf-1.2.0-py2.py3-none-any.whl" } ], "1.2.1": [ { "comment_text": "", "digests": { "md5": "ba9fe1f8bca66133616e1fef48c399d6", "sha256": "fb8464a299c49119ea3df0435b1e92d2efa384553cac56e22c9fb4d6360bcdf8" }, "downloads": -1, "filename": "Tyf-1.2.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "ba9fe1f8bca66133616e1fef48c399d6", "packagetype": "bdist_wheel", "python_version": "3.5", "requires_python": null, "size": 46318, "upload_time": "2016-03-10T05:47:11", "url": "https://files.pythonhosted.org/packages/ec/a3/ef36f81723a19d6a41f4fcd800ac8fef032cbc5a88cac08c651324d02e77/Tyf-1.2.1-py2.py3-none-any.whl" } ], "1.2.2": [ { "comment_text": "", "digests": { "md5": "0db72c5195750e65b41b679e1b49770e", "sha256": "e69c69aa37c85875e5d3243592a7435df092717c33e667184587076a2bb7dd91" }, "downloads": -1, "filename": "Tyf-1.2.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "0db72c5195750e65b41b679e1b49770e", "packagetype": "bdist_wheel", "python_version": "3.5", "requires_python": null, "size": 46332, "upload_time": "2016-03-19T16:38:10", "url": "https://files.pythonhosted.org/packages/a9/71/b3ca171fc77c1de5f91b73ca003fbc63ecbf4cc8607ee701d07a8a5f87aa/Tyf-1.2.2-py2.py3-none-any.whl" } ], "1.2.3": [ { "comment_text": "", "digests": { "md5": "bb3083553d32c9655c684b47fc79a549", "sha256": "7c861791b0739ffc9073f85da2af8f3e610b13588073418b9c46151deb90d8b8" }, "downloads": -1, "filename": "Tyf-1.2.3-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "bb3083553d32c9655c684b47fc79a549", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 46510, "upload_time": "2016-07-16T10:19:00", "url": "https://files.pythonhosted.org/packages/3f/85/2203607e903ceffcf580573e80ba4c1cf3335b5f95ed0551d53e4e255446/Tyf-1.2.3-py2.py3-none-any.whl" } ], "1.2.4": [ { "comment_text": "", "digests": { "md5": "568af21863f3ef05a2534c410e2a6245", "sha256": "591e24a603d4287289a5cb2f4c21d02a2b00ff0773cdcbc615b0e4d8cce0cefd" }, "downloads": -1, "filename": "Tyf-1.2.4-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "568af21863f3ef05a2534c410e2a6245", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 46991, "upload_time": "2016-07-16T12:25:24", "url": "https://files.pythonhosted.org/packages/49/c1/61e712eeeed8ee01b1ff1c0904c63f63f395371ae0f5559da98eae36eabf/Tyf-1.2.4-py2.py3-none-any.whl" } ], "1.3.0": [ { "comment_text": "", "digests": { "md5": "05b55b3374a5a5171b642b6521ed61a1", "sha256": "840b7ee836c9cf0f2a6ba857c1385da42a1a1a9a982933f5b2dae86c9e1291ce" }, "downloads": -1, "filename": "Tyf-1.3.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "05b55b3374a5a5171b642b6521ed61a1", "packagetype": "bdist_wheel", "python_version": "2.7", "requires_python": null, "size": 85389, "upload_time": "2016-11-25T19:22:15", "url": "https://files.pythonhosted.org/packages/bb/2d/0e297c592093876db48fe920921a305d106a477c88ce4644b02e04c757ca/Tyf-1.3.0-py2.py3-none-any.whl" } ], "1.3.1": [ { "comment_text": "", "digests": { "md5": "af32574448d2928bd769c43a6a3239d4", "sha256": "28674326ad7aab45cd69b5310e0d12a193e76a4757ed20b80857dc9ab07fd2b0" }, "downloads": -1, "filename": "Tyf-1.3.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "af32574448d2928bd769c43a6a3239d4", "packagetype": "bdist_wheel", "python_version": "3.5", "requires_python": null, "size": 87353, "upload_time": "2016-11-26T10:22:18", "url": "https://files.pythonhosted.org/packages/1b/ec/5a87e548af5d0c00b65558f12609a390f266a27f515c0fe52c033639aa53/Tyf-1.3.1-py2.py3-none-any.whl" } ], "1.3.2": [ { "comment_text": "", "digests": { "md5": "a44f15e21b174921238b7ba400a9ebaa", "sha256": "e60ac8b5a667f16b700913569110032ebcf9f8474e4fbf8eec31586e99e895dc" }, "downloads": -1, "filename": "Tyf-1.3.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "a44f15e21b174921238b7ba400a9ebaa", "packagetype": "bdist_wheel", "python_version": "3.5", "requires_python": null, "size": 87962, "upload_time": "2016-12-22T14:54:43", "url": "https://files.pythonhosted.org/packages/85/17/d6ef77cff3260a8708614459e78ba2c69b1f3be4bb77d46377d5472cc27d/Tyf-1.3.2-py2.py3-none-any.whl" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "a44f15e21b174921238b7ba400a9ebaa", "sha256": "e60ac8b5a667f16b700913569110032ebcf9f8474e4fbf8eec31586e99e895dc" }, "downloads": -1, "filename": "Tyf-1.3.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "a44f15e21b174921238b7ba400a9ebaa", "packagetype": "bdist_wheel", "python_version": "3.5", "requires_python": null, "size": 87962, "upload_time": "2016-12-22T14:54:43", "url": "https://files.pythonhosted.org/packages/85/17/d6ef77cff3260a8708614459e78ba2c69b1f3be4bb77d46377d5472cc27d/Tyf-1.3.2-py2.py3-none-any.whl" } ] }