Skip to content

Commit fbf93bc

Browse files
authored
fix: DNG handling when reading data from filepath directly (#151)
* fix: DNG handling * fix: Clarify docs * fix: Clarify docs 2 * fix: Refactor * fix: Bump version
1 parent ac43887 commit fbf93bc

File tree

4 files changed

+56
-16
lines changed

4 files changed

+56
-16
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "c2pa-python"
7-
version = "0.16.0"
7+
version = "0.17.0"
88
requires-python = ">=3.10"
99
description = "Python bindings for the C2PA Content Authenticity Initiative (CAI) library"
1010
readme = { file = "README.md", content-type = "text/markdown" }

src/c2pa/c2pa.py

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,33 @@ def load_settings(settings: str, format: str = "json") -> None:
654654
return result
655655

656656

657+
def _get_mime_type_from_path(path: Union[str, Path]) -> str:
658+
"""Attempt to guess the MIME type from a file path (with extension).
659+
660+
Args:
661+
path: File path as string or Path object
662+
663+
Returns:
664+
MIME type string
665+
666+
Raises:
667+
C2paError.NotSupported: If MIME type cannot be determined
668+
"""
669+
path_obj = Path(path)
670+
file_extension = path_obj.suffix.lower() if path_obj.suffix else ""
671+
672+
if file_extension == ".dng":
673+
# mimetypes guesses the wrong type for dng,
674+
# so we bypass it and set the correct type
675+
return "image/dng"
676+
else:
677+
mime_type = mimetypes.guess_type(str(path))[0]
678+
if not mime_type:
679+
raise C2paError.NotSupported(
680+
f"Could not determine MIME type for file: {path}")
681+
return mime_type
682+
683+
657684
def read_ingredient_file(
658685
path: Union[str, Path], data_dir: Union[str, Path]) -> str:
659686
"""Read a file as C2PA ingredient.
@@ -1214,7 +1241,11 @@ def __init__(self,
12141241
"""Create a new Reader.
12151242
12161243
Args:
1217-
format_or_path: The format or path to read from
1244+
format_or_path: The format or path to read from.
1245+
The stream API (params format and an open stream) is
1246+
the recommended way to use the Reader. For paths, we
1247+
will attempt to guess the mimetype of the source
1248+
file based on the extension.
12181249
stream: Optional stream to read from (Python stream-like object)
12191250
manifest_data: Optional manifest data in bytes
12201251
@@ -1231,12 +1262,8 @@ def __init__(self,
12311262
# If we don't get a stream as param:
12321263
# Create a stream from the file path in format_or_path
12331264
path = str(format_or_path)
1234-
mime_type = mimetypes.guess_type(
1235-
path)[0]
12361265

1237-
if not mime_type:
1238-
raise C2paError.NotSupported(
1239-
f"Could not determine MIME type for file: {path}")
1266+
mime_type = _get_mime_type_from_path(path)
12401267

12411268
if mime_type not in Reader.get_supported_mime_types():
12421269
raise C2paError.NotSupported(
@@ -2269,7 +2296,9 @@ def sign_file(self,
22692296
"""Sign a file and write the signed data to an output file.
22702297
22712298
Args:
2272-
source_path: Path to the source file
2299+
source_path: Path to the source file. We will attempt
2300+
to guess the mimetype of the source file based on
2301+
the extension.
22732302
dest_path: Path to write the signed file to
22742303
signer: The signer to use
22752304
@@ -2279,11 +2308,8 @@ def sign_file(self,
22792308
Raises:
22802309
C2paError: If there was an error during signing
22812310
"""
2282-
# Get the MIME type from the file extension
2283-
mime_type = mimetypes.guess_type(str(source_path))[0]
2284-
if not mime_type:
2285-
raise C2paError.NotSupported(
2286-
f"Could not determine MIME type for file: {source_path}")
2311+
2312+
mime_type = _get_mime_type_from_path(source_path)
22872313

22882314
try:
22892315
# Open source file and destination file, then use the sign method

tests/fixtures/C.dng

162 KB
Binary file not shown.

tests/test_unit_tests.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,6 @@ def test_reader_streams_with_nested(self):
126126
def test_reader_close_cleanup(self):
127127
with open(self.testPath, "rb") as file:
128128
reader = Reader("image/jpeg", file)
129-
# Store references to internal objects
130-
reader_ref = reader._reader
131-
stream_ref = reader._own_stream
132129
# Close the reader
133130
reader.close()
134131
# Verify all resources are cleaned up
@@ -144,6 +141,23 @@ def test_resource_to_stream_on_closed_reader(self):
144141
with self.assertRaises(Error):
145142
reader.resource_to_stream("", io.BytesIO(bytearray()))
146143

144+
def test_read_dng_from_stream(self):
145+
test_path = os.path.join(self.data_dir, "C.dng")
146+
with open(test_path, "rb") as file:
147+
file_content = file.read()
148+
149+
with Reader("dng", io.BytesIO(file_content)) as reader:
150+
# Just run and verify there is no crash
151+
json.loads(reader.json())
152+
153+
def test_read_dng_file_from_path(self):
154+
test_path = os.path.join(self.data_dir, "C.dng")
155+
156+
# Create reader with the file content
157+
with Reader(test_path) as reader:
158+
# Just run and verify there is no crash
159+
json.loads(reader.json())
160+
147161
def test_read_all_files(self):
148162
"""Test reading C2PA metadata from all files in the fixtures/files-for-reading-tests directory"""
149163
reading_dir = os.path.join(self.data_dir, "files-for-reading-tests")

0 commit comments

Comments
 (0)