or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

color-channels.mdcomposition.mdconstructor-input.mdindex.mdmetadata-stats.mdoperations-filters.mdoutput-formats.mdresize-geometry.mdutilities-performance.md

composition.mddocs/

0

# Image Composition

1

2

Sharp provides powerful image composition capabilities for overlaying, blending, and combining multiple images with precise control over positioning and blend modes.

3

4

## Capabilities

5

6

### Image Compositing

7

8

Overlay multiple images with various blend modes and positioning options.

9

10

```javascript { .api }

11

/**

12

* Composite multiple images over the processed image

13

* @param images - Array of overlay specifications

14

* @returns Sharp instance for chaining

15

*/

16

composite(images: OverlayOptions[]): Sharp;

17

18

interface OverlayOptions {

19

/** Input image (Buffer, file path, or creation object) */

20

input: string | Buffer | CreateInput;

21

/** Blend mode for compositing */

22

blend?: BlendMode;

23

/** Gravity-based positioning */

24

gravity?: GravityOption;

25

/** Pixel offset from top edge */

26

top?: number;

27

/** Pixel offset from left edge */

28

left?: number;

29

/** Repeat overlay across entire image */

30

tile?: boolean;

31

/** Overlay is already premultiplied */

32

premultiplied?: boolean;

33

/** DPI for vector overlays */

34

density?: number;

35

/** Read all frames for animated overlays */

36

animated?: boolean;

37

}

38

39

type CreateInput = { create: Create } | { text: CreateText } | { raw: CreateRaw };

40

41

type BlendMode = 'clear' | 'source' | 'over' | 'in' | 'out' | 'atop' | 'dest' |

42

'dest-over' | 'dest-in' | 'dest-out' | 'dest-atop' | 'xor' | 'add' | 'saturate' |

43

'multiply' | 'screen' | 'overlay' | 'darken' | 'lighten' | 'colour-dodge' |

44

'color-dodge' | 'colour-burn' | 'color-burn' | 'hard-light' | 'soft-light' |

45

'difference' | 'exclusion';

46

47

type GravityOption = 'north' | 'northeast' | 'east' | 'southeast' | 'south' |

48

'southwest' | 'west' | 'northwest' | 'center' | 'centre';

49

```

50

51

**Usage Examples:**

52

53

```javascript

54

// Basic overlay

55

await sharp('background.jpg')

56

.composite([{

57

input: 'logo.png',

58

gravity: 'southeast',

59

blend: 'over'

60

}])

61

.toFile('branded.jpg');

62

63

// Multiple overlays with different blend modes

64

await sharp('base.jpg')

65

.composite([

66

{

67

input: 'texture.png',

68

blend: 'multiply',

69

tile: true

70

},

71

{

72

input: 'spotlight.png',

73

blend: 'screen',

74

top: 100,

75

left: 200

76

},

77

{

78

input: 'watermark.png',

79

gravity: 'southeast',

80

blend: 'over'

81

}

82

])

83

.toFile('composite.jpg');

84

85

// Precise positioning

86

await sharp('canvas.jpg')

87

.composite([{

88

input: 'overlay.png',

89

top: 50,

90

left: 100,

91

blend: 'source-over'

92

}])

93

.toFile('positioned.jpg');

94

```

95

96

### Blend Modes

97

98

Different blend modes produce various visual effects when compositing images.

99

100

**Porter-Duff Blend Modes:**

101

- `clear` - Clear destination

102

- `source` - Copy source, ignore destination

103

- `over` - Source over destination (default)

104

- `in` - Source where destination is opaque

105

- `out` - Source where destination is transparent

106

- `atop` - Source over destination, only where destination is opaque

107

- `dest` - Keep destination, ignore source

108

- `dest-over` - Destination over source

109

- `dest-in` - Destination where source is opaque

110

- `dest-out` - Destination where source is transparent

111

- `dest-atop` - Destination over source, only where source is opaque

112

