or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

decoding.mdencoding.mdindex.mdtransformations.mdutilities.md

transformations.mddocs/

0

# Image Transformations

1

2

Lossless transformation operations for JPEG images including cropping, scaling with quality adjustment, multiple crop operations with background filling, and advanced transform operations that work directly in the compressed domain.

3

4

## Capabilities

5

6

### Single Crop Operation

7

8

Perform lossless crop operations on JPEG images without decompression/recompression quality loss.

9

10

```python { .api }

11

def crop(

12

jpeg_buf: bytes,

13

x: int, y: int, w: int, h: int,

14

preserve: bool = False,

15

gray: bool = False,

16

copynone: bool = False

17

) -> bytes:

18

"""

19

Losslessly crop a JPEG image.

20

21

Args:

22

jpeg_buf: Input JPEG data as bytes

23

x: Crop origin X coordinate (must be MCU-aligned unless preserve=True)

24

y: Crop origin Y coordinate (must be MCU-aligned unless preserve=True)

25

w: Crop width in pixels

26

h: Crop height in pixels

27

preserve: If True, preserve exact crop boundaries (slower)

28

gray: Convert to grayscale during crop

29

copynone: Do not copy EXIF metadata

30

31

Returns:

32

bytes: Cropped JPEG data

33

34

Raises:

35

OSError: If crop request is invalid or coordinates are not MCU-aligned

36

"""

37

```

38

39

### Multiple Crop Operations

40

41

Perform multiple crop and/or extension operations in a single call with optional background filling.

42

43

```python { .api }

44

def crop_multiple(

45

jpeg_buf: bytes,

46

crop_parameters: list[tuple[int, int, int, int]],

47

background_luminance: float = 1.0,

48

gray: bool = False,

49

copynone: bool = False

50

) -> list[bytes]:

51

"""

52

Lossless crop and/or extension operations on JPEG image.

53

54

Args:

55

jpeg_buf: Input JPEG data as bytes

56

crop_parameters: List of (x, y, w, h) tuples for each crop operation

57

background_luminance: Luminance level (0-1) for background fill when extending

58

gray: Produce grayscale output

59

copynone: Do not copy EXIF metadata

60

61

Returns:

62

list[bytes]: List of cropped/extended JPEG images

63

64

Notes:

65

- Crop origins must be divisible by MCU block size

66

- Extensions beyond image boundaries filled with background_luminance color

67

- background_luminance: 0=black, 0.5=gray, 1=white

68

"""

69

```

70

71

### Scale with Quality

72

73

Scale JPEG images while adjusting quality, combining decompression to YUV, scaling, and recompression in one operation.

74

75

```python { .api }

76

def scale_with_quality(

77

jpeg_buf: bytes,

78

scaling_factor: tuple[int, int] | None = None,

79

quality: int = 85,

80

flags: int = 0

81

) -> bytes:

82

"""

83

Scale JPEG image and re-encode with specified quality.

84

85

Args:

86

jpeg_buf: Input JPEG data as bytes

87

scaling_factor: Scaling as (numerator, denominator) tuple

88

quality: Output JPEG quality (1-100)

89

flags: Processing flags (TJFLAG_* constants)

90

91

Returns:

92

bytes: Scaled and re-encoded JPEG data

93

94

Notes:

95

- Avoids color conversion step for efficiency

96

- Useful for creating thumbnails with size and quality control

97

"""

98

```

99

100

## Constants

101

102

### Transform Operations

103

104

```python { .api }

105

TJXOP_NONE: int # No transform

106

TJXOP_HFLIP: int # Horizontal flip

107

TJXOP_VFLIP: int # Vertical flip

108

TJXOP_TRANSPOSE: int # Transpose

109

TJXOP_TRANSVERSE: int # Transverse

110

TJXOP_ROT90: int # 90 degree rotation

111

TJXOP_ROT180: int # 180 degree rotation

112

TJXOP_ROT270: int # 270 degree rotation

113

```

114

115

### Transform Options

116

117

```python { .api }

118

TJXOPT_PERFECT: int # Perfect transform (require exact alignment)

119

TJXOPT_TRIM: int # Trim partial MCUs

120

TJXOPT_CROP: int # Crop operation

121

TJXOPT_GRAY: int # Convert to grayscale

122

TJXOPT_NOOUTPUT: int # No output (validation only)

123

TJXOPT_PROGRESSIVE: int # Progressive output

124

TJXOPT_COPYNONE: int # Copy no metadata

125

```

