CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pyvips

Python binding for the libvips image processing library with high-performance streaming architecture

Pending
Overview
Eval results
Files

properties-metadata.mddocs/

Properties and Metadata

Access and manipulation of image properties, metadata, and introspection capabilities for understanding image characteristics and processing pipelines. PyVips provides comprehensive metadata support including EXIF, IPTC, XMP, ICC profiles, and custom properties.

Capabilities

Basic Image Properties

Access fundamental image characteristics that define the image structure.

# Core dimensions
@property
def width(self) -> int:
    """Image width in pixels."""

@property  
def height(self) -> int:
    """Image height in pixels."""

@property
def bands(self) -> int:
    """Number of bands (channels) in the image."""

# Format and interpretation
@property
def format(self) -> str:
    """
    Pixel format.
    Values: 'uchar', 'char', 'ushort', 'short', 'uint', 'int', 
            'float', 'complex', 'double', 'dpcomplex'
    """

@property
def interpretation(self) -> str:
    """
    Color space interpretation.
    Values: 'multiband', 'b-w', 'histogram', 'xyz', 'lab', 'cmyk', 
            'rgb', 'srgb', 'yxy', 'fourier', 'rgb16', 'grey16', etc.
    """

@property
def coding(self) -> str:
    """
    Pixel coding method.
    Values: 'none', 'labq', 'rad'
    """

# Resolution information
@property
def xres(self) -> float:
    """Horizontal resolution in pixels per unit."""

@property
def yres(self) -> float:
    """Vertical resolution in pixels per unit."""

@property  
def xoffset(self) -> int:
    """Horizontal offset."""

@property
def yoffset(self) -> int:
    """Vertical offset."""

Example usage:

# Basic image info
print(f"Dimensions: {image.width} x {image.height}")
print(f"Bands: {image.bands}")
print(f"Format: {image.format}")
print(f"Color space: {image.interpretation}")
print(f"Resolution: {image.xres} x {image.yres}")

# Check image characteristics
if image.bands == 1:
    print("Grayscale image")
elif image.bands == 3:
    print("RGB image")
elif image.bands == 4:
    print("RGBA image")

# Format information
if image.format in ['uchar', 'char']:
    print("8-bit image")
elif image.format in ['ushort', 'short']:
    print("16-bit image")
elif image.format == 'float':
    print("32-bit float image")

Property Access Methods

Generic methods for getting and setting image properties and metadata.

def get(self, name: str):
    """
    Get property value.
    
    Parameters:
    - name: str, property name
    
    Returns:
    Property value (type varies by property)
    """

def set(self, name: str, value) -> None:
    """
    Set property value.
    
    Parameters:
    - name: str, property name  
    - value: property value (type varies)
    
    Returns:
    None (modifies image metadata)
    """

def get_fields(self) -> list:
    """
    Get list of all property names.
    
    Returns:
    List of property name strings
    """

def remove(self, name: str) -> None:
    """
    Remove property.
    
    Parameters:
    - name: str, property name to remove
    
    Returns:
    None (modifies image metadata)
    """

def get_typeof(self, name: str) -> str:
    """
    Get property type.
    
    Parameters:
    - name: str, property name
    
    Returns:
    str, GType name for the property
    """

def set_type(self, gtype: int, name: str, value) -> None:
    """
    Set property with explicit type.
    
    Parameters:
    - gtype: int, GType for the property
    - name: str, property name
    - value: property value
    
    Returns:
    None (modifies image metadata)
    """

Example usage:

# List all properties
fields = image.get_fields()
print(f"Available properties: {len(fields)}")
for field in fields[:10]:  # Show first 10
    print(f"  {field}: {image.get(field)}")

# Get specific properties
try:
    orientation = image.get('orientation')
    print(f"Image orientation: {orientation}")
except:
    print("No orientation metadata")

# Set custom metadata
image_copy = image.copy()
image_copy.set('custom-property', 'my value')
image_copy.set('processing-date', '2024-01-15')

# Remove metadata
image_copy.remove('exif-ifd0-Orientation')

# Check property types
if 'xres' in image.get_fields():
    prop_type = image.get_typeof('xres')
    print(f"xres type: {prop_type}")

EXIF Metadata

Access and manipulate EXIF (Exchangeable Image File Format) metadata commonly found in digital photos.

# Common EXIF properties (examples)
# Camera information
'exif-ifd0-Make'              # Camera manufacturer
'exif-ifd0-Model'             # Camera model
'exif-ifd0-Software'          # Software used
'exif-ifd0-DateTime'          # File modification date
'exif-ifd0-Orientation'       # Image orientation (1-8)

