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

utilities-performance.mddocs/

Utilities and Performance

Sharp provides extensive utilities for performance monitoring, library configuration, and runtime optimization controls.

Capabilities

Cache Management

Control libvips operation cache for memory and performance optimization.

/**
 * Get or set libvips operation cache limits
 * @param options - Cache configuration or boolean
 * @returns Current cache statistics
 */
sharp.cache(options?: boolean | CacheOptions): CacheResult;

interface CacheOptions {
  /** Maximum memory in MB (default 50) */
  memory?: number;
  /** Maximum open files (default 20) */
  files?: number;
  /** Maximum cached operations (default 100) */
  items?: number;
}

interface CacheResult {
  /** Memory usage statistics */
  memory: {
    current: number;
    high: number;
    max: number;
  };
  /** File handle statistics */
  files: {
    current: number;
    max: number;
  };
  /** Cached items statistics */
  items: {
    current: number;
    max: number;
  };
}

Usage Examples:

// Get current cache statistics
const cacheStats = sharp.cache();
console.log('Memory usage:', cacheStats.memory);
console.log('Open files:', cacheStats.files);
console.log('Cached items:', cacheStats.items);

// Set cache limits
sharp.cache({
  memory: 100,  // 100MB
  files: 50,    // 50 open files
  items: 200    // 200 cached operations
});

// Disable caching
sharp.cache(false);

// Reset to defaults
sharp.cache(true);

// Monitor cache usage
const monitorCache = () => {
  const stats = sharp.cache();
  console.log(`Memory: ${stats.memory.current}MB / ${stats.memory.max}MB`);
  console.log(`Files: ${stats.files.current} / ${stats.files.max}`);
  console.log(`Items: ${stats.items.current} / ${stats.items.max}`);
  
  if (stats.memory.current > stats.memory.max * 0.9) {
    console.warn('Cache memory usage is high');
  }
};

Concurrency Control

Manage thread usage for optimal performance across different workloads.

/**
 * Get or set number of libvips worker threads
 * @param concurrency - Number of threads (0 = auto-detect)
 * @returns Current concurrency value
 */
sharp.concurrency(concurrency?: number): number;

Usage Examples:

// Get current thread count
const currentThreads = sharp.concurrency();
console.log(`Current threads: ${currentThreads}`);

// Set thread count
sharp.concurrency(4);  // Use 4 threads
sharp.concurrency(0);  // Auto-detect (default)

// Optimize for workload
const optimizeForWorkload = (type) => {
  const cpuCount = require('os').cpus().length;
  
  switch (type) {
    case 'batch':
      // High throughput batch processing
      sharp.concurrency(cpuCount);
      break;
    case 'server':
      // Web server with many concurrent requests
      sharp.concurrency(Math.max(2, cpuCount / 2));
      break;
    case 'single':
      // Single image processing
      sharp.concurrency(1);
      break;
    default:
      // Auto-detect
      sharp.concurrency(0);
  }
};

Task Monitoring

Monitor Sharp's internal task queue and processing status.

/**
 * Access internal task counters
 * @returns Current task queue statistics
 */
sharp.counters(): SharpCounters;

interface SharpCounters {
  /** Tasks waiting for worker threads */
  queue: number;
  /** Tasks currently being processed */
  process: number;
}

Usage Examples:

// Monitor task queue
const monitorTasks = () => {
  const counters = sharp.counters();
  console.log(`Queued: ${counters.queue}, Processing: ${counters.process}`);
  
  if (counters.queue > 10) {
    console.warn('High queue depth - consider increasing concurrency');
  }
};

// Monitor during batch processing
const processBatch = async (images) => {
  console.log('Starting batch processing...');
  
  const interval = setInterval(monitorTasks, 1000);
  
  try {
    await Promise.all(images.map(processImage));
  } finally {
    clearInterval(interval);
    console.log('Batch processing complete');
  }
};

SIMD Control