126

127

### MCU Block Sizes

128

129

MCU (Minimum Coded Unit) alignment requirements:

130

131

```python { .api }

132

tjMCUWidth: list[int] # MCU width for each subsampling type

133

tjMCUHeight: list[int] # MCU height for each subsampling type

134

135

# MCU sizes by subsampling:

136

# TJSAMP_444 (4:4:4): 8x8 pixels

137

# TJSAMP_422 (4:2:2): 16x8 pixels

138

# TJSAMP_420 (4:2:0): 16x16 pixels

139

# TJSAMP_GRAY: 8x8 pixels

140

# TJSAMP_440 (4:4:0): 8x16 pixels

141

# TJSAMP_411 (4:1:1): 32x8 pixels

142

```

143

144

## Structure Definitions

145

146

### Cropping Region

147

148

```python { .api }

149

class CroppingRegion(Structure):

150

"""Defines a rectangular cropping region."""

151

_fields_ = [

152

("x", c_int), # X coordinate of crop origin

153

("y", c_int), # Y coordinate of crop origin

154

("w", c_int), # Width of crop region

155

("h", c_int) # Height of crop region

156

]

157

```

158

159

### Scaling Factor

160

161

```python { .api }

162

class ScalingFactor(Structure):

163

"""Defines a scaling factor as numerator/denominator."""

164

_fields_ = [

165

("num", c_int), # Numerator

166

("denom", c_int) # Denominator

167

]

168

```

169

170

### Background Structure

171

172

```python { .api }

173

class BackgroundStruct(Structure):

174

"""Background fill parameters for image extension operations."""

175

_fields_ = [

176

("w", c_int), # Input image width

177

("h", c_int), # Input image height

178

("lum", c_int) # Luminance value for background fill

179

]

180

```

181

182

### Transform Structure

183

184

```python { .api }

185

class TransformStruct(Structure):

186

"""Complete transform operation definition."""

187

_fields_ = [

188

("r", CroppingRegion), # Crop region

189

("op", c_int), # Transform operation (TJXOP_*)

190

("options", c_int), # Transform options (TJXOPT_*)

191

("data", POINTER(BackgroundStruct)), # Background data for extensions

192

("customFilter", CUSTOMFILTER) # Custom filter function

193

]

194

```

195

196

## Usage Examples

197

198

### Basic Cropping

199

200

```python

201

from turbojpeg import TurboJPEG

202

203

jpeg = TurboJPEG()

204

205

# Load JPEG image

206

with open('input.jpg', 'rb') as f:

207

jpeg_data = f.read()

208

209

# Get image info for crop planning

210

width, height, subsample, _ = jpeg.decode_header(jpeg_data)

211

print(f"Original: {width}x{height}, subsampling: {subsample}")

212

213

# Crop from (100, 100) with size 300x200

214

cropped = jpeg.crop(jpeg_data, 100, 100, 300, 200)

215

216

# Save cropped image

217

with open('cropped.jpg', 'wb') as f:

218

f.write(cropped)

219

```

220

221

### MCU-Aligned Cropping

222

223

```python

224

# For 4:2:0 subsampling, MCU is 16x16 pixels

225

# Crop coordinates should be multiples of 16 for perfect alignment

226

227

# MCU-aligned crop (fast, lossless)

228

aligned_crop = jpeg.crop(jpeg_data, 16, 32, 320, 240) # All multiples of 16

229

230

# Non-aligned crop with preserve=True (slower but exact)

231

exact_crop = jpeg.crop(jpeg_data, 15, 33, 318, 238, preserve=True)

232

```

233

234

### Multiple Crops

235

236

```python

237

# Define multiple crop regions

238

crop_regions = [

239

(0, 0, 100, 100), # Top-left corner

240

(100, 0, 100, 100), # Top-right corner

241

(0, 100, 100, 100), # Bottom-left corner

242

(100, 100, 100, 100), # Bottom-right corner

243

]

244

245

# Perform all crops in one operation

246

crops = jpeg.crop_multiple(jpeg_data, crop_regions)

247

248

# Save each crop

249

for i, crop_data in enumerate(crops):

250

with open(f'crop_{i}.jpg', 'wb') as f:

251

f.write(crop_data)

252

```

