or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

formats-plugins.mdimage-io.mdindex.mdmulti-image.mdreader-writer.mdv3-api.mdvolume-data.md

reader-writer.mddocs/

0

# Reader/Writer Objects

1

2

Low-level interfaces for manual control over reading and writing operations, providing fine-grained parameter access and custom workflow support.

3

4

## Capabilities

5

6

### Reader Objects

7

8

Get reader objects for manual, sequential, or custom reading workflows.

9

10

```python { .api }

11

def get_reader(uri, format=None, mode="?", **kwargs):

12

"""

13

Get a Reader object for manual reading operations.

14

15

Parameters:

16

- uri (ImageResource): File path, URL, bytes, or file object

17

- format (str, optional): Format to use for reading

18

- mode (str): Reader mode hint

19

- 'i': single image

20

- 'I': multiple images

21

- 'v': single volume

22

- 'V': multiple volumes

23

- '?': don't care (default)

24

- **kwargs: Format-specific parameters

25

26

Returns:

27

- Reader: Reader object with manual control methods

28

"""

29

```

30

31

**Usage Examples:**

32

33

```python

34

import imageio.v2 as imageio

35

36

# Basic reader usage

37

reader = imageio.get_reader('animation.gif')

38

39

try:

40

print(f"Number of frames: {len(reader)}")

41

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

42

43

# Read frames individually

44

frame_0 = reader.get_data(0)

45

frame_5 = reader.get_data(5)

46

47

# Get metadata

48

global_meta = reader.get_meta_data()

49

frame_meta = reader.get_meta_data(3)

50

51

# Iterate through frames

52

for i, frame in enumerate(reader):

53

print(f"Frame {i}: {frame.shape}")

54

if i >= 10: # Process first 10 frames only

55

break

56

57

finally:

58

reader.close() # Always close reader

59

60

# Context manager usage (recommended)

61

with imageio.get_reader('video.mp4') as reader:

62

print(f"Video length: {len(reader)} frames")

63

64

# Skip frames efficiently

65

for i in range(0, len(reader), 30): # Every 30th frame

66

frame = reader.get_data(i)

67

process_frame(frame, i) # Your processing function

68

```

69

70

### Writer Objects

71

72

Get writer objects for manual, streaming, or custom writing workflows.

73

74

```python { .api }

75

def get_writer(uri, format=None, mode="?", **kwargs):

76

"""

77

Get a Writer object for manual writing operations.

78

79

Parameters:

80

- uri (ImageResource): Output path or file object

81

- format (str, optional): Format to use for writing

82

- mode (str): Writer mode hint

83

- 'i': single image

84

- 'I': multiple images

85

- 'v': single volume

86

- 'V': multiple volumes

87

- '?': don't care (default)

88

- **kwargs: Format-specific parameters

89

90

Returns:

91

- Writer: Writer object with manual control methods

92

"""

93

```

94

95

**Usage Examples:**

96

97

```python

98

import imageio.v2 as imageio

99

import numpy as np

100

101

# Create animation frame by frame

102

with imageio.get_writer('animation.gif', duration=0.5) as writer:

103

for i in range(20):

104

# Generate frame dynamically

105

frame = np.zeros((100, 100, 3), dtype=np.uint8)

106

107

# Create rotating pattern

108

angle = i * 18 # degrees

109

x = int(50 + 30 * np.cos(np.radians(angle)))

110

y = int(50 + 30 * np.sin(np.radians(angle)))

111

frame[y-5:y+5, x-5:x+5] = [255, 0, 0] # Red dot

112

113

writer.append_data(frame)

114

115

# Optional: set per-frame metadata

116

frame_meta = {'frame_time': i * 0.5}

117

# Note: metadata support varies by format

118

119

# Write video with custom parameters

120

with imageio.get_writer('output.mp4', fps=30, codec='libx264') as writer:

121

for frame_data in generate_frames(): # Your frame generator

122

writer.append_data(frame_data)

123

124

# Manual writer control (not recommended for normal use)

125

writer = imageio.get_writer('manual.png')

126

try:

127

# For single images, append_data writes the image

128

image = np.random.randint(0, 255, (200, 200, 3), dtype=np.uint8)

129

writer.append_data(image)

130

131

# Set global metadata if supported

132

try:

133

writer.set_meta_data({'software': 'ImageIO Example'})

134

except NotImplementedError:

135

print("Format doesn't support metadata writing")

136

finally:

137

writer.close()

138

```

