or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

array-integration.mdenumerations.mdimage-creation.mdimage-operations.mdimage-output.mdindex.mdio-connections.mdproperties-metadata.mdsystem-control.md

properties-metadata.mddocs/

0

# Properties and Metadata

1

2

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.

3

4

## Capabilities

5

6

### Basic Image Properties

7

8

Access fundamental image characteristics that define the image structure.

9

10

```python { .api }

11

# Core dimensions

12

@property

13

def width(self) -> int:

14

"""Image width in pixels."""

15

16

@property

17

def height(self) -> int:

18

"""Image height in pixels."""

19

20

@property

21

def bands(self) -> int:

22

"""Number of bands (channels) in the image."""

23

24

# Format and interpretation

25

@property

26

def format(self) -> str:

27

"""

28

Pixel format.

29

Values: 'uchar', 'char', 'ushort', 'short', 'uint', 'int',

30

'float', 'complex', 'double', 'dpcomplex'

31

"""

32

33

@property

34

def interpretation(self) -> str:

35

"""

36

Color space interpretation.

37

Values: 'multiband', 'b-w', 'histogram', 'xyz', 'lab', 'cmyk',

38

'rgb', 'srgb', 'yxy', 'fourier', 'rgb16', 'grey16', etc.

39

"""

40

41

@property

42

def coding(self) -> str:

43

"""

44

Pixel coding method.

45

Values: 'none', 'labq', 'rad'

46

"""

47

48

# Resolution information

49

@property

50

def xres(self) -> float:

51

"""Horizontal resolution in pixels per unit."""

52

53

@property

54

def yres(self) -> float:

55

"""Vertical resolution in pixels per unit."""

56

57

@property

58

def xoffset(self) -> int:

59

"""Horizontal offset."""

60

61

@property

62

def yoffset(self) -> int:

63

"""Vertical offset."""

64

```

65

66

Example usage:

67

68

```python

69

# Basic image info

70

print(f"Dimensions: {image.width} x {image.height}")

71

print(f"Bands: {image.bands}")

72

print(f"Format: {image.format}")

73

print(f"Color space: {image.interpretation}")

74

print(f"Resolution: {image.xres} x {image.yres}")

75

76

# Check image characteristics

77

if image.bands == 1:

78

print("Grayscale image")

79

elif image.bands == 3:

80

print("RGB image")

81

elif image.bands == 4:

82

print("RGBA image")

83

84

# Format information

85

if image.format in ['uchar', 'char']:

86

print("8-bit image")

87

elif image.format in ['ushort', 'short']:

88

print("16-bit image")

89

elif image.format == 'float':

90

print("32-bit float image")

91

```

92

93

### Property Access Methods

94

95

Generic methods for getting and setting image properties and metadata.

96

97

```python { .api }

98

def get(self, name: str):

99

"""

100

Get property value.

101

102

Parameters:

103

- name: str, property name

104

105

Returns:

106

Property value (type varies by property)

107

"""

108

109

def set(self, name: str, value) -> None:

110

"""

111

Set property value.

112

113

Parameters:

114

- name: str, property name

115

- value: property value (type varies)

116

117

Returns:

118

None (modifies image metadata)

119

"""

120

121

def get_fields(self) -> list:

122

"""

123

Get list of all property names.

124

125

Returns:

126

List of property name strings

127

"""

128

129

def remove(self, name: str) -> None:

130

"""

131

Remove property.

132

133

Parameters:

134

- name: str, property name to remove

135

136

Returns:

137

None (modifies image metadata)

138

"""

139

140

def get_typeof(self, name: str) -> str:

141

"""

142

Get property type.

143

144

Parameters:

145

- name: str, property name

146

147

Returns:

148

str, GType name for the property

149

"""

150

151

def set_type(self, gtype: int, name: str, value) -> None:

152

"""

153

Set property with explicit type.

154

155

Parameters:

156

- gtype: int, GType for the property

157

- name: str, property name

158

- value: property value

159

160

Returns:

161

None (modifies image metadata)

162

"""

163

```