Enable or disable SIMD vector unit instructions for performance optimization.

/**
 * Get or set SIMD vector unit instruction usage
 * @param enable - Enable SIMD instructions (optional)
 * @returns Current SIMD status
 */
sharp.simd(enable?: boolean): boolean;

Usage Examples:

// Check SIMD availability
const simdEnabled = sharp.simd();
console.log(`SIMD enabled: ${simdEnabled}`);

// Enable SIMD (if supported)
if (sharp.simd(true)) {
  console.log('SIMD enabled for better performance');
} else {
  console.log('SIMD not available on this system');
}

// Disable SIMD for debugging
sharp.simd(false);

// Performance comparison
const benchmarkSIMD = async (imagePath) => {
  const image = sharp(imagePath);
  
  // Test with SIMD disabled
  sharp.simd(false);
  const start1 = Date.now();
  await image.clone().resize(800, 600).blur(2).toBuffer();
  const time1 = Date.now() - start1;
  
  // Test with SIMD enabled
  sharp.simd(true);
  const start2 = Date.now();
  await image.clone().resize(800, 600).blur(2).toBuffer();
  const time2 = Date.now() - start2;
  
  console.log(`Without SIMD: ${time1}ms`);
  console.log(`With SIMD: ${time2}ms`);
  console.log(`Performance gain: ${((time1 - time2) / time1 * 100).toFixed(1)}%`);
};

Operation Blocking

Block or unblock specific libvips operations for security or compatibility.

/**
 * Block libvips operations at runtime
 * @param options - Operations to block
 */
sharp.block(options: { operation: string[] }): void;

/**
 * Unblock libvips operations at runtime
 * @param options - Operations to unblock
 */
sharp.unblock(options: { operation: string[] }): void;

Usage Examples:

// Block potentially unsafe operations
sharp.block({
  operation: ['VipsForeignLoadTiff', 'VipsForeignLoadPdf']
});

// Create allowlist by blocking all then unblocking specific operations
sharp.block({
  operation: ['VipsForeignLoad']  // Block all loaders
});

sharp.unblock({
  operation: [
    'VipsForeignLoadJpegFile',
    'VipsForeignLoadPngFile',
    'VipsForeignLoadWebpFile'
  ]
});

// Security-focused configuration
const secureConfiguration = () => {
  // Block operations that could be security risks
  sharp.block({
    operation: [
      'VipsForeignLoadTiff',      // TIFF can contain exploits
      'VipsForeignLoadPdf',       // PDF processing
      'VipsForeignLoadSvg',       // SVG can contain scripts
      'VipsForeignLoadGif'        // Limit GIF processing
    ]
  });
  
  // Set conservative limits
  sharp.cache({
    memory: 50,   // Limit memory usage
    files: 10,    // Limit open files
    items: 50     // Limit cached items
  });
  
  // Single thread for predictable behavior
  sharp.concurrency(1);
};

Library Information

Access version information and format capabilities.

// Static properties providing library information

/** Available input/output formats and their capabilities */
sharp.format: FormatEnum;

/** Version information for Sharp and dependencies */
sharp.versions: {
  sharp: string;
  vips: string;
  // Optional dependency versions
  aom?: string;
  cairo?: string;
  exif?: string;
  fontconfig?: string;
  freetype?: string;
  heif?: string;
  jpeg?: string;
  lcms?: string;
  png?: string;
  svg?: string;
  tiff?: string;
  webp?: string;
  // ... other optional dependencies
};

/** Available interpolation methods */
sharp.interpolators: {
  nearest: 'nearest';
  bilinear: 'bilinear'; 
  bicubic: 'bicubic';
  locallyBoundedBicubic: 'lbb';
  nohalo: 'nohalo';
  vertexSplitQuadraticBasisSpline: 'vsqbs';
};

/** Event emitter for queue status changes */
sharp.queue: NodeJS.EventEmitter;