139

140

## Reader Methods and Properties

141

142

### Core Reader Methods

143

144

```python { .api }

145

class Reader:

146

"""Reader object for manual image reading control."""

147

148

def get_length(self):

149

"""Get number of images in the file."""

150

151

def get_data(self, index):

152

"""Get image data at specific index."""

153

154

def get_next_data(self):

155

"""Get next image in sequence."""

156

157

def get_meta_data(self, index=None):

158

"""Get metadata for image or global metadata."""

159

160

def set_image_index(self, index):

161

"""Set current reading position."""

162

163

def close(self):

164

"""Close the reader and free resources."""

165

166

def iter_data(self):

167

"""Iterate over all images with metadata."""

168

169

# Properties

170

request: Request # Request object with file info

171

format: Format # Format object (legacy plugins only)

172

```

173

174

**Detailed Usage:**

175

176

```python

177

import imageio.v2 as imageio

178

179

with imageio.get_reader('multi_page.tiff') as reader:

180

# Length and basic info

181

total_images = reader.get_length()

182

print(f"Total images: {total_images}")

183

184

# Access request information

185

print(f"Filename: {reader.request.filename}")

186

print(f"File size: {reader.request.get_file().seek(0, 2)}")

187

188

# Random access to images

189

middle_image = reader.get_data(total_images // 2)

190

last_image = reader.get_data(-1) # Last image

191

192

# Sequential reading with position control

193

reader.set_image_index(10) # Start from image 10

194

for i in range(5): # Read next 5 images

195

image = reader.get_next_data()

196

print(f"Image {10+i}: {image.shape}")

197

198

# Metadata access

199

global_meta = reader.get_meta_data() # Global file metadata

200

for i in range(min(3, total_images)): # First 3 images

201

image_meta = reader.get_meta_data(i)

202

print(f"Image {i} metadata: {image_meta}")

203

204

# Iteration with metadata

205

for image_with_meta in reader.iter_data():

206

print(f"Image shape: {image_with_meta.shape}")

207

print(f"Metadata: {image_with_meta.meta}")

208

```

209

210

## Writer Methods and Properties

211

212

### Core Writer Methods

213

214

```python { .api }

215

class Writer:

216

"""Writer object for manual image writing control."""

217

218

def append_data(self, im, meta=None):

219

"""Add image data to output."""

220

221

def set_meta_data(self, meta):

222

"""Set global metadata for output file."""

223

224

def close(self):

225

"""Close writer and finalize output."""

226

227

# Properties

228

request: Request # Request object with file info

229

format: Format # Format object (legacy plugins only)

230

```

231

232

**Detailed Usage:**

233

234

```python

235

import imageio.v2 as imageio

236

import numpy as np

237

from datetime import datetime

238

239

# Create multi-page TIFF with metadata

240

with imageio.get_writer('output.tiff', compression='lzw') as writer:

241

# Set global metadata

242

global_meta = {

243

'software': 'ImageIO Python',

244

'datetime': datetime.now().isoformat(),

245

'description': 'Multi-page TIFF created with ImageIO'

246

}

247

248

try:

249

writer.set_meta_data(global_meta)

250

except NotImplementedError:

251

print("This format doesn't support global metadata")

252

253

# Add images with individual metadata

254

for i in range(5):

255

# Create test image

256

image = np.random.randint(0, 255, (100, 100), dtype=np.uint8)

257

258

# Per-image metadata

259

image_meta = {

260

'page_number': i,

261

'timestamp': datetime.now().timestamp()

262

}

263

264

# Append image (metadata support varies by format)

265

writer.append_data(image, meta=image_meta)

266

267

print(f"Written to: {writer.request.filename}")

268

```

269

270

## Advanced Reader/Writer Patterns

271

272

### Streaming Large Files

273

274

Handle large files without loading everything into memory:

275

276

