CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-sharp

High performance Node.js image processing library for resizing JPEG, PNG, WebP, GIF, AVIF and TIFF images

80

1.01x
Overview
Eval results
Files

composition.mddocs/

Image Composition

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

Capabilities

Image Compositing

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');

Blend Modes

Different blend modes produce various visual effects when compositing images.

Porter-Duff Blend Modes:

  • clear - Clear destination
  • source - Copy source, ignore destination
  • over - Source over destination (default)
  • in - Source where destination is opaque
  • out - Source where destination is transparent
  • atop - Source over destination, only where destination is opaque
  • dest - Keep destination, ignore source
  • dest-over - Destination over source
  • dest-in - Destination where source is opaque
  • dest-out - Destination where source is transparent
  • dest-atop - Destination over source, only where source is opaque
  • xor - Either source or destination, not both

Mathematical Blend Modes:

  • add - Add source to destination
  • saturate - Saturated addition
  • multiply - Multiply source with destination
  • screen - Screen blend (inverse multiply)
  • overlay - Overlay blend

Photographic Blend Modes:

  • darken - Keep darker pixels
  • lighten - Keep lighter pixels
  • colour-dodge / color-dodge - Brighten destination based on source
  • colour-burn / color-burn - Darken destination based on source
  • hard-light - Hard light blend
  • soft-light - Soft light blend
  • difference - Absolute difference
  • exclusion - Similar to difference but with lower contrast

Usage 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');

Tiled Overlays

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');

Dynamic Content Overlays

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');

Advanced Composition Patterns

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);
};

Constants and Utilities

// 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');

Performance Considerations

  • Large Images: Be mindful of memory usage when compositing large images
  • Multiple Overlays: Each overlay adds processing time; consider combining overlays when possible
  • Blend Modes: Some blend modes are more computationally expensive than others
  • Tiled Overlays: Can be memory-intensive for large canvases with small tiles
  • Dynamic Content: Text and shape generation adds overhead; cache when possible

Install with Tessl CLI

npx tessl i tessl/npm-sharp

docs

color-channels.md

composition.md

constructor-input.md

index.md

metadata-stats.md

operations-filters.md

output-formats.md

resize-geometry.md

utilities-performance.md

tile.json