init push
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -174,3 +174,6 @@ cython_debug/
|
|||||||
# PyPI configuration file
|
# PyPI configuration file
|
||||||
.pypirc
|
.pypirc
|
||||||
|
|
||||||
|
|
||||||
|
# ...
|
||||||
|
*.ARW
|
||||||
|
|||||||
1
.python-version
Normal file
1
.python-version
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3.13
|
||||||
14
README.md
14
README.md
@@ -1,3 +1,15 @@
|
|||||||
# qifdp
|
# qifdp
|
||||||
|
|
||||||
QIFDP - Quick IFD Parser
|
QIFDP - Quick IFD Parser
|
||||||
|
|
||||||
|
Tested with:
|
||||||
|
- Sony ARW v4.0.1
|
||||||
|
|
||||||
|
# Build
|
||||||
|
|
||||||
|
If you don't already have uv installed: `pip install uv`
|
||||||
|
|
||||||
|
```
|
||||||
|
uv build
|
||||||
|
pip install dist/qifdp-0.1.0.tar.gz
|
||||||
|
```
|
||||||
19
examples/read_ifd_tags.py
Normal file
19
examples/read_ifd_tags.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
from qifdp import IFDTagMap
|
||||||
|
from qifdp import get_raw_ifd_tag
|
||||||
|
|
||||||
|
file_path = "DSC00001.ARW"
|
||||||
|
|
||||||
|
# Get the DateTimeOriginal
|
||||||
|
date = get_raw_ifd_tag(file_path=file_path)
|
||||||
|
print(date)
|
||||||
|
|
||||||
|
# Get the camera brand name
|
||||||
|
make = get_raw_ifd_tag(file_path=file_path, tag_bytes=IFDTagMap.Make)
|
||||||
|
print(make)
|
||||||
|
|
||||||
|
# If the buffer from 0x80000 (512k) inst enough for parsing the IFD tag,
|
||||||
|
# you can increase the buffer. Use either a hex value or an int.
|
||||||
|
# 0x80000 | 524288
|
||||||
|
# 0x100000 | 1048576
|
||||||
|
date = get_raw_ifd_tag(file_path=file_path, read_buffer=0x100000)
|
||||||
|
print(date)
|
||||||
32
pyproject.toml
Normal file
32
pyproject.toml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
[project]
|
||||||
|
name = "qifdp"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Add your description here"
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.13"
|
||||||
|
dependencies = []
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["setuptools", "wheel"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[tool.setuptools]
|
||||||
|
package-dir = {"" = "src"}
|
||||||
|
|
||||||
|
[tool.setuptools.packages.find]
|
||||||
|
where = ["src"]
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
name = "qidfp"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "A Python library to quickly parse IFD Tags"
|
||||||
|
long_description = "file:README.md"
|
||||||
|
long_description_content_type = "text/markdown"
|
||||||
|
author = "DasMoorhuhn"
|
||||||
|
author_email = "dasmoorhuhn@proton.me"
|
||||||
|
license = "GPLv3.0"
|
||||||
|
url = "https://github.com/yourusername/my-library"
|
||||||
|
classifiers = [
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
"Operating System :: OS Independent",
|
||||||
|
]
|
||||||
6
src/qifdp/__init__.py
Normal file
6
src/qifdp/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
"""
|
||||||
|
A quick IFD parser
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .main import get_raw_ifd_tag
|
||||||
|
from .main import IFDTagMap
|
||||||
78
src/qifdp/main.py
Normal file
78
src/qifdp/main.py
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import struct
|
||||||
|
|
||||||
|
|
||||||
|
class IFDTagMap:
|
||||||
|
# Image tags
|
||||||
|
ImageWidth = b'\x01\x00' # 0x0100
|
||||||
|
ImageLength = b'\x01\x01' # 0x0101
|
||||||
|
Make = b'\x01\x0F' # 0x010F
|
||||||
|
Model = b'\x01\x10' # 0x0110
|
||||||
|
Orientation = b'\x01\x12' # 0x0112
|
||||||
|
XResolution = b'\x01\x1A' # 0x011A
|
||||||
|
YResolution = b'\x01\x1B' # 0x011B
|
||||||
|
ResolutionUnit = b'\x01\x28' # 0x0128
|
||||||
|
Software = b'\x01\x31' # 0x0131
|
||||||
|
DateTime = b'\x01\x32' # 0x0132
|
||||||
|
Artist = b'\x01\xB0' # 0x01B0
|
||||||
|
Copyright = b'\x82\x98' # 0x8298
|
||||||
|
|
||||||
|
# Exposure tags
|
||||||
|
ExposureTime = b'\x82\x9A' # 0x829A
|
||||||
|
FNumber = b'\x82\x9D' # 0x829D
|
||||||
|
ISOSpeedRatings = b'\x88\x69' # 0x8827
|
||||||
|
ExposureBiasValue = b'\x92\x73' # 0x9273
|
||||||
|
MeteringMode = b'\x92\x7C' # 0x927C
|
||||||
|
Flash = b'\x92\x19' # 0x9209
|
||||||
|
FocalLength = b'\x92\x26' # 0x920A
|
||||||
|
|
||||||
|
# Date/Time tags
|
||||||
|
DateTimeOriginal = b'\x90\x03' # 0x9003
|
||||||
|
DateTimeDigitized = b'\x90\x04' # 0x9004
|
||||||
|
SubsecTime = b'\x92\x00' # 0x9200
|
||||||
|
SubsecTimeOriginal = b'\x92\x01' # 0x9201
|
||||||
|
SubsecTimeDigitized = b'\x92\x02' # 0x9202
|
||||||
|
|
||||||
|
# Image dimensions and color
|
||||||
|
ColorSpace = b'\xA0\x13' # 0xA001
|
||||||
|
PixelXDimension = b'\xA0\x02' # 0xA002
|
||||||
|
PixelYDimension = b'\xA0\x03' # 0xA003
|
||||||
|
|
||||||
|
# Camera-specific / MakerNote
|
||||||
|
CameraOwnerName = b'\xC6\x0E' # 0xC60E
|
||||||
|
|
||||||
|
|
||||||
|
def get_raw_ifd_tag(file_path:str, read_buffer:int=0x80000, tag_bytes:bytes=IFDTagMap.DateTimeOriginal) -> str:
|
||||||
|
with open(file_path, "rb") as f:
|
||||||
|
f.seek(0, 2)
|
||||||
|
size_bytes = f.tell()
|
||||||
|
read_buffer = min(read_buffer, size_bytes)
|
||||||
|
f.seek(0)
|
||||||
|
data = f.read(read_buffer)
|
||||||
|
|
||||||
|
# Try first LE then BE
|
||||||
|
offset = data.find(tag_bytes[::-1])
|
||||||
|
endian = "<"
|
||||||
|
if offset == -1:
|
||||||
|
offset = data.find(tag_bytes)
|
||||||
|
endian = ">"
|
||||||
|
|
||||||
|
if offset == -1:
|
||||||
|
raise ValueError("Tag 0x9003 not found in the file.")
|
||||||
|
|
||||||
|
# Read type and count
|
||||||
|
type_, count = struct.unpack(endian + "HI", data[offset+2:offset+8])
|
||||||
|
|
||||||
|
# Read value/offset
|
||||||
|
value_or_offset = struct.unpack(endian + "I", data[offset+8:offset+12])[0]
|
||||||
|
|
||||||
|
# If ASCII and count > 4, value_or_offset is the file offset of the string
|
||||||
|
if type_ == 2 and count > 4:
|
||||||
|
value_offset = value_or_offset
|
||||||
|
value_bytes = data[value_offset:value_offset+count]
|
||||||
|
value = value_bytes.decode('ascii')
|
||||||
|
else:
|
||||||
|
# Small values stored inline
|
||||||
|
value_bytes = data[offset+8:offset+8+count]
|
||||||
|
value = value_bytes.decode('ascii')
|
||||||
|
|
||||||
|
return value
|
||||||
Reference in New Issue
Block a user