```python

277

import imageio.v2 as imageio

278

import numpy as np

279

280

def process_large_video(input_path, output_path, processing_func):

281

"""Process large video file frame by frame."""

282

283

with imageio.get_reader(input_path) as reader:

284

# Get video properties

285

total_frames = len(reader)

286

first_frame = reader.get_data(0)

287

height, width = first_frame.shape[:2]

288

289

print(f"Processing {total_frames} frames of size {height}x{width}")

290

291

# Reset to beginning

292

reader.set_image_index(0)

293

294

with imageio.get_writer(output_path, fps=30) as writer:

295

for frame_num in range(total_frames):

296

# Read frame

297

frame = reader.get_data(frame_num)

298

299

# Process frame

300

processed_frame = processing_func(frame)

301

302

# Write processed frame

303

writer.append_data(processed_frame)

304

305

# Progress indicator

306

if frame_num % 100 == 0:

307

print(f"Processed {frame_num}/{total_frames} frames")

308

309

# Example processing function

310

def enhance_contrast(frame):

311

"""Simple contrast enhancement."""

312

frame = frame.astype(np.float32)

313

frame = (frame - frame.min()) / (frame.max() - frame.min()) * 255

314

return frame.astype(np.uint8)

315

316

# Usage

317

process_large_video('input_video.mp4', 'enhanced_video.mp4', enhance_contrast)

318

```

319

320

### Custom Format Handling

321

322

Handle files that need special parameter control:

323

324

```python

325

import imageio.v2 as imageio

326

327

def read_scientific_data(file_path, calibration_params):

328

"""Read scientific data with custom calibration."""

329

330

with imageio.get_reader(file_path, format='TIFF') as reader:

331

# Get calibration from metadata if available

332

global_meta = reader.get_meta_data()

333

334

# Override with provided calibration

335

pixel_size = calibration_params.get('pixel_size', 1.0)

336

units = calibration_params.get('units', 'pixels')

337

338

print(f"Reading {len(reader)} images with {pixel_size} {units}/pixel")

339

340

calibrated_images = []

341

for i in range(len(reader)):

342

# Read raw image

343

raw_image = reader.get_data(i)

344

image_meta = reader.get_meta_data(i)

345

346

# Apply calibration (example: convert to physical units)

347

calibrated_image = raw_image * pixel_size

348

349

# Attach enhanced metadata

350

enhanced_meta = {

351

**image_meta,

352

'pixel_size': pixel_size,

353

'units': units,

354

'calibrated': True

355

}

356

357

# Create Array with metadata

358

from imageio.core import Array

359

calibrated_array = Array(calibrated_image)

360

calibrated_array.meta = enhanced_meta

361

362

calibrated_images.append(calibrated_array)

363

364

return calibrated_images

365

366

# Usage

367

calibration = {'pixel_size': 0.1, 'units': 'micrometers'}

368

calibrated_data = read_scientific_data('microscopy.tiff', calibration)

369

```

370

371

### Error Recovery and Validation

372

373

Robust file handling with error recovery:

374

375

```python

376

import imageio.v2 as imageio

377

import numpy as np

378

379

def robust_multi_image_read(file_path, max_errors=5):

380

"""Read multi-image file with error recovery."""

381

382

try:

383

reader = imageio.get_reader(file_path)

384

except Exception as e:

385

print(f"Cannot open {file_path}: {e}")

386

return []

387

388

valid_images = []

389

error_count = 0

390

391

try:

392

total_length = len(reader)

393

print(f"Attempting to read {total_length} images")

394

395

for i in range(total_length):

396

try:

397

# Attempt to read image

398

image = reader.get_data(i)

399

400

# Validate image

401

if image.size == 0:

402

raise ValueError("Empty image")

403

404

if not np.isfinite(image).all():

405

raise ValueError("Invalid pixel values")

406

407

valid_images.append(image)

408

409

except Exception as e:

410

error_count += 1

411

print(f"Error reading image {i}: {e}")

412

413

if error_count >= max_errors:

414

print(f"Too many errors ({error_count}), stopping")

415

break

416

417

# Continue with next image

418

continue

419

420

finally:

421

reader.close()

422

423

print(f"Successfully read {len(valid_images)} images with {error_count} errors")

424

return valid_images

425

426

# Usage

427

images = robust_multi_image_read('potentially_corrupted.tiff', max_errors=10)

428

```