High performance Node.js image processing library for resizing JPEG, PNG, WebP, GIF, AVIF and TIFF images
80
Sharp provides powerful image composition capabilities for overlaying, blending, and combining multiple images with precise control over positioning and blend modes.
Overlay multiple images with various blend modes and positioning options.
/**
* Composite multiple images over the processed image
* @param images - Array of overlay specifications
* @returns Sharp instance for chaining
*/
composite(images: OverlayOptions[]): Sharp;
interface OverlayOptions {
/** Input image (Buffer, file path, or creation object) */
input: string | Buffer | CreateInput;
/** Blend mode for compositing */
blend?: BlendMode;
/** Gravity-based positioning */
gravity?: GravityOption;
/** Pixel offset from top edge */
top?: number;
/** Pixel offset from left edge */
left?: number;
/** Repeat overlay across entire image */
tile?: boolean;
/** Overlay is already premultiplied */
premultiplied?: boolean;
/** DPI for vector overlays */
density?: number;
/** Read all frames for animated overlays */
animated?: boolean;
}
type CreateInput = { create: Create } | { text: CreateText } | { raw: CreateRaw };
type BlendMode = 'clear' | 'source' | 'over' | 'in' | 'out' | 'atop' | 'dest' |
'dest-over' | 'dest-in' | 'dest-out' | 'dest-atop' | 'xor' | 'add' | 'saturate' |
'multiply' | 'screen' | 'overlay' | 'darken' | 'lighten' | 'colour-dodge' |
'color-dodge' | 'colour-burn' | 'color-burn' | 'hard-light' | 'soft-light' |
'difference' | 'exclusion';
type GravityOption = 'north' | 'northeast' | 'east' | 'southeast' | 'south' |
'southwest' | 'west' | 'northwest' | 'center' | 'centre';Usage Examples:
// Basic overlay
await sharp('background.jpg')
.composite([{
input: 'logo.png',
gravity: 'southeast',
blend: 'over'
}])
.toFile('branded.jpg');
// Multiple overlays with different blend modes
await sharp('base.jpg')
.composite([
{
input: 'texture.png',
blend: 'multiply',
tile: true
},
{
input: 'spotlight.png',
blend: 'screen',
top: 100,
left: 200
},
{
input: 'watermark.png',
gravity: 'southeast',
blend: 'over'
}
])
.toFile('composite.jpg');
// Precise positioning
await sharp('canvas.jpg')
.composite([{
input: 'overlay.png',
top: 50,
left: 100,
blend: 'source-over'
}])
.toFile('positioned.jpg');Different blend modes produce various visual effects when compositing images.
Porter-Duff Blend Modes:
clear - Clear destinationsource - Copy source, ignore destinationover - Source over destination (default)in - Source where destination is opaqueout - Source where destination is transparentatop - Source over destination, only where destination is opaquedest - Keep destination, ignore sourcedest-over - Destination over sourcedest-in - Destination where source is opaquedest-out - Destination where source is transparentdest-atop - Destination over source, only where source is opaquexor - Either source or destination, not bothMathematical Blend Modes:
add - Add source to destinationsaturate - Saturated additionmultiply - Multiply source with destinationscreen - Screen blend (inverse multiply)overlay - Overlay blendPhotographic Blend Modes:
darken - Keep darker pixelslighten - Keep lighter pixelscolour-dodge / color-dodge - Brighten destination based on sourcecolour-burn / color-burn - Darken destination based on sourcehard-light - Hard light blendsoft-light - Soft light blenddifference - Absolute differenceexclusion - Similar to difference but with lower contrastUsage Examples:
// Multiply blend for shadows/textures
await sharp('photo.jpg')
.composite([{
input: 'shadow-texture.png',
blend: 'multiply'
}])
.toFile('textured.jpg');
// Screen blend for light effects
await sharp('portrait.jpg')
.composite([{
input: 'light-rays.png',
blend: 'screen'
}])
.toFile('lit.jpg');
// Difference blend for artistic effects
await sharp('image1.jpg')
.composite([{
input: 'image2.jpg',
blend: 'difference'
}])
.toFile('artistic.jpg');Repeat overlays across the entire image surface.
// Tile overlay example
await sharp('large-canvas.jpg')
.composite([{
input: 'pattern.png',
tile: true,
blend: 'multiply'
}])
.toFile('patterned.jpg');
// Tiled watermark
await sharp('document.jpg')
.composite([{
input: 'watermark.png',
tile: true,
blend: 'over',
gravity: 'center'
}])
.toFile('watermarked.jpg');Composite dynamically generated content.
// Text overlay
await sharp('photo.jpg')
.composite([{
input: {
text: {
text: 'Copyright 2024',
font: 'Arial',
rgba: true,
dpi: 150
}
},
gravity: 'southeast',
blend: 'over'
}])
.toFile('copyrighted.jpg');
// Generated shape overlay
await sharp('background.jpg')
.composite([{
input: {
create: {
width: 100,
height: 100,
channels: 4,
background: { r: 255, g: 0, b: 0, alpha: 0.5 }
}
},
top: 50,
left: 50,
blend: 'over'
}])
.toFile('with-shape.jpg');Multi-layer Composition:
const createComplexComposite = async (base, elements, output) => {
const layers = elements.map(element => ({
input: element.file,
top: element.y,
left: element.x,
blend: element.blend || 'over'
}));
await sharp(base)
.composite(layers)
.toFile(output);
};
// Usage
await createComplexComposite('canvas.jpg', [
{ file: 'layer1.png', x: 0, y: 0, blend: 'multiply' },
{ file: 'layer2.png', x: 100, y: 50, blend: 'screen' },
{ file: 'layer3.png', x: 200, y: 100, blend: 'overlay' }
], 'composite.jpg');Conditional Overlays:
const addWatermark = async (input, output, addMark = true) => {
const pipeline = sharp(input);
if (addMark) {
pipeline.composite([{
input: 'watermark.png',
gravity: 'southeast',
blend: 'over'
}]);
}
await pipeline.toFile(output);
};Batch Processing with Overlays:
const batchOverlay = async (inputDir, overlayFile, outputDir) => {
const files = await fs.readdir(inputDir);
await Promise.all(
files.map(file =>
sharp(path.join(inputDir, file))
.composite([{
input: overlayFile,
gravity: 'northeast',
blend: 'over'
}])
.toFile(path.join(outputDir, file))
)
);
};Smart Positioning:
const smartPosition = async (base, overlay, output) => {
const { width, height } = await sharp(base).metadata();
const { width: overlayWidth, height: overlayHeight } = await sharp(overlay).metadata();
// Position overlay in bottom-right with margin
const margin = 20;
const left = width - overlayWidth - margin;
const top = height - overlayHeight - margin;
await sharp(base)
.composite([{
input: overlay,
left,
top,
blend: 'over'
}])
.toFile(output);
};Alpha Blending:
const alphaBlend = async (base, overlay, opacity, output) => {
// Apply opacity to overlay
const transparentOverlay = await sharp(overlay)
.ensureAlpha(opacity)
.toBuffer();
await sharp(base)
.composite([{
input: transparentOverlay,
blend: 'over'
}])
.toFile(output);
};Masked Composition:
const maskedComposite = async (base, overlay, mask, output) => {
// Apply mask to overlay
const maskedOverlay = await sharp(overlay)
.composite([{
input: mask,
blend: 'dest-in'
}])
.toBuffer();
await sharp(base)
.composite([{
input: maskedOverlay,
blend: 'over'
}])
.toFile(output);
};// Available via sharp.blend (conceptual - blend modes are strings)
const blendModes = [
'clear', 'source', 'over', 'in', 'out', 'atop',
'dest', 'dest-over', 'dest-in', 'dest-out', 'dest-atop', 'xor',
'add', 'saturate', 'multiply', 'screen', 'overlay',
'darken', 'lighten', 'colour-dodge', 'color-dodge',
'colour-burn', 'color-burn', 'hard-light', 'soft-light',
'difference', 'exclusion'
];
// Available via sharp.gravity
interface GravityEnum {
north: number;
northeast: number;
east: number;
southeast: number;
south: number;
southwest: number;
west: number;
northwest: number;
center: number;
centre: number;
}Usage Examples:
// Using gravity constants
await sharp('base.jpg')
.composite([{
input: 'overlay.png',
gravity: sharp.gravity.northeast
}])
.toFile('positioned.jpg');Install with Tessl CLI
npx tessl i tessl/npm-sharpdocs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10