CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-python-xmp-toolkit

Python library for working with XMP (Extensible Metadata Platform) metadata in files.

Pending
Overview
Eval results
Files

file-operations.mddocs/

File Operations

The XMPFiles class provides convenient access to XMP metadata in files with smart handlers for various file formats. It manages file opening, XMP extraction, modification, and writing back to files.

Capabilities

XMPFiles Class

API for accessing main metadata in files with smart file handlers.

class XMPFiles:
    def __init__(self, **kwargs):
        """
        Create XMPFiles instance.
        
        Parameters:
        - file_path (optional): str, path to file to open
        """

File Operations

def open_file(self, file_path, **kwargs):
    """
    Open file and read XMP metadata.
    
    Parameters:
    - file_path: str, path to file
    - **kwargs: optional keyword arguments from XMP_OPEN_OPTIONS
    
    Raises:
    XMPError: if file already open or operation fails
    """

def close_file(self, close_flags=0):
    """
    Close file and write XMP changes.
    
    Parameters:
    - close_flags: int, optional close flags from XMP_CLOSE_OPTIONS
                  (default: XMP_CLOSE_NOOPTION)
    """

Metadata Access

def get_xmp(self):
    """
    Get XMP metadata from file.
    
    Returns:
    XMPMeta: New XMPMeta instance with file's XMP data, or None if no XMP
    
    Raises:
    XMPError: on failure
    """

def put_xmp(self, xmp_obj):
    """
    Write XMP metadata to file.
    
    Parameters:
    - xmp_obj: XMPMeta instance with XMP data to write
    
    Raises:
    XMPError: on failure
    """

def can_put_xmp(self, xmp_obj):
    """
    Check if XMP can be written to file.
    
    Parameters:
    - xmp_obj: XMPMeta instance
    
    Returns:
    bool: True if XMP can be written to file
    """

File Format Support

The XMPFiles class includes smart handlers for various file formats:

  • Image formats: JPEG, TIFF, PNG, GIF, WebP
  • Document formats: PDF, PostScript, EPS
  • RAW formats: Camera RAW files (via Adobe Camera Raw)
  • Video formats: Various multimedia formats
  • Generic: Packet scanning fallback for unknown formats

Open Options

Available options for open_file() method from libxmp.consts:

XMP_OPEN_NOOPTION = 0x00000000       # No special options
XMP_OPEN_READ = 0x00000001           # Open for read-only access
XMP_OPEN_FORUPDATE = 0x00000002      # Open for read-write access
XMP_OPEN_ONLYXMP = 0x00000004        # Only process XMP, ignore other metadata
XMP_OPEN_CACHETNAIL = 0x00000008     # Cache thumbnail if present
XMP_OPEN_STRICTLY = 0x00000010       # Strict conformance checking
XMP_OPEN_USESMARTHANDLER = 0x00000020    # Use smart handlers
XMP_OPEN_USEPACKETSCANNING = 0x00000040  # Use packet scanning fallback
XMP_OPEN_LIMITSCANNING = 0x00000080      # Limit packet scanning
XMP_OPEN_INBACKGROUND = 0x10000000       # Set if calling from background thread

Close Options

Available options for close_file() method:

XMP_CLOSE_NOOPTION = 0x0000      # No special options
XMP_CLOSE_SAFEUPDATE = 0x0001    # Write XMP into safe temp file first

Usage Examples

Basic File Operations

from libxmp import XMPFiles, XMPMeta, XMPError

# Open file and read XMP
try:
    xmpfile = XMPFiles(file_path="photo.jpg")
    xmp_data = xmpfile.get_xmp()
    
    if xmp_data:
        # Read existing metadata
        creator = xmp_data.get_property("http://purl.org/dc/elements/1.1/", "creator")
        print(f"Original creator: {creator}")
        
        # Modify metadata
        xmp_data.set_property("http://purl.org/dc/elements/1.1/", "creator", "Updated Creator")
        xmp_data.set_property("http://ns.adobe.com/xap/1.0/", "CreatorTool", "Python XMP Toolkit")
        
        # Write back to file
        xmpfile.put_xmp(xmp_data)
    else:
        print("No XMP metadata found in file")
    
    # Close file (writes changes)
    xmpfile.close_file()
    
except XMPError as e:
    print(f"XMP error: {e}")

