Skip to content
>_ TrueFileSize.com
··7 min read

Testing Image Processing Pipelines with Sample Files

Image processing pipelines need diverse test inputs — different formats, sizes, transparency, and edge cases. This guide shows how to build a thorough test suite using sample images from TrueFileSize.

Prerequisites

  • Node.js 18+ with sharp, or Python 3.10+ with Pillow
  • Sample images from TrueFileSize

Step 1: Download Diverse Sample Images

mkdir -p test-images
CDN="https://cdn.truefilesize.com"

# Standard formats and sizes
curl -sL -o test-images/photo-1mb.jpg "$CDN/jpg/sample-1mb.jpg"
curl -sL -o test-images/photo-5mb.jpg "$CDN/jpg/sample-5mb.jpg"
curl -sL -o test-images/screenshot.png "$CDN/png/sample-500kb.png"

# Transparency (alpha channel)
curl -sL -o test-images/logo-transparent.png "$CDN/png/transparent-logo.png"

# Modern formats
curl -sL -o test-images/modern.webp "$CDN/webp/sample-100kb.webp"
curl -sL -o test-images/next-gen.avif "$CDN/avif/sample-100kb.avif"

# Edge cases
curl -sL -o test-images/tiny-icon.png "$CDN/png/sample-icon-32.png"
curl -sL -o test-images/large-4k.png "$CDN/png/sample-5mb.png"
curl -sL -o test-images/grayscale.png "$CDN/png/sample-grayscale.png"

Available: JPG · PNG · WebP · AVIF · SVG · GIF

Step 2: Test Resize (Node.js / sharp)

import sharp from 'sharp';
import { readFileSync, statSync } from 'fs';

describe('Image Resize', () => {
  it('resizes JPG to 800x600', async () => {
    const output = await sharp('test-images/photo-1mb.jpg')
      .resize(800, 600, { fit: 'cover' })
      .jpeg({ quality: 85 })
      .toBuffer();

    const meta = await sharp(output).metadata();
    expect(meta.width).toBe(800);
    expect(meta.height).toBe(600);
    expect(output.length).toBeLessThan(statSync('test-images/photo-1mb.jpg').size);
  });

  it('creates thumbnail from 4K image', async () => {
    const output = await sharp('test-images/large-4k.png')
      .resize(200, 200, { fit: 'inside' })
      .png()
      .toBuffer();

    const meta = await sharp(output).metadata();
    expect(meta.width).toBeLessThanOrEqual(200);
    expect(meta.height).toBeLessThanOrEqual(200);
  });
});

Step 3: Test Format Conversion

describe('Format Conversion', () => {
  it('converts JPG to WebP', async () => {
    const output = await sharp('test-images/photo-1mb.jpg')
      .webp({ quality: 80 })
      .toBuffer();

    const meta = await sharp(output).metadata();
    expect(meta.format).toBe('webp');
    // WebP should be smaller than JPG
    expect(output.length).toBeLessThan(
      statSync('test-images/photo-1mb.jpg').size
    );
  });

  it('converts JPG to AVIF', async () => {
    const output = await sharp('test-images/photo-1mb.jpg')
      .avif({ quality: 50 })
      .toBuffer();

    const meta = await sharp(output).metadata();
    expect(meta.format).toBe('heif'); // sharp reports AVIF as heif
  });

  it('converts PNG to WebP preserving transparency', async () => {
    const output = await sharp('test-images/logo-transparent.png')
      .webp({ quality: 90 })
      .toBuffer();

    const meta = await sharp(output).metadata();
    expect(meta.format).toBe('webp');
    expect(meta.hasAlpha).toBe(true); // Transparency preserved
  });
});

Step 4: Test Transparency Preservation

describe('Transparency', () => {
  it('preserves alpha channel in PNG → WebP', async () => {
    const output = await sharp('test-images/logo-transparent.png')
      .webp()
      .toBuffer();

    const { channels, hasAlpha } = await sharp(output).metadata();
    expect(hasAlpha).toBe(true);
    expect(channels).toBe(4); // RGBA
  });

  it('flattens transparency to white for JPG', async () => {
    const output = await sharp('test-images/logo-transparent.png')
      .flatten({ background: { r: 255, g: 255, b: 255 } })
      .jpeg()
      .toBuffer();

    const { channels, hasAlpha } = await sharp(output).metadata();
    expect(hasAlpha).toBe(false);
    expect(channels).toBe(3); // RGB only
  });
});

Step 5: Test Optimization Pipeline

describe('Optimization', () => {
  it('reduces file size by 50%+', async () => {
    const input = readFileSync('test-images/photo-5mb.jpg');
    const output = await sharp(input)
      .resize(1920, 1080, { fit: 'inside', withoutEnlargement: true })
      .jpeg({ quality: 80, mozjpeg: true })
      .toBuffer();

    const reduction = 1 - output.length / input.length;
    expect(reduction).toBeGreaterThan(0.5); // >50% reduction
  });

  it('strips EXIF metadata', async () => {
    const output = await sharp('test-images/photo-1mb.jpg')
      .rotate() // Auto-rotate based on EXIF
      .jpeg()
      .toBuffer();

    const meta = await sharp(output).metadata();
    expect(meta.orientation).toBeUndefined();
  });
});

Python (Pillow)

from PIL import Image
from pathlib import Path

def test_resize():
    img = Image.open('test-images/photo-1mb.jpg')
    resized = img.resize((800, 600), Image.LANCZOS)
    assert resized.size == (800, 600)

def test_transparency_preserved():
    img = Image.open('test-images/logo-transparent.png')
    assert img.mode == 'RGBA'
    webp_path = '/tmp/output.webp'
    img.save(webp_path, 'WEBP', quality=90)
    result = Image.open(webp_path)
    assert result.mode == 'RGBA'

def test_format_conversion():
    img = Image.open('test-images/photo-1mb.jpg')
    img.save('/tmp/output.webp', 'WEBP', quality=80)
    assert Path('/tmp/output.webp').stat().st_size < Path('test-images/photo-1mb.jpg').stat().st_size

Test Matrix

| Test | Input File | Operation | Verify | |------|-----------|-----------|--------| | Resize | 1MB JPG | 800×600 cover | Dimensions, smaller size | | Thumbnail | 5MB PNG | 200×200 inside | Max dimension ≤200 | | JPG→WebP | 1MB JPG | webp q80 | Format, smaller size | | JPG→AVIF | 1MB JPG | avif q50 | Format check | | PNG→WebP (alpha) | transparent PNG | webp q90 | hasAlpha=true | | PNG→JPG (flatten) | transparent PNG | flatten+jpeg | hasAlpha=false | | Optimize | 5MB JPG | resize+mozjpeg | >50% reduction | | Grayscale | grayscale PNG | Convert | channels=1 | | 32×32 icon | icon PNG | Resize up | Quality check |