/** Gravity constants for positioning */
sharp.gravity: GravityEnum;

/** Strategy constants for cropping */
sharp.strategy: StrategyEnum;

/** Kernel constants for resizing */
sharp.kernel: KernelEnum;

/** Fit constants for resize behavior */
sharp.fit: FitEnum;

/** Boolean operation constants */
sharp.bool: BoolEnum;

Usage Examples:

// Check format support
console.log('Supported formats:');
Object.keys(sharp.format).forEach(format => {
  const info = sharp.format[format];
  console.log(`${format}: input=${info.input.file}, output=${info.output.file}`);
});

// Check specific format capabilities
if (sharp.format.avif && sharp.format.avif.output.file) {
  console.log('AVIF output is supported');
} else {
  console.log('AVIF output not available');
}

// Version information
console.log('Library versions:');
console.log(`Sharp: ${sharp.versions.sharp}`);
console.log(`libvips: ${sharp.versions.vips}`);

if (sharp.versions.webp) {
  console.log(`WebP: ${sharp.versions.webp}`);
}

// Check for optional features
const checkFeatures = () => {
  const features = {
    avif: !!sharp.versions.heif,  // AVIF requires HEIF support
    svg: !!sharp.versions.svg,
    pdf: !!sharp.versions.poppler || !!sharp.versions.pdfium,
    tiff: !!sharp.versions.tiff,
    jpeg2000: !!sharp.versions.openjpeg
  };
  
  console.log('Available features:', features);
  return features;
};

// Monitor queue events
sharp.queue.on('change', (queueLength) => {
  console.log(`Queue length changed: ${queueLength}`);
});

Performance Optimization Patterns

Optimal Configuration for Different Use Cases:

// Web server configuration
const configureForWebServer = () => {
  const cpuCount = require('os').cpus().length;
  
  sharp.cache({
    memory: 100,                    // 100MB cache
    files: Math.min(cpuCount * 2, 20),  // Reasonable file limit
    items: 200                      // Cache many operations
  });
  
  sharp.concurrency(Math.max(2, cpuCount / 2));  // Leave CPU for other tasks
  sharp.simd(true);                              // Enable SIMD if available
  
  // Monitor performance
  setInterval(() => {
    const stats = sharp.cache();
    const counters = sharp.counters();
    
    if (stats.memory.current > stats.memory.max * 0.8) {
      console.warn('Sharp cache memory usage high');
    }
    
    if (counters.queue > 5) {
      console.warn('Sharp queue backing up');
    }
  }, 30000);
};

// Batch processing configuration
const configureForBatch = () => {
  const totalMemory = require('os').totalmem() / 1024 / 1024 / 1024; // GB
  const memoryLimit = Math.min(Math.floor(totalMemory / 4), 500);    // 25% of RAM, max 500MB
  
  sharp.cache({
    memory: memoryLimit,
    files: 100,      // Many files for batch processing
    items: 1000      // Cache many operations
  });
  
  sharp.concurrency(0);  // Use all available CPUs
  sharp.simd(true);      // Maximum performance
};

// Memory-constrained configuration
const configureForLowMemory = () => {
  sharp.cache({
    memory: 20,      // Low memory limit
    files: 5,        // Few open files
    items: 50        // Limited caching
  });
  
  sharp.concurrency(1);  // Single thread to limit memory
  sharp.simd(false);     // Reduce complexity
};

Performance Monitoring:

const createPerformanceMonitor = () => {
  const stats = {
    processedImages: 0,
    totalTime: 0,
    errors: 0
  };
  
  const monitor = {
    async processImage(imagePath, operations) {
      const startTime = Date.now();
      
      try {
        let pipeline = sharp(imagePath);
        
        // Apply operations
        for (const op of operations) {
          pipeline = pipeline[op.method](...op.args);
        }
        
        const result = await pipeline.toBuffer();
        
        const endTime = Date.now();
        const processingTime = endTime - startTime;
        
        stats.processedImages++;
        stats.totalTime += processingTime;
        
        // Log performance metrics
        const avgTime = stats.totalTime / stats.processedImages;
        console.log(`Processed ${imagePath} in ${processingTime}ms (avg: ${avgTime.toFixed(1)}ms)`);
        
        return result;
      } catch (error) {
        stats.errors++;
        console.error(`Error processing ${imagePath}:`, error.message);
        throw error;
      }
    },
    
    getStats() {
      return {
        ...stats,
        averageTime: stats.processedImages > 0 ? stats.totalTime / stats.processedImages : 0,
        errorRate: stats.processedImages > 0 ? stats.errors / stats.processedImages : 0
      };
    },
    
    reset() {
      stats.processedImages = 0;
      stats.totalTime = 0;
      stats.errors = 0;
    }
  };
  
  return monitor;
};

Memory Management:

const createMemoryManager = () => {
  return {
    async processWithMemoryManagement(images, processor) {
      const batchSize = 10;  // Process in batches
      const results = [];
      
      for (let i = 0; i < images.length; i += batchSize) {
        const batch = images.slice(i, i + batchSize);
        
        // Process batch
        const batchResults = await Promise.all(
          batch.map(processor)
        );
        
        results.push(...batchResults);
        
        // Check memory usage
        const cacheStats = sharp.cache();
        if (cacheStats.memory.current > cacheStats.memory.max * 0.8) {
          console.log('Clearing cache due to high memory usage');
          sharp.cache(false);  // Clear cache
          sharp.cache(true);   // Re-enable with defaults
        }
        
        // Force garbage collection if available
        if (global.gc) {
          global.gc();
        }
        
        console.log(`Processed batch ${Math.floor(i/batchSize) + 1}/${Math.ceil(images.length/batchSize)}`);
      }
      
      return results;
    }
  };
};

Enum Definitions

Complete definitions for all Sharp constants and enums.

interface FormatEnum {
  heif: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
  jpeg: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
  jp2: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
  jxl: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
  png: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
  webp: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
  gif: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
  avif: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
  tiff: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
  dz: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
  fits: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
  magick: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
  openslide: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
  pdf: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
  ppm: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
  raw: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
  svg: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
  v: { id: string; input: { file: boolean; buffer: boolean; stream: boolean; }; output: { file: boolean; buffer: boolean; stream: boolean; }; };
}

interface GravityEnum {
  north: 1;
  northeast: 2;
  east: 3;
  southeast: 4;
  south: 5;
  southwest: 6;
  west: 7;
  northwest: 8;
  center: 9;
  centre: 9;
}

interface StrategyEnum {
  entropy: 16;
  attention: 17;
}

interface KernelEnum {
  nearest: 'nearest';
  linear: 'linear';
  cubic: 'cubic';
  mitchell: 'mitchell';
  lanczos2: 'lanczos2';
  lanczos3: 'lanczos3';
}

interface FitEnum {
  contain: 'contain';
  cover: 'cover';
  fill: 'fill';
  inside: 'inside';
  outside: 'outside';
}

interface BoolEnum {
  and: 'and';
  or: 'or';
  eor: 'eor';
}

interface Interpolators {
  nearest: 'nearest';
  bilinear: 'bilinear';
  bicubic: 'bicubic';
  locallyBoundedBicubic: 'lbb';
  nohalo: 'nohalo';
  vertexSplitQuadraticBasisSpline: 'vsqbs';
}

Best Practices

  1. Cache Configuration: Set appropriate cache limits based on available memory
  2. Concurrency: Balance thread count with system resources and workload
  3. SIMD Usage: Enable SIMD for better performance on supported systems
  4. Security: Block unnecessary operations in production environments
  5. Monitoring: Track cache usage and queue depth for optimization
  6. Memory Management: Process large batches in chunks to prevent memory exhaustion
  7. Error Handling: Monitor error rates and adjust configuration as needed

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