253

254

### Extended Crops with Background

255

256

```python

257

# Get original image dimensions

258

width, height, _, _ = jpeg.decode_header(jpeg_data)

259

260

# Define crops that extend beyond image boundaries

261

extended_crops = [

262

(0, 0, width + 50, height + 50), # Extend right and bottom

263

(-25, -25, width + 50, height + 50), # Extend all sides

264

]

265

266

# White background fill (luminance = 1.0)

267

white_bg_crops = jpeg.crop_multiple(

268

jpeg_data,

269

extended_crops,

270

background_luminance=1.0

271

)

272

273

# Gray background fill (luminance = 0.5)

274

gray_bg_crops = jpeg.crop_multiple(

275

jpeg_data,

276

extended_crops,

277

background_luminance=0.5

278

)

279

280

# Black background fill (luminance = 0.0)

281

black_bg_crops = jpeg.crop_multiple(

282

jpeg_data,

283

extended_crops,

284

background_luminance=0.0

285

)

286

```

287

288

### Grayscale Cropping

289

290

```python

291

# Convert to grayscale during crop

292

gray_crop = jpeg.crop(

293

jpeg_data,

294

100, 100, 200, 200,

295

gray=True

296

)

297

298

# Multiple grayscale crops

299

gray_crops = jpeg.crop_multiple(

300

jpeg_data,

301

[(0, 0, 100, 100), (100, 100, 100, 100)],

302

gray=True

303

)

304

```

305

306

### Scale with Quality

307

308

```python

309

# Scale to half size with quality 70

310

half_size = jpeg.scale_with_quality(

311

jpeg_data,

312

scaling_factor=(1, 2),

313

quality=70

314

)

315

316

# Scale to quarter size with high quality

317

quarter_size = jpeg.scale_with_quality(

318

jpeg_data,

319

scaling_factor=(1, 4),

320

quality=90

321

)

322

323

# Available scaling factors

324

print("Available scaling factors:", jpeg.scaling_factors)

325

# Common factors: (1,8), (1,4), (3,8), (1,2), (5,8), (3,4), (7,8), (1,1), (9,8), (5,4), (11,8), (3,2), (13,8), (7,4), (15,8), (2,1)

326

```

327

328

### Strip Metadata

329

330

```python

331

# Remove EXIF and other metadata during crop

332

no_metadata = jpeg.crop(

333

jpeg_data,

334

0, 0, width, height, # Full image crop

335

copynone=True # Strip all metadata

336

)

337

338

# Compare file sizes

339

print(f"Original size: {len(jpeg_data)} bytes")

340

print(f"No metadata size: {len(no_metadata)} bytes")

341

```

342

343

### Advanced Transform Example

344

345

```python

346

# Combine multiple operations

347

def create_thumbnail_gallery(jpeg_data, thumb_size=(150, 150)):

348

"""Create multiple thumbnail crops with different qualities."""

349

350

# Get image info

351

width, height, subsample, _ = jpeg.decode_header(jpeg_data)

352

353

# Calculate grid positions for thumbnails

354

thumb_w, thumb_h = thumb_size

355

cols = width // thumb_w

356

rows = height // thumb_h

357

358

crop_params = []

359

for row in range(rows):

360

for col in range(cols):

361

x = col * thumb_w

362

y = row * thumb_h

363

crop_params.append((x, y, thumb_w, thumb_h))

364

365

# Extract all thumbnails

366

thumbnails = jpeg.crop_multiple(jpeg_data, crop_params)

367

368

# Scale and adjust quality for web use

369

web_thumbs = []

370

for thumb in thumbnails:

371

web_thumb = jpeg.scale_with_quality(

372

thumb,

373

scaling_factor=(1, 2), # Half size

374

quality=60 # Web quality

375

)

376

web_thumbs.append(web_thumb)

377

378

return web_thumbs

379

380

# Usage

381

with open('large_image.jpg', 'rb') as f:

382

image_data = f.read()

383

384

thumbnails = create_thumbnail_gallery(image_data)

385

386

for i, thumb in enumerate(thumbnails):

387

with open(f'thumb_{i:03d}.jpg', 'wb') as f:

388

f.write(thumb)

389

```