164

165

Example usage:

166

167

```python

168

# List all properties

169

fields = image.get_fields()

170

print(f"Available properties: {len(fields)}")

171

for field in fields[:10]: # Show first 10

172

print(f" {field}: {image.get(field)}")

173

174

# Get specific properties

175

try:

176

orientation = image.get('orientation')

177

print(f"Image orientation: {orientation}")

178

except:

179

print("No orientation metadata")

180

181

# Set custom metadata

182

image_copy = image.copy()

183

image_copy.set('custom-property', 'my value')

184

image_copy.set('processing-date', '2024-01-15')

185

186

# Remove metadata

187

image_copy.remove('exif-ifd0-Orientation')

188

189

# Check property types

190

if 'xres' in image.get_fields():

191

prop_type = image.get_typeof('xres')

192

print(f"xres type: {prop_type}")

193

```

194

195

### EXIF Metadata

196

197

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

198

199

```python { .api }

200

# Common EXIF properties (examples)

201

# Camera information

202

'exif-ifd0-Make' # Camera manufacturer

203

'exif-ifd0-Model' # Camera model

204

'exif-ifd0-Software' # Software used

205

'exif-ifd0-DateTime' # File modification date

206

'exif-ifd0-Orientation' # Image orientation (1-8)

207

208

# Photo settings

209

'exif-exif-ExposureTime' # Shutter speed

210

'exif-exif-FNumber' # Aperture (f-stop)

211

'exif-exif-ISO' # ISO sensitivity

212

'exif-exif-FocalLength' # Focal length

213

'exif-exif-Flash' # Flash settings

214

'exif-exif-WhiteBalance' # White balance setting

215

216

# GPS information

217

'exif-gps-GPSLatitude' # Latitude

218

'exif-gps-GPSLongitude' # Longitude

219

'exif-gps-GPSAltitude' # Altitude

220

'exif-gps-GPSTimeStamp' # GPS timestamp

221

```

222

223

Example usage:

224

225

```python

226

# Read EXIF data

227

def get_camera_info(image):

228

camera_info = {}

229

try:

230

camera_info['make'] = image.get('exif-ifd0-Make')

231

camera_info['model'] = image.get('exif-ifd0-Model')

232

camera_info['datetime'] = image.get('exif-ifd0-DateTime')

233

camera_info['orientation'] = image.get('exif-ifd0-Orientation')

234

except:

235

pass # Property not available

236

return camera_info

237

238

def get_photo_settings(image):

239

settings = {}

240

try:

241

settings['exposure'] = image.get('exif-exif-ExposureTime')

242

settings['aperture'] = image.get('exif-exif-FNumber')

243

settings['iso'] = image.get('exif-exif-ISO')

244

settings['focal_length'] = image.get('exif-exif-FocalLength')

245

except:

246

pass

247

return settings

248

249

# Use EXIF data

250

camera = get_camera_info(image)

251

if camera:

252

print(f"Camera: {camera.get('make', 'Unknown')} {camera.get('model', 'Unknown')}")

253

254

# Handle orientation

255

orientation = image.get('exif-ifd0-Orientation') if 'exif-ifd0-Orientation' in image.get_fields() else 1

256

if orientation in [3, 6, 8]: # Common rotation values

257

if orientation == 3:

258

image = image.rotate(180)

259

elif orientation == 6:

260

image = image.rotate(90)

261

elif orientation == 8:

262

image = image.rotate(270)

263

264

# Set EXIF data

265

image_copy = image.copy()

266

image_copy.set('exif-ifd0-Artist', 'Photographer Name')

267

image_copy.set('exif-ifd0-Copyright', '© 2024 My Company')

268

image_copy.set('exif-ifd0-Software', 'PyVips Processing')

269

```

270

271

### ICC Color Profiles

272

273

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

274

275