Working with Different File Types

from libxmp import XMPFiles, XMPMeta
from libxmp.consts import XMP_OPEN_FORUPDATE, XMP_CLOSE_SAFEUPDATE

# Process multiple file types
file_paths = ["document.pdf", "image.tiff", "photo.jpg"]

for file_path in file_paths:
    try:
        # Open with specific options
        xmpfile = XMPFiles()
        xmpfile.open_file(file_path, open_forupdate=True)
        
        xmp_data = xmpfile.get_xmp()
        if not xmp_data:
            # Create new XMP if none exists
            xmp_data = XMPMeta()
        
        # Add processing timestamp
        from datetime import datetime
        xmp_data.set_property_datetime(
            "http://ns.adobe.com/xap/1.0/", 
            "ModifyDate", 
            datetime.now()
        )
        
        # Check if we can write XMP to this file type
        if xmpfile.can_put_xmp(xmp_data):
            xmpfile.put_xmp(xmp_data)
            print(f"Updated XMP in {file_path}")
        else:
            print(f"Cannot write XMP to {file_path}")
        
        # Close with safe update
        xmpfile.close_file(close_flags=XMP_CLOSE_SAFEUPDATE)
        
    except Exception as e:
        print(f"Error processing {file_path}: {e}")

Advanced File Handling

from libxmp import XMPFiles, XMPMeta
from libxmp.consts import *

def process_file_metadata(file_path, metadata_updates):
    """
    Process file metadata with comprehensive error handling.
    
    Args:
        file_path: Path to file
        metadata_updates: Dict of namespace -> {property: value} mappings
    """
    xmpfile = None
    try:
        # Open file with comprehensive options
        xmpfile = XMPFiles()
        xmpfile.open_file(
            file_path,
            open_forupdate=True,
            open_usesmarthandler=True,
            open_usepacketscanning=True
        )
        
        # Get existing XMP or create new
        xmp_data = xmpfile.get_xmp()
        if not xmp_data:
            xmp_data = XMPMeta()
        
        # Apply metadata updates
        for namespace, properties in metadata_updates.items():
            for prop_name, prop_value in properties.items():
                if isinstance(prop_value, list):
                    # Handle arrays
                    for item in prop_value:
                        xmp_data.append_array_item(namespace, prop_name, item)
                else:
                    # Handle simple properties
                    xmp_data.set_property(namespace, prop_name, prop_value)
        
        # Verify we can write before attempting
        if xmpfile.can_put_xmp(xmp_data):
            xmpfile.put_xmp(xmp_data)
            return True
        else:
            print(f"Cannot write XMP to {file_path}")
            return False
            
    except Exception as e:
        print(f"Error processing {file_path}: {e}")
        return False
    
    finally:
        if xmpfile:
            try:
                xmpfile.close_file(close_flags=XMP_CLOSE_SAFEUPDATE)
            except:
                pass  # Ignore close errors after main operation failure

# Usage
updates = {
    "http://purl.org/dc/elements/1.1/": {
        "creator": "John Doe",
        "subject": ["photography", "landscape", "nature"]
    },
    "http://ns.adobe.com/xap/1.0/": {
        "CreatorTool": "Python XMP Toolkit"
    }
}

success = process_file_metadata("photo.jpg", updates)
if success:
    print("Metadata updated successfully")

Error Handling

Common XMP file operation errors and handling:

from libxmp import XMPFiles, XMPError, ExempiLoadError

try:
    xmpfile = XMPFiles(file_path="example.jpg")
    xmp_data = xmpfile.get_xmp()
    # ... work with XMP data
    
except ExempiLoadError:
    print("Exempi library could not be loaded - check installation")
    
except XMPError as e:
    if "Permission denied" in str(e):
        print("File access denied - check file permissions")
    elif "No such file" in str(e):
        print("File not found - check file path")
    else:
        print(f"XMP operation failed: {e}")
        
except IOError as e:
    print(f"File I/O error: {e}")
    
finally:
    # Always close file if opened
    if 'xmpfile' in locals():
        try:
            xmpfile.close_file()
        except:
            pass  # Ignore close errors

Install with Tessl CLI

npx tessl i tessl/pypi-python-xmp-toolkit

docs

core-metadata.md

file-operations.md

index.md

utilities.md

tile.json