- `xor` - Either source or destination, not both

113

114

**Mathematical Blend Modes:**

115

- `add` - Add source to destination

116

- `saturate` - Saturated addition

117

- `multiply` - Multiply source with destination

118

- `screen` - Screen blend (inverse multiply)

119

- `overlay` - Overlay blend

120

121

**Photographic Blend Modes:**

122

- `darken` - Keep darker pixels

123

- `lighten` - Keep lighter pixels

124

- `colour-dodge` / `color-dodge` - Brighten destination based on source

125

- `colour-burn` / `color-burn` - Darken destination based on source

126

- `hard-light` - Hard light blend

127

- `soft-light` - Soft light blend

128

- `difference` - Absolute difference

129

- `exclusion` - Similar to difference but with lower contrast

130

131

**Usage Examples:**

132

133

```javascript

134

// Multiply blend for shadows/textures

135

await sharp('photo.jpg')

136

.composite([{

137

input: 'shadow-texture.png',

138

blend: 'multiply'

139

}])

140

.toFile('textured.jpg');

141

142

// Screen blend for light effects

143

await sharp('portrait.jpg')

144

.composite([{

145

input: 'light-rays.png',

146

blend: 'screen'

147

}])

148

.toFile('lit.jpg');

149

150

// Difference blend for artistic effects

151

await sharp('image1.jpg')

152

.composite([{

153

input: 'image2.jpg',

154

blend: 'difference'

155

}])

156

.toFile('artistic.jpg');

157

```

158

159

### Tiled Overlays

160

161

Repeat overlays across the entire image surface.

162

163

```javascript { .api }

164

// Tile overlay example

165

await sharp('large-canvas.jpg')

166

.composite([{

167

input: 'pattern.png',

168

tile: true,

169

blend: 'multiply'

170

}])

171

.toFile('patterned.jpg');

172

173

// Tiled watermark

174

await sharp('document.jpg')

175

.composite([{

176

input: 'watermark.png',

177

tile: true,

178

blend: 'over',

179

gravity: 'center'

180

}])

181

.toFile('watermarked.jpg');

182

```

183

184

### Dynamic Content Overlays

185

186

Composite dynamically generated content.

187

188

```javascript { .api }

189

// Text overlay

190

await sharp('photo.jpg')

191

.composite([{

192

input: {

193

text: {

194

text: 'Copyright 2024',

195

font: 'Arial',

196

rgba: true,

197

dpi: 150

198

}

199

},

200

gravity: 'southeast',

201

blend: 'over'

202

}])

203

.toFile('copyrighted.jpg');

204

205

// Generated shape overlay

206

await sharp('background.jpg')

207

.composite([{

208

input: {

209

create: {

210

width: 100,

211

height: 100,

212

channels: 4,

213

background: { r: 255, g: 0, b: 0, alpha: 0.5 }

214

}

215

},

216

top: 50,

217

left: 50,

218

blend: 'over'

219

}])

220

.toFile('with-shape.jpg');

221

```

222

223

### Advanced Composition Patterns

224

225

**Multi-layer Composition:**

226

227

```javascript

228

const createComplexComposite = async (base, elements, output) => {

229

const layers = elements.map(element => ({

230

input: element.file,

231

top: element.y,

232

left: element.x,

233

blend: element.blend || 'over'

234

}));

235

236

await sharp(base)

237

.composite(layers)

238

.toFile(output);

239

};

240

241

// Usage

242

await createComplexComposite('canvas.jpg', [

243

{ file: 'layer1.png', x: 0, y: 0, blend: 'multiply' },

244

{ file: 'layer2.png', x: 100, y: 50, blend: 'screen' },

245

{ file: 'layer3.png', x: 200, y: 100, blend: 'overlay' }

246

], 'composite.jpg');

247

```

248

249

**Conditional Overlays:**

250

251

