Tyf


Foreword

The main goal of this package is to provide pythonic way to read and edit EXIF data from JPEG file.

>>> import Tyf
>>> jpg = Tyf.open("a_file.jpg")
>>> jpg.ifd0.gps["GPSLatitude"]
51.1597896
>>> jpg.ifd0.gps["GPSLatitude"] = 45.3265487
>>> jpg.save("another_file.jpg")

Where are EXIF in JPEG file ?

Googling « Exif file format » you can find any pages that explain how JPEG file is build :

SOI MarkerMarker XX
size=SSSS
Marker YY
size=TTTT
SOS Marker
size=UUUU
Image streamEOI Marker
FFD8FFXXSSSSDDDD…FFYYTTTTDDDD…FFDAUUUUDDDD…IIII…FFD9

EXIF informations are contained in APP1 segment of JPEG File (marker number E1) :

FFE1APP1 Marker
SSSSAPP1 Data Size
45786966 0000APP1 DataExif Header → b"Exif\x00\x00"
49492A00 08000000TIFF Header
XXXX…IFD0 (main image)Directory
LLLLLLLLLink to IFD1
XXXX…Data area of IFD0
XXXX…Exif SubIFDDirectory
00000000End of Link
XXXX…Data area of Exif SubIFD
XXXX…IFD1 (thumbnail image)Directory
00000000End of Link
XXXX…Data area of IFD1
FFD8XXXX…XXXXFFD9Thumbnail image

EXIF is actualy a Sub Image File Directory (SubIFD) contained in a TIFF IFD. So once EXIF data extracted from JPEG file we have to deal with data[6:] (striped from Exif Header) as a TIFF (Tagged Image File Format) file. The idea here is to base Tyf package on TIFF Tag and Ifd classes implementing TIFF specification. Tyf has to be able to read and edit TIFF tags…

Main idea

Firstly, as end-up user, I only want to assign a value to a tag name or to get value from a tag name. It is easily associatd to well known dictionary Python built-in type. It is the mean reason why Tyf.ifd.Ifd class is an implementation of dict object.

Secondly, tag values can be tricky to understand. For example, GPS longitude is a set of 6 integers that have to be interpreted as three rationals for degrees, minutes and seconds. It means that code has to provide encoders and decoders according to IFD entries type or tag. They are defined in Tyf.encoders and Tyf.decoders.

>>> enc = getattr(Tyf.encoders, "_0x2") # 0x2 for GPSLongitude
>>> enc(5.3212315165454)
(5, 1, 19, 1, 25842026, 1572525)
>>> enc = getattr(Tyf.encoders, "_0x1") # 0x1 for GPSLongitudeRef
>>> enc(5.3212315165454) # should return the north hemisphere value
b'N\x00'

To keep a maximum flexibility with my code, I wish to have a « human » and a « raw » way to read or write values in IFD :

Finaly I want the Tyf.ifd.Tag class to be end user friendly. A TIFF IFD is a collection of entries each one defining a tag with 4 entities : id number, type data, count of data and data itself. Tag id are integers and for each tag id is associated a type and sometime a default value. So Tyf.ifd.Tag class should know about those values when I instanciate it with nothing but a keyword.

>>> tag = Tyf.ifd.Tag("ReferenceBlackWhite")
>>> tag.value
(0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1)
>>> tag.tag
532
>>> tag.type
5
>>> tag.count
24

A Tyf.tags module containing a database of all tag should do the work. See this page for more informations.