Python binding for the libvips image processing library with high-performance streaming architecture
—
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.
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")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}")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 timestampExample 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')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 copyrightExample 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')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' # CountryExample 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"
)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 valuesExample 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 -10Add 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 propertiesExample 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')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