# Photo settings
'exif-exif-ExposureTime'      # Shutter speed
'exif-exif-FNumber'           # Aperture (f-stop)
'exif-exif-ISO'               # ISO sensitivity
'exif-exif-FocalLength'       # Focal length
'exif-exif-Flash'             # Flash settings
'exif-exif-WhiteBalance'      # White balance setting

# GPS information
'exif-gps-GPSLatitude'        # Latitude
'exif-gps-GPSLongitude'       # Longitude
'exif-gps-GPSAltitude'        # Altitude
'exif-gps-GPSTimeStamp'       # GPS timestamp

Example usage:

# Read EXIF data
def get_camera_info(image):
    camera_info = {}
    try:
        camera_info['make'] = image.get('exif-ifd0-Make')
        camera_info['model'] = image.get('exif-ifd0-Model')
        camera_info['datetime'] = image.get('exif-ifd0-DateTime')
        camera_info['orientation'] = image.get('exif-ifd0-Orientation')
    except:
        pass  # Property not available
    return camera_info

def get_photo_settings(image):
    settings = {}
    try:
        settings['exposure'] = image.get('exif-exif-ExposureTime')
        settings['aperture'] = image.get('exif-exif-FNumber')
        settings['iso'] = image.get('exif-exif-ISO')
        settings['focal_length'] = image.get('exif-exif-FocalLength')
    except:
        pass
    return settings

# Use EXIF data
camera = get_camera_info(image)
if camera:
    print(f"Camera: {camera.get('make', 'Unknown')} {camera.get('model', 'Unknown')}")

# Handle orientation
orientation = image.get('exif-ifd0-Orientation') if 'exif-ifd0-Orientation' in image.get_fields() else 1
if orientation in [3, 6, 8]:  # Common rotation values
    if orientation == 3:
        image = image.rotate(180)
    elif orientation == 6:
        image = image.rotate(90)
    elif orientation == 8:
        image = image.rotate(270)

# Set EXIF data
image_copy = image.copy()
image_copy.set('exif-ifd0-Artist', 'Photographer Name')
image_copy.set('exif-ifd0-Copyright', '© 2024 My Company')
image_copy.set('exif-ifd0-Software', 'PyVips Processing')

ICC Color Profiles

Access and manipulate ICC (International Color Consortium) color profiles for accurate color management.

# ICC profile properties
'icc-profile-data'            # Raw ICC profile data (bytes)
'icc-profile-description'     # Profile description
'icc-profile-manufacturer'    # Profile manufacturer
'icc-profile-model'           # Profile model
'icc-profile-copyright'       # Profile copyright

Example usage:

# Check for ICC profile
has_profile = 'icc-profile-data' in image.get_fields()
if has_profile:
    profile_data = image.get('icc-profile-data')
    print(f"ICC profile size: {len(profile_data)} bytes")
    
    # Get profile description
    try:
        description = image.get('icc-profile-description')
        print(f"Profile: {description}")
    except:
        print("No profile description")

# Embed ICC profile
with open('srgb_profile.icc', 'rb') as f:
    profile_data = f.read()

image_with_profile = image.copy()
image_with_profile.set('icc-profile-data', profile_data)

# Remove ICC profile
image_no_profile = image.copy()
if 'icc-profile-data' in image_no_profile.get_fields():
    image_no_profile.remove('icc-profile-data')

XMP and IPTC Metadata

Access XMP (Extensible Metadata Platform) and IPTC (International Press Telecommunications Council) metadata.

# XMP properties (examples)
'xmp-dc-title'                # Title
'xmp-dc-description'          # Description  
'xmp-dc-creator'              # Creator
'xmp-dc-subject'              # Keywords/subjects
'xmp-dc-rights'               # Rights/copyright

# IPTC properties (examples)
'iptc-Application2-Caption'   # Caption/description
'iptc-Application2-Keywords'  # Keywords
'iptc-Application2-Byline'    # Photographer
'iptc-Application2-Copyright' # Copyright notice
'iptc-Application2-City'      # City
'iptc-Application2-Country'   # Country

Example usage:

# Read XMP metadata
def get_xmp_info(image):
    xmp_info = {}
    fields = image.get_fields()
    
    xmp_fields = [f for f in fields if f.startswith('xmp-')]
    for field in xmp_fields:
        try:
            xmp_info[field] = image.get(field)
        except:
            pass
    return xmp_info

# Read IPTC metadata
def get_iptc_info(image):
    iptc_info = {}
    fields = image.get_fields()
    
    iptc_fields = [f for f in fields if f.startswith('iptc-')]
    for field in iptc_fields:
        try:
            iptc_info[field] = image.get(field)
        except:
            pass
    return iptc_info

