Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "c2pa-python"
version = "0.16.0"
version = "0.17.0"
requires-python = ">=3.10"
description = "Python bindings for the C2PA Content Authenticity Initiative (CAI) library"
readme = { file = "README.md", content-type = "text/markdown" }
Expand Down
50 changes: 38 additions & 12 deletions src/c2pa/c2pa.py
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,33 @@ def load_settings(settings: str, format: str = "json") -> None:
return result


def _get_mime_type_from_path(path: Union[str, Path]) -> str:
"""Attempt to guess the MIME type from a file path (with extension).

Args:
path: File path as string or Path object

Returns:
MIME type string

Raises:
C2paError.NotSupported: If MIME type cannot be determined
"""
path_obj = Path(path)
file_extension = path_obj.suffix.lower() if path_obj.suffix else ""

if file_extension == ".dng":
# mimetypes guesses the wrong type for dng,
# so we bypass it and set the correct type
return "image/dng"
else:
mime_type = mimetypes.guess_type(str(path))[0]
if not mime_type:
raise C2paError.NotSupported(
f"Could not determine MIME type for file: {path}")
return mime_type


def read_ingredient_file(
path: Union[str, Path], data_dir: Union[str, Path]) -> str:
"""Read a file as C2PA ingredient.
Expand Down Expand Up @@ -1214,7 +1241,11 @@ def __init__(self,
"""Create a new Reader.

Args:
format_or_path: The format or path to read from
format_or_path: The format or path to read from.
The stream API (params format and an open stream) is
the recommended way to use the Reader. For paths, we
will attempt to guess the mimetype of the source
file based on the extension.
stream: Optional stream to read from (Python stream-like object)
manifest_data: Optional manifest data in bytes

Expand All @@ -1231,12 +1262,8 @@ def __init__(self,
# If we don't get a stream as param:
# Create a stream from the file path in format_or_path
path = str(format_or_path)
mime_type = mimetypes.guess_type(
path)[0]

if not mime_type:
raise C2paError.NotSupported(
f"Could not determine MIME type for file: {path}")
mime_type = _get_mime_type_from_path(path)

if mime_type not in Reader.get_supported_mime_types():
raise C2paError.NotSupported(
Expand Down Expand Up @@ -2269,7 +2296,9 @@ def sign_file(self,
"""Sign a file and write the signed data to an output file.

Args:
source_path: Path to the source file
source_path: Path to the source file. We will attempt
to guess the mimetype of the source file based on
the extension.
dest_path: Path to write the signed file to
signer: The signer to use

Expand All @@ -2279,11 +2308,8 @@ def sign_file(self,
Raises:
C2paError: If there was an error during signing
"""
# Get the MIME type from the file extension
mime_type = mimetypes.guess_type(str(source_path))[0]
if not mime_type:
raise C2paError.NotSupported(
f"Could not determine MIME type for file: {source_path}")

mime_type = _get_mime_type_from_path(source_path)

try:
# Open source file and destination file, then use the sign method
Expand Down
Binary file added tests/fixtures/C.dng
Binary file not shown.
20 changes: 17 additions & 3 deletions tests/test_unit_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,6 @@ def test_reader_streams_with_nested(self):
def test_reader_close_cleanup(self):
with open(self.testPath, "rb") as file:
reader = Reader("image/jpeg", file)
# Store references to internal objects
Comment thread
tmathern marked this conversation as resolved.
reader_ref = reader._reader
stream_ref = reader._own_stream
# Close the reader
reader.close()
# Verify all resources are cleaned up
Expand All @@ -144,6 +141,23 @@ def test_resource_to_stream_on_closed_reader(self):
with self.assertRaises(Error):
reader.resource_to_stream("", io.BytesIO(bytearray()))

def test_read_dng_from_stream(self):
test_path = os.path.join(self.data_dir, "C.dng")
with open(test_path, "rb") as file:
file_content = file.read()

with Reader("dng", io.BytesIO(file_content)) as reader:
# Just run and verify there is no crash
json.loads(reader.json())

def test_read_dng_file_from_path(self):
test_path = os.path.join(self.data_dir, "C.dng")

# Create reader with the file content
with Reader(test_path) as reader:
# Just run and verify there is no crash
json.loads(reader.json())

def test_read_all_files(self):
"""Test reading C2PA metadata from all files in the fixtures/files-for-reading-tests directory"""
reading_dir = os.path.join(self.data_dir, "files-for-reading-tests")
Expand Down
Loading