```python { .api }

276

# ICC profile properties

277

'icc-profile-data' # Raw ICC profile data (bytes)

278

'icc-profile-description' # Profile description

279

'icc-profile-manufacturer' # Profile manufacturer

280

'icc-profile-model' # Profile model

281

'icc-profile-copyright' # Profile copyright

282

```

283

284

Example usage:

285

286

```python

287

# Check for ICC profile

288

has_profile = 'icc-profile-data' in image.get_fields()

289

if has_profile:

290

profile_data = image.get('icc-profile-data')

291

print(f"ICC profile size: {len(profile_data)} bytes")

292

293

# Get profile description

294

try:

295

description = image.get('icc-profile-description')

296

print(f"Profile: {description}")

297

except:

298

print("No profile description")

299

300

# Embed ICC profile

301

with open('srgb_profile.icc', 'rb') as f:

302

profile_data = f.read()

303

304

image_with_profile = image.copy()

305

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

306

307

# Remove ICC profile

308

image_no_profile = image.copy()

309

if 'icc-profile-data' in image_no_profile.get_fields():

310

image_no_profile.remove('icc-profile-data')

311

```

312

313

### XMP and IPTC Metadata

314

315

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

316

317

```python { .api }

318

# XMP properties (examples)

319

'xmp-dc-title' # Title

320

'xmp-dc-description' # Description

321

'xmp-dc-creator' # Creator

322

'xmp-dc-subject' # Keywords/subjects

323

'xmp-dc-rights' # Rights/copyright

324

325

# IPTC properties (examples)

326

'iptc-Application2-Caption' # Caption/description

327

'iptc-Application2-Keywords' # Keywords

328

'iptc-Application2-Byline' # Photographer

329

'iptc-Application2-Copyright' # Copyright notice

330

'iptc-Application2-City' # City

331

'iptc-Application2-Country' # Country

332

```

333

334

Example usage:

335

336

```python

337

# Read XMP metadata

338

def get_xmp_info(image):

339

xmp_info = {}

340

fields = image.get_fields()

341

342

xmp_fields = [f for f in fields if f.startswith('xmp-')]

343

for field in xmp_fields:

344

try:

345

xmp_info[field] = image.get(field)

346

except:

347

pass

348

return xmp_info

349

350

# Read IPTC metadata

351

def get_iptc_info(image):

352

iptc_info = {}

353

fields = image.get_fields()

354

355

iptc_fields = [f for f in fields if f.startswith('iptc-')]

356

for field in iptc_fields:

357

try:

358

iptc_info[field] = image.get(field)

359

except:

360

pass

361

return iptc_info

362

363

# Set metadata for web publishing

364

def add_web_metadata(image, title, description, keywords, author):

365

web_image = image.copy()

366

367

# XMP metadata

368

web_image.set('xmp-dc-title', title)

369

web_image.set('xmp-dc-description', description)

370

web_image.set('xmp-dc-creator', author)

371

web_image.set('xmp-dc-subject', keywords)

372

373

# IPTC metadata

374

web_image.set('iptc-Application2-Caption', description)

375

web_image.set('iptc-Application2-Keywords', keywords)

376

web_image.set('iptc-Application2-Byline', author)

377

378

return web_image

379

380

# Use metadata functions

381

xmp_data = get_xmp_info(image)

382

if xmp_data:

383

print("XMP metadata found:")

384

for key, value in xmp_data.items():

385

print(f" {key}: {value}")

386

387

# Add metadata to processed image

388

processed = add_web_metadata(

389

image,

390

"Sunset Landscape",

391

"Beautiful sunset over mountains",

392

"sunset, landscape, mountains, nature",

393

"John Photographer"

394

)

395

```

396

397

### Image Scale and Offset

398

399

Access scale and offset properties used for pixel value interpretation.

400

401

```python { .api }

402

def get_scale(self) -> float:

403

"""

404

Get scale property.

405

406

Returns:

407

float, scale factor applied to pixel values

408

"""

409

410

def get_offset(self) -> float:

411

"""

412

Get offset property.

413

414

Returns:

415

float, offset added to pixel values

416

"""

417

418

# Properties

419

'scale' # Scale factor for pixel values

420

'offset' # Offset for pixel values

421

```