```javascript

252

const addWatermark = async (input, output, addMark = true) => {

253

const pipeline = sharp(input);

254

255

if (addMark) {

256

pipeline.composite([{

257

input: 'watermark.png',

258

gravity: 'southeast',

259

blend: 'over'

260

}]);

261

}

262

263

await pipeline.toFile(output);

264

};

265

```

266

267

**Batch Processing with Overlays:**

268

269

```javascript

270

const batchOverlay = async (inputDir, overlayFile, outputDir) => {

271

const files = await fs.readdir(inputDir);

272

273

await Promise.all(

274

files.map(file =>

275

sharp(path.join(inputDir, file))

276

.composite([{

277

input: overlayFile,

278

gravity: 'northeast',

279

blend: 'over'

280

}])

281

.toFile(path.join(outputDir, file))

282

)

283

);

284

};

285

```

286

287

**Smart Positioning:**

288

289

```javascript

290

const smartPosition = async (base, overlay, output) => {

291

const { width, height } = await sharp(base).metadata();

292

const { width: overlayWidth, height: overlayHeight } = await sharp(overlay).metadata();

293

294

// Position overlay in bottom-right with margin

295

const margin = 20;

296

const left = width - overlayWidth - margin;

297

const top = height - overlayHeight - margin;

298

299

await sharp(base)

300

.composite([{

301

input: overlay,

302

left,

303

top,

304

blend: 'over'

305

}])

306

.toFile(output);

307

};

308

```

309

310

**Alpha Blending:**

311

312

```javascript

313

const alphaBlend = async (base, overlay, opacity, output) => {

314

// Apply opacity to overlay

315

const transparentOverlay = await sharp(overlay)

316

.ensureAlpha(opacity)

317

.toBuffer();

318

319

await sharp(base)

320

.composite([{

321

input: transparentOverlay,

322

blend: 'over'

323

}])

324

.toFile(output);

325

};

326

```

327

328

**Masked Composition:**

329

330

```javascript

331

const maskedComposite = async (base, overlay, mask, output) => {

332

// Apply mask to overlay

333

const maskedOverlay = await sharp(overlay)

334

.composite([{

335

input: mask,

336

blend: 'dest-in'

337

}])

338

.toBuffer();

339

340

await sharp(base)

341

.composite([{

342

input: maskedOverlay,

343

blend: 'over'

344

}])

345

.toFile(output);

346

};

347

```

348

349

## Constants and Utilities

350

351

```javascript { .api }

352

// Available via sharp.blend (conceptual - blend modes are strings)

353

const blendModes = [

354

'clear', 'source', 'over', 'in', 'out', 'atop',

355

'dest', 'dest-over', 'dest-in', 'dest-out', 'dest-atop', 'xor',

356

'add', 'saturate', 'multiply', 'screen', 'overlay',

357

'darken', 'lighten', 'colour-dodge', 'color-dodge',

358

'colour-burn', 'color-burn', 'hard-light', 'soft-light',

359

'difference', 'exclusion'

360

];

361

362

// Available via sharp.gravity

363

interface GravityEnum {

364

north: number;

365

northeast: number;

366

east: number;

367

southeast: number;

368

south: number;

369

southwest: number;

370

west: number;

371

northwest: number;

372

center: number;

373

centre: number;

374

}

375

```

376

377

**Usage Examples:**

378

379

```javascript

380

// Using gravity constants

381

await sharp('base.jpg')

382

.composite([{

383

input: 'overlay.png',

384

gravity: sharp.gravity.northeast

385

}])

386

.toFile('positioned.jpg');

387

```

388

389

## Performance Considerations

390

391

- **Large Images**: Be mindful of memory usage when compositing large images

392

- **Multiple Overlays**: Each overlay adds processing time; consider combining overlays when possible

393

- **Blend Modes**: Some blend modes are more computationally expensive than others

394

- **Tiled Overlays**: Can be memory-intensive for large canvases with small tiles

395

- **Dynamic Content**: Text and shape generation adds overhead; cache when possible