parse LE/BE indicator bytes
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -177,3 +177,4 @@ cython_debug/
|
|||||||
|
|
||||||
# ...
|
# ...
|
||||||
*.ARW
|
*.ARW
|
||||||
|
*.JPG
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
QIFDP - Quick IFD Parser
|
QIFDP - Quick IFD Parser
|
||||||
|
|
||||||
Tested with:
|
Instead of parsing and processing the whole IFD sections, this lib will only search for a given IFD tag and only parses this one tag, in order to save alot of time. The intention behind this are python programs, which process a lot of images where any improvenent time-wise counts.
|
||||||
- Sony ARW v4.0.1
|
|
||||||
|
# Tested formats
|
||||||
|
- Sony ARW v4.01
|
||||||
|
|
||||||
# Build
|
# Build
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ date = get_raw_ifd_tag(file_path=file_path)
|
|||||||
print(date)
|
print(date)
|
||||||
|
|
||||||
# Get the camera brand name
|
# Get the camera brand name
|
||||||
make = get_raw_ifd_tag(file_path=file_path, tag_bytes=IFDTagMap.Make)
|
make = get_raw_ifd_tag(file_path=file_path, ifd_tag=IFDTagMap.Make)
|
||||||
print(make)
|
print(make)
|
||||||
|
|
||||||
# If the buffer from 0x80000 (512k) inst enough for parsing the IFD tag,
|
# If the buffer from 0x80000 (512k) inst enough for parsing the IFD tag,
|
||||||
@@ -16,4 +16,4 @@ print(make)
|
|||||||
# 0x80000 | 524288
|
# 0x80000 | 524288
|
||||||
# 0x100000 | 1048576
|
# 0x100000 | 1048576
|
||||||
date = get_raw_ifd_tag(file_path=file_path, read_buffer=0x100000)
|
date = get_raw_ifd_tag(file_path=file_path, read_buffer=0x100000)
|
||||||
print(date)
|
print(date)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "qifdp"
|
name = "qifdp"
|
||||||
version = "0.1.0"
|
version = "25.12.9"
|
||||||
description = "Add your description here"
|
description = "A Python library to quickly parse IFD Tags"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
dependencies = []
|
dependencies = []
|
||||||
@@ -15,18 +15,3 @@ package-dir = {"" = "src"}
|
|||||||
|
|
||||||
[tool.setuptools.packages.find]
|
[tool.setuptools.packages.find]
|
||||||
where = ["src"]
|
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",
|
|
||||||
]
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import struct
|
import struct
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
|
|
||||||
class IFDTagMap:
|
class IFDTagMap:
|
||||||
@@ -41,7 +42,24 @@ class IFDTagMap:
|
|||||||
CameraOwnerName = b'\xC6\x0E' # 0xC60E
|
CameraOwnerName = b'\xC6\x0E' # 0xC60E
|
||||||
|
|
||||||
|
|
||||||
def get_raw_ifd_tag(file_path:str, read_buffer:int=0x80000, tag_bytes:bytes=IFDTagMap.DateTimeOriginal) -> str:
|
def check_for_endian(data: bytes) -> Tuple[int, int]|None:
|
||||||
|
header = struct.unpack(">H", data[:2])[0]
|
||||||
|
offset = 0
|
||||||
|
# Check for JPEG Header. If present, go to TIFF.
|
||||||
|
if header == 0xFFD8:
|
||||||
|
raise ValueError("JPEG not supported yet.")
|
||||||
|
header = struct.unpack_from(">H", data, 12)[0]
|
||||||
|
offset = 12
|
||||||
|
|
||||||
|
if header == 0x4949: # "II" LE
|
||||||
|
return 1, offset
|
||||||
|
if header == 0x4D4D: # "MM" BE
|
||||||
|
return 2, offset
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_raw_ifd_tag(file_path:str, read_buffer:int=0x80000, ifd_tag:bytes=IFDTagMap.DateTimeOriginal) -> str:
|
||||||
with open(file_path, "rb") as f:
|
with open(file_path, "rb") as f:
|
||||||
f.seek(0, 2)
|
f.seek(0, 2)
|
||||||
size_bytes = f.tell()
|
size_bytes = f.tell()
|
||||||
@@ -49,15 +67,19 @@ def get_raw_ifd_tag(file_path:str, read_buffer:int=0x80000, tag_bytes:bytes=IFDT
|
|||||||
f.seek(0)
|
f.seek(0)
|
||||||
data = f.read(read_buffer)
|
data = f.read(read_buffer)
|
||||||
|
|
||||||
# Try first LE then BE
|
# Parse header to check if IFD Tags are LE or BE
|
||||||
offset = data.find(tag_bytes[::-1])
|
endian, tiff_offset = check_for_endian(data)
|
||||||
endian = "<"
|
if endian == 1:
|
||||||
if offset == -1:
|
endian = "<"
|
||||||
offset = data.find(tag_bytes)
|
ifd_tag = ifd_tag[::-1]
|
||||||
endian = ">"
|
elif endian == 2:
|
||||||
|
endian = ">"
|
||||||
|
else: return
|
||||||
|
|
||||||
|
offset = data[tiff_offset:].find(ifd_tag)
|
||||||
|
|
||||||
if offset == -1:
|
if offset == -1:
|
||||||
raise ValueError("Tag 0x9003 not found in the file.")
|
raise ValueError(f"Tag {hex(ifd_tag)} not found in the file.")
|
||||||
|
|
||||||
# Read type and count
|
# Read type and count
|
||||||
type_, count = struct.unpack(endian + "HI", data[offset+2:offset+8])
|
type_, count = struct.unpack(endian + "HI", data[offset+2:offset+8])
|
||||||
@@ -66,13 +88,8 @@ def get_raw_ifd_tag(file_path:str, read_buffer:int=0x80000, tag_bytes:bytes=IFDT
|
|||||||
value_or_offset = struct.unpack(endian + "I", data[offset+8:offset+12])[0]
|
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 ASCII and count > 4, value_or_offset is the file offset of the string
|
||||||
|
# print(hex(offset))
|
||||||
if type_ == 2 and count > 4:
|
if type_ == 2 and count > 4:
|
||||||
value_offset = value_or_offset
|
return data[value_or_offset:value_or_offset+count].decode('ascii')
|
||||||
value_bytes = data[value_offset:value_offset+count]
|
|
||||||
value = value_bytes.decode('ascii')
|
|
||||||
else:
|
else:
|
||||||
# Small values stored inline
|
return data[offset+8:offset+8+count].decode('ascii')
|
||||||
value_bytes = data[offset+8:offset+8+count]
|
|
||||||
value = value_bytes.decode('ascii')
|
|
||||||
|
|
||||||
return value
|
|
||||||
|
|||||||
Reference in New Issue
Block a user