422

423

Example usage:

424

425

```python

426

# Check scale and offset

427

scale = image.get_scale()

428

offset = image.get_offset()

429

print(f"Scale: {scale}, Offset: {offset}")

430

431

# Pixel values are interpreted as: (raw_value * scale) + offset

432

if scale != 1.0 or offset != 0.0:

433

print("Image has scale/offset transformation")

434

435

# Set scale and offset for calibrated images

436

calibrated = image.copy()

437

calibrated.set('scale', 2.5) # Each unit represents 2.5 real units

438

calibrated.set('offset', -10.0) # Zero point is shifted by -10

439

```

440

441

### Custom Properties

442

443

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

444

445

```python { .api }

446

# Custom property naming conventions

447

'custom-*' # Application-specific properties

448

'processing-*' # Processing history

449

'workflow-*' # Workflow information

450

'user-*' # User-defined properties

451

```

452

453

Example usage:

454

455

```python

456

# Processing history

457

def add_processing_history(image, operation, parameters):

458

processed = image.copy()

459

460

# Add timestamp

461

import datetime

462

timestamp = datetime.datetime.now().isoformat()

463

processed.set('processing-timestamp', timestamp)

464

465

# Add operation info

466

processed.set('processing-operation', operation)

467

processed.set('processing-parameters', str(parameters))

468

469

# Increment processing count

470

try:

471

count = processed.get('processing-count')

472

processed.set('processing-count', count + 1)

473

except:

474

processed.set('processing-count', 1)

475

476

return processed

477

478

# Quality assessment

479

def add_quality_metrics(image, sharpness, noise_level, exposure_quality):

480

metrics = image.copy()

481

metrics.set('quality-sharpness', sharpness)

482

metrics.set('quality-noise', noise_level)

483

metrics.set('quality-exposure', exposure_quality)

484

return metrics

485

486

# Workflow tracking

487

def add_workflow_info(image, stage, version, user):

488

workflow = image.copy()

489

workflow.set('workflow-stage', stage)

490

workflow.set('workflow-version', version)

491

workflow.set('workflow-user', user)

492

return workflow

493

494

# Use custom properties

495

processed = add_processing_history(image, 'resize', {'scale': 0.5})

496

with_metrics = add_quality_metrics(processed, 8.5, 2.1, 7.8)

497

final = add_workflow_info(with_metrics, 'final-review', '1.2', 'editor@example.com')

498

```

499

500

## Metadata Preservation

501

502

Control which metadata is preserved during image operations.

503

504

```python

505

# Copy with all metadata

506

exact_copy = image.copy()

507

508

# Copy image data only (no metadata)

509

data_only = pyvips.Image.new_from_memory(

510

image.write_to_memory(),

511

image.width, image.height, image.bands, image.format

512

)

513

514

# Copy with selective metadata

515

selective_copy = image.copy()

516

for field in ['icc-profile-data', 'exif-ifd0-Orientation']:

517

if field in image.get_fields():

518

selective_copy.set(field, image.get(field))

519

520

# Preserve metadata through operations

521

def preserve_metadata(original, processed):

522

"""Copy important metadata to processed image."""

523

result = processed.copy()

524

525

# Core metadata to preserve

526

important_fields = [

527

'icc-profile-data',

528

'exif-ifd0-Orientation',

529

'exif-ifd0-Artist',

530

'exif-ifd0-Copyright',

531

'xmp-dc-creator',

532

'xmp-dc-rights'

533

]

534

535

for field in important_fields:

536

if field in original.get_fields():

537

try:

538

result.set(field, original.get(field))

539

except:

540

pass # Skip if can't set

541

542

return result

543

544

# Use metadata preservation

545

resized = image.resize(0.5)

546

final = preserve_metadata(image, resized)

547

```