# Set metadata for web publishing
def add_web_metadata(image, title, description, keywords, author):
    web_image = image.copy()
    
    # XMP metadata
    web_image.set('xmp-dc-title', title)
    web_image.set('xmp-dc-description', description)
    web_image.set('xmp-dc-creator', author)
    web_image.set('xmp-dc-subject', keywords)
    
    # IPTC metadata
    web_image.set('iptc-Application2-Caption', description)
    web_image.set('iptc-Application2-Keywords', keywords)
    web_image.set('iptc-Application2-Byline', author)
    
    return web_image

# Use metadata functions
xmp_data = get_xmp_info(image)
if xmp_data:
    print("XMP metadata found:")
    for key, value in xmp_data.items():
        print(f"  {key}: {value}")

# Add metadata to processed image
processed = add_web_metadata(
    image, 
    "Sunset Landscape", 
    "Beautiful sunset over mountains",
    "sunset, landscape, mountains, nature",
    "John Photographer"
)

Image Scale and Offset

Access scale and offset properties used for pixel value interpretation.

def get_scale(self) -> float:
    """
    Get scale property.
    
    Returns:
    float, scale factor applied to pixel values
    """

def get_offset(self) -> float:
    """
    Get offset property.
    
    Returns:
    float, offset added to pixel values
    """

# Properties
'scale'                       # Scale factor for pixel values
'offset'                      # Offset for pixel values

Example usage:

# Check scale and offset
scale = image.get_scale()
offset = image.get_offset()
print(f"Scale: {scale}, Offset: {offset}")

# Pixel values are interpreted as: (raw_value * scale) + offset
if scale != 1.0 or offset != 0.0:
    print("Image has scale/offset transformation")

# Set scale and offset for calibrated images
calibrated = image.copy()
calibrated.set('scale', 2.5)    # Each unit represents 2.5 real units
calibrated.set('offset', -10.0) # Zero point is shifted by -10

Custom Properties

Add application-specific metadata for processing workflows and custom applications.

# Custom property naming conventions
'custom-*'                    # Application-specific properties
'processing-*'                # Processing history
'workflow-*'                  # Workflow information
'user-*'                      # User-defined properties

Example usage:

# Processing history
def add_processing_history(image, operation, parameters):
    processed = image.copy()
    
    # Add timestamp
    import datetime
    timestamp = datetime.datetime.now().isoformat()
    processed.set('processing-timestamp', timestamp)
    
    # Add operation info
    processed.set('processing-operation', operation)
    processed.set('processing-parameters', str(parameters))
    
    # Increment processing count
    try:
        count = processed.get('processing-count')
        processed.set('processing-count', count + 1)
    except:
        processed.set('processing-count', 1)
    
    return processed

# Quality assessment
def add_quality_metrics(image, sharpness, noise_level, exposure_quality):
    metrics = image.copy()
    metrics.set('quality-sharpness', sharpness)
    metrics.set('quality-noise', noise_level)
    metrics.set('quality-exposure', exposure_quality)
    return metrics

# Workflow tracking
def add_workflow_info(image, stage, version, user):
    workflow = image.copy()
    workflow.set('workflow-stage', stage)
    workflow.set('workflow-version', version)
    workflow.set('workflow-user', user)
    return workflow

# Use custom properties
processed = add_processing_history(image, 'resize', {'scale': 0.5})
with_metrics = add_quality_metrics(processed, 8.5, 2.1, 7.8)
final = add_workflow_info(with_metrics, 'final-review', '1.2', 'editor@example.com')

Metadata Preservation

Control which metadata is preserved during image operations.

# Copy with all metadata
exact_copy = image.copy()

# Copy image data only (no metadata)
data_only = pyvips.Image.new_from_memory(
    image.write_to_memory(),
    image.width, image.height, image.bands, image.format
)

# Copy with selective metadata
selective_copy = image.copy()
for field in ['icc-profile-data', 'exif-ifd0-Orientation']:
    if field in image.get_fields():
        selective_copy.set(field, image.get(field))

# Preserve metadata through operations
def preserve_metadata(original, processed):
    """Copy important metadata to processed image."""
    result = processed.copy()
    
    # Core metadata to preserve
    important_fields = [
        'icc-profile-data',
        'exif-ifd0-Orientation', 
        'exif-ifd0-Artist',
        'exif-ifd0-Copyright',
        'xmp-dc-creator',
        'xmp-dc-rights'
    ]
    
    for field in important_fields:
        if field in original.get_fields():
            try:
                result.set(field, original.get(field))
            except:
                pass  # Skip if can't set
    
    return result

# Use metadata preservation
resized = image.resize(0.5)
final = preserve_metadata(image, resized)

Install with Tessl CLI

npx tessl i tessl/pypi-pyvips

docs

array-integration.md

enumerations.md

image-creation.md

image-operations.md

image-output.md

index.md

io-connections.md

properties-metadata.md

system-control.md

tile.json