init push

This commit is contained in:
2025-12-08 05:12:14 +01:00
parent 7d42af7cfc
commit 30f5a8d6a1
8 changed files with 160 additions and 1 deletions

3
.gitignore vendored
View File

@@ -174,3 +174,6 @@ cython_debug/
# PyPI configuration file # PyPI configuration file
.pypirc .pypirc
# ...
*.ARW

1
.python-version Normal file
View File

@@ -0,0 +1 @@
3.13

View File

@@ -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
View 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
View 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
View 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
View 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

8
uv.lock generated Normal file
View File

@@ -0,0 +1,8 @@
version = 1
revision = 3
requires-python = ">=3.13"
[[package]]
name = "qifdp"
version = "0.1.0"
source = { editable = "." }