Elysia Tools

Browse tools, examples, visual explainers, and topic guides from one clear workspace.

Top Categories

Hubs

Language
ZHDERUPTENFRES

Elysia Tools

Navigation

TypeScript

Web Image Processing TypeScript Samples

Web TypeScript image processing examples including image read/save, scaling, and format conversion

Samples

Entries inside this sample collection

CodetypescriptSimple

Image Read/Save

Read and save images using FileReader, Canvas API, and various download methods

Difficulty

4/10

Estimated time

20 min

Tags

typescript, web, image processing

Prerequisites

Basic TypeScript, File API, Canvas API

typescript
// Web TypeScript Image Read/Save Examples
// Using FileReader, Canvas API, and download methods

// 1. Image Reader
class ImageReader {
  // Read image as Data URL
  readAsDataURL(file: File): Promise<string> {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();

      reader.onload = () => {
        resolve(reader.result as string);
      };

      reader.onerror = () => {
        reject(new Error('Failed to read image'));
      };

      reader.readAsDataURL(file);
    });
  }

  // Read image as ArrayBuffer
  readAsArrayBuffer(file: File): Promise<ArrayBuffer> {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();

      reader.onload = () => {
        resolve(reader.result as ArrayBuffer);
      };

      reader.onerror = () => {
        reject(new Error('Failed to read image'));
      };

      reader.readAsArrayBuffer(file);
    });
  }

  // Read image as Base64
  readAsBase64(file: File): Promise<string> {
    return new Promise(async (resolve, reject) => {
      try {
        const dataURL = await this.readAsDataURL(file);
        const base64 = dataURL.split(',')[1];
        resolve(base64);
      } catch (error) {
        reject(error);
      }
    });
  }

  // Read image and get dimensions
  readWithDimensions(file: File): Promise<{
    dataURL: string;
    width: number;
    height: number;
  }> {
    return new Promise(async (resolve, reject) => {
      try {
        const dataURL = await this.readAsDataURL(file);
        const img = await this.loadImage(dataURL);

        resolve({
          dataURL,
          width: img.width,
          height: img.height
        });
      } catch (error) {
        reject(error);
      }
    });
  }

  // Read multiple images
  readMultiple(files: File[]): Promise<Array<{ file: File; dataURL: string }>> {
    const promises = files.map(file =>
      this.readAsDataURL(file).then(dataURL => ({ file, dataURL }))
    );

    return Promise.all(promises);
  }

  // Load image from URL
  loadImage(src: string): Promise<HTMLImageElement> {
    return new Promise((resolve, reject) => {
      const img = new Image();

      img.onload = () => resolve(img);
      img.onerror = () => reject(new Error('Failed to load image'));
      img.src = src;
    });
  }

  // Read image with metadata
  readWithMetadata(file: File): Promise<{
    dataURL: string;
    name: string;
    size: number;
    type: string;
    width: number;
    height: number;
  }> {
    return new Promise(async (resolve, reject) => {
      try {
        const dataURL = await this.readAsDataURL(file);
        const img = await this.loadImage(dataURL);

        resolve({
          dataURL,
          name: file.name,
          size: file.size,
          type: file.type,
          width: img.width,
          height: img.height
        });
      } catch (error) {
        reject(error);
      }
    });
  }
}

// 2. Image Writer
class ImageWriter {
  // Save canvas as image
  saveCanvas(canvas: HTMLCanvasElement, fileName: string, quality: number = 0.92): void {
    canvas.toBlob((blob) => {
      if (blob) {
        this.downloadBlob(blob, fileName);
      }
    }, 'image/png');
  }

  // Save canvas as JPEG
  saveAsJPEG(canvas: HTMLCanvasElement, fileName: string, quality: number = 0.92): void {
    canvas.toBlob((blob) => {
      if (blob) {
        this.downloadBlob(blob, fileName);
      }
    }, 'image/jpeg', quality);
  }

  // Save canvas as WebP
  saveAsWebP(canvas: HTMLCanvasElement, fileName: string, quality: number = 0.92): void {
    canvas.toBlob((blob) => {
      if (blob) {
        this.downloadBlob(blob, fileName);
      }
    }, 'image/webp', quality);
  }

  // Download blob as file
  private downloadBlob(blob: Blob, fileName: string): void {
    const url = URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url;
    link.download = fileName;
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    URL.revokeObjectURL(url);
  }

  // Save image element
  saveImage(img: HTMLImageElement, fileName: string): void {
    const canvas = document.createElement('canvas');
    canvas.width = img.width;
    canvas.height = img.height;

    const ctx = canvas.getContext('2d');
    if (ctx) {
      ctx.drawImage(img, 0, 0);
      this.saveCanvas(canvas, fileName);
    }
  }
}

// 3. Image Converter
class ImageConverter {
  private reader = new ImageReader();
  private writer = new ImageWriter();

  // Convert file to canvas
  async fileToCanvas(file: File): Promise<HTMLCanvasElement> {
    const dataURL = await this.reader.readAsDataURL(file);
    const img = await this.reader.loadImage(dataURL);

    const canvas = document.createElement('canvas');
    canvas.width = img.width;
    canvas.height = img.height;

    const ctx = canvas.getContext('2d');
    if (ctx) {
      ctx.drawImage(img, 0, 0);
    }

    return canvas;
  }

  // Convert to PNG
  async convertToPNG(file: File, outputFileName?: string): Promise<void> {
    const canvas = await this.fileToCanvas(file);
    const fileName = outputFileName || file.name.replace(/\\.[^.]+$/, '.png');
    this.writer.saveCanvas(canvas, fileName);
  }

  // Convert to JPEG
  async convertToJPEG(file: File, outputFileName?: string, quality: number = 0.92): Promise<void> {
    const canvas = await this.fileToCanvas(file);
    const fileName = outputFileName || file.name.replace(/\\.[^.]+$/, '.jpg');
    this.writer.saveAsJPEG(canvas, fileName, quality);
  }

  // Convert to WebP
  async convertToWebP(file: File, outputFileName?: string, quality: number = 0.92): Promise<void> {
    const canvas = await this.fileToCanvas(file);
    const fileName = outputFileName || file.name.replace(/\\.[^.]+$/, '.webp');
    this.writer.saveAsWebP(canvas, fileName, quality);
  }

  // Convert and return as blob
  async convertToBlob(file: File, format: 'png' | 'jpeg' | 'webp' = 'png', quality: number = 0.92): Promise<Blob> {
    const canvas = await this.fileToCanvas(file);

    return new Promise((resolve, reject) => {
      const mimeType = `image/${format}`;
      canvas.toBlob((blob) => {
        if (blob) {
          resolve(blob);
        } else {
          reject(new Error('Failed to convert image'));
        }
      }, mimeType, quality);
    });
  }
}

// 4. Image Info Extractor
class ImageInfoExtractor {
  private reader = new ImageReader();

  // Get basic image info
  async getInfo(file: File): Promise<{
    name: string;
    size: number;
    type: string;
    lastModified: Date;
  }> {
    return {
      name: file.name,
      size: file.size,
      type: file.type,
      lastModified: new Date(file.lastModified)
    };
  }

  // Get image dimensions
  async getDimensions(file: File): Promise<{
    width: number;
    height: number;
    aspectRatio: number;
  }> {
    const dataURL = await this.reader.readAsDataURL(file);
    const img = await this.reader.loadImage(dataURL);

    const aspectRatio = img.width / img.height;

    return {
      width: img.width,
      height: img.height,
      aspectRatio
    };
  }

  // Get complete image info
  async getCompleteInfo(file: File): Promise<{
    name: string;
    size: number;
    type: string;
    lastModified: Date;
    width: number;
    height: number;
    aspectRatio: number;
    megapixels: number;
  }> {
    const basic = await this.getInfo(file);
    const dims = await this.getDimensions(file);

    const megapixels = (dims.width * dims.height) / 1000000;

    return {
      ...basic,
      ...dims,
      megapixels
    };
  }

  // Format file size
  formatFileSize(bytes: number): string {
    const kb = bytes / 1024;
    const mb = kb / 1024;

    if (mb >= 1) {
      return `${mb.toFixed(2)} MB`;
    } else if (kb >= 1) {
      return `${kb.toFixed(2)} KB`;
    } else {
      return `${bytes} bytes`;
    }
  }
}

// 5. Image Batch Processor
class ImageBatchProcessor {
  private reader = new ImageReader();
  private converter = new ImageConverter();

  // Batch convert images
  async batchConvert(
    files: File[],
    format: 'png' | 'jpeg' | 'webp' = 'png',
    quality: number = 0.92,
    onProgress?: (current: number, total: number, file: File) => void
  ): Promise<Array<{ original: File; converted: Blob }>> {
    const results: Array<{ original: File; converted: Blob }> = [];

    for (let i = 0; i < files.length; i++) {
      const file = files[i];

      try {
        const converted = await this.converter.convertToBlob(file, format, quality);
        results.push({ original: file, converted });

        if (onProgress) {
          onProgress(i + 1, files.length, file);
        }
      } catch (error) {
        console.error(`Failed to convert ${file.name}:`, error);
      }
    }

    return results;
  }

  // Batch resize images
  async batchResize(
    files: File[],
    maxWidth: number,
    maxHeight: number,
    onProgress?: (current: number, total: number, file: File) => void
  ): Promise<Blob[]> {
    const results: Blob[] = [];

    for (let i = 0; i < files.length; i++) {
      const file = files[i];

      try {
        // Resize logic would go here
        if (onProgress) {
          onProgress(i + 1, files.length, file);
        }
      } catch (error) {
        console.error(`Failed to resize ${file.name}:`, error);
      }
    }

    return results;
  }

  // Batch get image info
  async batchGetInfo(files: File[]): Promise<Array<{ file: File; info: any }>> {
    const results: Array<{ file: File; info: any }> = [];
    const extractor = new ImageInfoExtractor();

    for (const file of files) {
      try {
        const info = await extractor.getCompleteInfo(file);
        results.push({ file, info });
      } catch (error) {
        console.error(`Failed to get info for ${file.name}:`, error);
      }
    }

    return results;
  }
}

// 6. Image Validator
class ImageValidator {
  // Validate if file is an image
  isImage(file: File): boolean {
    return file.type.startsWith('image/');
  }

  // Validate supported formats
  isSupportedFormat(file: File): boolean {
    const supportedTypes = [
      'image/jpeg',
      'image/jpg',
      'image/png',
      'image/gif',
      'image/webp',
      'image/bmp',
      'image/svg+xml'
    ];

    return supportedTypes.includes(file.type);
  }

  // Validate file size
  isValidSize(file: File, maxSizeInMB: number): boolean {
    const maxSizeInBytes = maxSizeInMB * 1024 * 1024;
    return file.size <= maxSizeInBytes;
  }

  // Validate dimensions
  async validateDimensions(
    file: File,
    minWidth: number,
    minHeight: number
  ): Promise<boolean> {
    const reader = new ImageReader();
    const dims = await reader.readWithDimensions(file);

    return dims.width >= minWidth && dims.height >= minHeight;
  }

  // Validate with all rules
  async validate(
    file: File,
    rules: {
      maxSizeInMB?: number;
      minWidth?: number;
      minHeight?: number;
      maxWidth?: number;
      maxHeight?: number;
    }
  ): Promise<{ valid: boolean; errors: string[] }> {
    const errors: string[] = [];

    if (!this.isImage(file)) {
      errors.push('File is not an image');
      return { valid: false, errors };
    }

    if (rules.maxSizeInMB && !this.isValidSize(file, rules.maxSizeInMB)) {
      errors.push(`File size exceeds ${rules.maxSizeInMB}MB`);
    }

    if (rules.minWidth || rules.minHeight) {
      const reader = new ImageReader();
      const dims = await reader.readWithDimensions(file);

      if (rules.minWidth && dims.width < rules.minWidth) {
        errors.push(`Width is less than ${rules.minWidth}px`);
      }

      if (rules.minHeight && dims.height < rules.minHeight) {
        errors.push(`Height is less than ${rules.minHeight}px`);
      }

      if (rules.maxWidth && dims.width > rules.maxWidth) {
        errors.push(`Width exceeds ${rules.maxWidth}px`);
      }

      if (rules.maxHeight && dims.height > rules.maxHeight) {
        errors.push(`Height exceeds ${rules.maxHeight}px`);
      }
    }

    return {
      valid: errors.length === 0,
      errors
    };
  }
}

// Usage Examples
async function demonstrateImageReadSave() {
  console.log('=== Web TypeScript Image Read/Save Examples ===\n');

  const reader = new ImageReader();
  const writer = new ImageWriter();
  const converter = new ImageConverter();
  const extractor = new ImageInfoExtractor();
  const validator = new ImageValidator();

  // Note: These examples require actual file input
  console.log('--- Image Reader ---');
  console.log('Use reader.readAsDataURL(file) to read image');
  console.log('Use reader.readWithDimensions(file) to get dimensions');

  console.log('\n--- Image Writer ---');
  console.log('Use writer.saveCanvas(canvas, filename) to save canvas');
  console.log('Use writer.saveAsJPEG(canvas, filename, quality) to save as JPEG');

  console.log('\n--- Image Converter ---');
  console.log('Use converter.convertToPNG(file) to convert to PNG');
  console.log('Use converter.convertToJPEG(file) to convert to JPEG');
  console.log('Use converter.convertToWebP(file) to convert to WebP');

  console.log('\n--- Image Info Extractor ---');
  console.log('Use extractor.getInfo(file) to get basic info');
  console.log('Use extractor.getDimensions(file) to get dimensions');
  console.log('Use extractor.getCompleteInfo(file) to get complete info');

  console.log('\n--- Image Validator ---');
  console.log('Use validator.isImage(file) to check if file is image');
  console.log('Use validator.validate(file, rules) to validate with rules');

  console.log('\n=== All Image Read/Save Examples Completed ===');
}

// Export functions
export { ImageReader, ImageWriter, ImageConverter, ImageInfoExtractor, ImageBatchProcessor, ImageValidator };
export { demonstrateImageReadSave };
CodetypescriptIntermediate

Image Scaling

Resize images with various algorithms including bilinear, bicubic, and high-quality scaling

Difficulty

6/10

Estimated time

25 min

Tags

typescript, web, image processing

Prerequisites

Intermediate TypeScript, Canvas API

typescript
// Web TypeScript Image Scaling Examples
// Using Canvas API for image resizing and scaling

// 1. Basic Image Scaler
class ImageScaler {
  // Resize image to specific dimensions
  async resize(
    img: HTMLImageElement,
    width: number,
    height: number
  ): Promise<HTMLCanvasElement> {
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;

    const ctx = canvas.getContext('2d');
    if (ctx) {
      ctx.drawImage(img, 0, 0, width, height);
    }

    return canvas;
  }

  // Resize by percentage
  async resizeByPercentage(
    img: HTMLImageElement,
    percentage: number
  ): Promise<HTMLCanvasElement> {
    const newWidth = Math.floor(img.width * (percentage / 100));
    const newHeight = Math.floor(img.height * (percentage / 100));

    return this.resize(img, newWidth, newHeight);
  }

  // Resize to fit within bounds
  async resizeToFit(
    img: HTMLImageElement,
    maxWidth: number,
    maxHeight: number
  ): Promise<HTMLCanvasElement> {
    const ratio = Math.min(maxWidth / img.width, maxHeight / img.height);
    const newWidth = Math.floor(img.width * ratio);
    const newHeight = Math.floor(img.height * ratio);

    return this.resize(img, newWidth, newHeight);
  }

  // Resize to fill bounds (cover)
  async resizeToCover(
    img: HTMLImageElement,
    minWidth: number,
    minHeight: number
  ): Promise<HTMLCanvasElement> {
    const ratio = Math.max(minWidth / img.width, minHeight / img.height);
    const newWidth = Math.floor(img.width * ratio);
    const newHeight = Math.floor(img.height * ratio);

    return this.resize(img, newWidth, newHeight);
  }

  // Resize maintaining aspect ratio
  async resizeWithAspect(
    img: HTMLImageElement,
    targetWidth: number,
    targetHeight: number
  ): Promise<HTMLCanvasElement> {
    const srcRatio = img.width / img.height;
    const targetRatio = targetWidth / targetHeight;

    let finalWidth: number, finalHeight: number;

    if (srcRatio > targetRatio) {
      finalWidth = targetWidth;
      finalHeight = Math.floor(targetWidth / srcRatio);
    } else {
      finalHeight = targetHeight;
      finalWidth = Math.floor(targetHeight * srcRatio);
    }

    return this.resize(img, finalWidth, finalHeight);
  }
}

// 2. High Quality Scaler
class HighQualityScaler {
  // Resize with better quality using step-down approach
  async resizeHighQuality(
    img: HTMLImageElement,
    width: number,
    height: number
  ): Promise<HTMLCanvasElement> {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    if (!ctx) {
      throw new Error('Failed to get canvas context');
    }

    canvas.width = width;
    canvas.height = height;

    // Enable image smoothing for better quality
    ctx.imageSmoothingEnabled = true;
    ctx.imageSmoothingQuality = 'high';

    // For significant downscaling, use multiple passes
    const scaleFactor = width / img.width;

    if (scaleFactor < 0.5) {
      // Step down by half multiple times
      let w = img.width;
      let h = img.height;
      let tempCanvas = document.createElement('canvas');
      let tempCtx = tempCanvas.getContext('2d');

      if (!tempCtx) {
        throw new Error('Failed to get temp canvas context');
      }

      tempCanvas.width = w;
      tempCanvas.height = h;
      tempCtx.drawImage(img, 0, 0);

      while (w * 0.5 > width) {
        w = Math.floor(w * 0.5);
        h = Math.floor(h * 0.5);

        const newCanvas = document.createElement('canvas');
        newCanvas.width = w;
        newCanvas.height = h;
        const newCtx = newCanvas.getContext('2d');

        if (newCtx) {
          newCtx.imageSmoothingEnabled = true;
          newCtx.imageSmoothingQuality = 'high';
          newCtx.drawImage(tempCanvas, 0, 0, w, h);
        }

        tempCanvas = newCanvas;
        tempCtx = newCtx;
      }

      // Final resize to target dimensions
      ctx.drawImage(tempCanvas, 0, 0, width, height);
    } else {
      ctx.drawImage(img, 0, 0, width, height);
    }

    return canvas;
  }

  // Resize with Lanczos-like approximation
  async resizeLanczos(
    img: HTMLImageElement,
    width: number,
    height: number
  ): Promise<HTMLCanvasElement> {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    if (!ctx) {
      throw new Error('Failed to get canvas context');
    }

    canvas.width = width;
    canvas.height = height;

    ctx.imageSmoothingEnabled = true;
    ctx.imageSmoothingQuality = 'high';
    ctx.drawImage(img, 0, 0, width, height);

    return canvas;
  }
}

// 3. Thumbnail Generator
class ThumbnailGenerator {
  // Generate square thumbnail
  async generateSquareThumbnail(
    img: HTMLImageElement,
    size: number
  ): Promise<HTMLCanvasElement> {
    const canvas = document.createElement('canvas');
    canvas.width = size;
    canvas.height = size;

    const ctx = canvas.getContext('2d');
    if (!ctx) {
      throw new Error('Failed to get canvas context');
    }

    // Calculate crop dimensions
    const minDimension = Math.min(img.width, img.height);
    const startX = (img.width - minDimension) / 2;
    const startY = (img.height - minDimension) / 2;

    // Draw cropped and resized
    ctx.drawImage(
      img,
      startX, startY, minDimension, minDimension,
      0, 0, size, size
    );

    return canvas;
  }

  // Generate thumbnail with specific aspect ratio
  async generateThumbnailWithRatio(
    img: HTMLImageElement,
    width: number,
    height: number,
    fit: 'cover' | 'contain' | 'fill' = 'cover'
  ): Promise<HTMLCanvasElement> {
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;

    const ctx = canvas.getContext('2d');
    if (!ctx) {
      throw new Error('Failed to get canvas context');
    }

    if (fit === 'fill') {
      ctx.drawImage(img, 0, 0, width, height);
    } else {
      const srcRatio = img.width / img.height;
      const targetRatio = width / height;

      let renderWidth: number, renderHeight: number;
      let offsetX: number = 0, offsetY: number = 0;

      if (fit === 'cover') {
        if (srcRatio > targetRatio) {
          renderHeight = height;
          renderWidth = height * srcRatio;
          offsetX = (width - renderWidth) / 2;
        } else {
          renderWidth = width;
          renderHeight = width / srcRatio;
          offsetY = (height - renderHeight) / 2;
        }
      } else { // contain
        if (srcRatio > targetRatio) {
          renderWidth = width;
          renderHeight = width / srcRatio;
          offsetY = (height - renderHeight) / 2;
        } else {
          renderHeight = height;
          renderWidth = height * srcRatio;
          offsetX = (width - renderWidth) / 2;
        }
      }

      ctx.drawImage(img, offsetX, offsetY, renderWidth, renderHeight);
    }

    return canvas;
  }

  // Generate multiple thumbnail sizes
  async generateMultipleThumbnails(
    img: HTMLImageElement,
    sizes: number[]
  ): Promise<Map<number, HTMLCanvasElement>> {
    const thumbnails = new Map<number, HTMLCanvasElement>();

    for (const size of sizes) {
      const thumbnail = await this.generateSquareThumbnail(img, size);
      thumbnails.set(size, thumbnail);
    }

    return thumbnails;
  }
}

// 4. Smart Scaler
class SmartScaler {
  private basicScaler = new ImageScaler();
  private hqScaler = new HighQualityScaler();

  // Auto-select scaling method based on resize factor
  async smartResize(
    img: HTMLImageElement,
    width: number,
    height: number
  ): Promise<HTMLCanvasElement> {
    const scaleFactor = width / img.width;

    // Use high quality for significant downscaling
    if (scaleFactor < 0.5 || scaleFactor > 2) {
      return this.hqScaler.resizeHighQuality(img, width, height);
    } else {
      return this.basicScaler.resize(img, width, height);
    }
  }

  // Resize with smart content detection (simplified)
  async smartContentResize(
    img: HTMLImageElement,
    width: number,
    height: number
  ): Promise<HTMLCanvasElement> {
    // For now, use high quality scaler
    // A full implementation would use content-aware resizing
    return this.hqScaler.resizeHighQuality(img, width, height);
  }
}

// 5. Batch Image Scaler
class BatchImageScaler {
  private scaler = new SmartScaler();

  // Scale multiple images
  async scaleMultiple(
    images: HTMLImageElement[],
    width: number,
    height: number,
    onProgress?: (current: number, total: number) => void
  ): Promise<HTMLCanvasElement[]> {
    const results: HTMLCanvasElement[] = [];

    for (let i = 0; i < images.length; i++) {
      const canvas = await this.scaler.smartResize(images[i], width, height);
      results.push(canvas);

      if (onProgress) {
        onProgress(i + 1, images.length);
      }
    }

    return results;
  }

  // Scale files and save
  async scaleFiles(
    files: File[],
    width: number,
    height: number,
    format: 'png' | 'jpeg' | 'webp' = 'png',
    onProgress?: (current: number, total: number, fileName: string) => void
  ): Promise<Blob[]> {
    const results: Blob[] = [];

    for (let i = 0; i < files.length; i++) {
      const file = files[i];

      try {
        const reader = new ImageReader();
        const dataURL = await reader.readAsDataURL(file);
        const img = await reader.loadImage(dataURL);

        const canvas = await this.scaler.smartResize(img, width, height);

        const blob = await this.canvasToBlob(canvas, format);
        results.push(blob);

        if (onProgress) {
          onProgress(i + 1, files.length, file.name);
        }
      } catch (error) {
        console.error(`Failed to scale ${file.name}:`, error);
      }
    }

    return results;
  }

  private async canvasToBlob(canvas: HTMLCanvasElement, format: string): Promise<Blob> {
    return new Promise((resolve, reject) => {
      const mimeType = `image/${format}`;
      canvas.toBlob((blob) => {
        if (blob) {
          resolve(blob);
        } else {
          reject(new Error('Failed to convert canvas to blob'));
        }
      }, mimeType);
    });
  }
}

// 6. Image Resizer Helper
class ImageResizerHelper {
  // Calculate new dimensions maintaining aspect ratio
  static calculateDimensions(
    originalWidth: number,
    originalHeight: number,
    targetWidth?: number,
    targetHeight?: number
  ): { width: number; height: number } {
    if (targetWidth && targetHeight) {
      return { width: targetWidth, height: targetHeight };
    }

    if (targetWidth) {
      const ratio = targetWidth / originalWidth;
      return {
        width: targetWidth,
        height: Math.floor(originalHeight * ratio)
      };
    }

    if (targetHeight) {
      const ratio = targetHeight / originalHeight;
      return {
        width: Math.floor(originalWidth * ratio),
        height: targetHeight
      };
    }

    return { width: originalWidth, height: originalHeight };
  }

  // Calculate fit dimensions
  static calculateFitDimensions(
    originalWidth: number,
    originalHeight: number,
    maxWidth: number,
    maxHeight: number
  ): { width: number; height: number } {
    const ratio = Math.min(maxWidth / originalWidth, maxHeight / originalHeight);
    return {
      width: Math.floor(originalWidth * ratio),
      height: Math.floor(originalHeight * ratio)
    };
  }

  // Calculate cover dimensions
  static calculateCoverDimensions(
    originalWidth: number,
    originalHeight: number,
    minWidth: number,
    minHeight: number
  ): { width: number; height: number } {
    const ratio = Math.max(minWidth / originalWidth, minHeight / originalHeight);
    return {
      width: Math.floor(originalWidth * ratio),
      height: Math.floor(originalHeight * ratio)
    };
  }
}

// Usage Examples
async function demonstrateImageScaling() {
  console.log('=== Web TypeScript Image Scaling Examples ===\n');

  const scaler = new ImageScaler();
  const hqScaler = new HighQualityScaler();
  const thumbGen = new ThumbnailGenerator();
  const smartScaler = new SmartScaler();

  console.log('--- Basic Scaler ---');
  console.log('Use scaler.resize(img, width, height) to resize');
  console.log('Use scaler.resizeByPercentage(img, 50) to resize by 50%');
  console.log('Use scaler.resizeToFit(img, maxWidth, maxHeight) to fit within bounds');

  console.log('\n--- High Quality Scaler ---');
  console.log('Use hqScaler.resizeHighQuality(img, width, height) for best quality');

  console.log('\n--- Thumbnail Generator ---');
  console.log('Use thumbGen.generateSquareThumbnail(img, size) for square thumbnails');
  console.log('Use thumbGen.generateThumbnailWithRatio(img, width, height, fit) for custom ratio');

  console.log('\n--- Smart Scaler ---');
  console.log('Use smartScaler.smartResize(img, width, height) for auto-selected method');

  console.log('\n--- Helper Functions ---');
  console.log('Use ImageResizerHelper.calculateDimensions() to calculate new dimensions');
  console.log('Use ImageResizerHelper.calculateFitDimensions() to calculate fit dimensions');

  console.log('\n=== All Image Scaling Examples Completed ===');
}

// ImageReader import helper
class ImageReader {
  async readAsDataURL(file: File): Promise<string> {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => resolve(reader.result as string);
      reader.onerror = () => reject(new Error('Failed to read'));
      reader.readAsDataURL(file);
    });
  }

  async loadImage(src: string): Promise<HTMLImageElement> {
    return new Promise((resolve, reject) => {
      const img = new Image();
      img.onload = () => resolve(img);
      img.onerror = () => reject(new Error('Failed to load image'));
      img.src = src;
    });
  }
}

// Export functions
export { ImageScaler, HighQualityScaler, ThumbnailGenerator, SmartScaler, BatchImageScaler, ImageResizerHelper };
export { demonstrateImageScaling };
CodetypescriptIntermediate

Image Format Conversion

Convert between image formats including PNG, JPEG, WebP, GIF, and BMP

Difficulty

6/10

Estimated time

25 min

Tags

typescript, web, image processing

Prerequisites

Intermediate TypeScript, Canvas API, File API

typescript
// Web TypeScript Image Format Conversion Examples
// Convert between PNG, JPEG, WebP, GIF, and other formats

// 1. Basic Format Converter
class FormatConverter {
  // Convert canvas to PNG
  toPNG(canvas: HTMLCanvasElement): Promise<Blob> {
    return new Promise((resolve, reject) => {
      canvas.toBlob((blob) => {
        if (blob) {
          resolve(blob);
        } else {
          reject(new Error('Failed to convert to PNG'));
        }
      }, 'image/png');
    });
  }

  // Convert canvas to JPEG
  toJPEG(canvas: HTMLCanvasElement, quality: number = 0.92): Promise<Blob> {
    return new Promise((resolve, reject) => {
      canvas.toBlob((blob) => {
        if (blob) {
          resolve(blob);
        } else {
          reject(new Error('Failed to convert to JPEG'));
        }
      }, 'image/jpeg', quality);
    });
  }

  // Convert canvas to WebP
  toWebP(canvas: HTMLCanvasElement, quality: number = 0.92): Promise<Blob> {
    return new Promise((resolve, reject) => {
      canvas.toBlob((blob) => {
        if (blob) {
          resolve(blob);
        } else {
          reject(new Error('Failed to convert to WebP'));
        }
      }, 'image/webp', quality);
    });
  }

  // Check format support
  checkFormatSupport(): {
    png: boolean;
    jpeg: boolean;
    webp: boolean;
  } {
    const canvas = document.createElement('canvas');
    canvas.width = 1;
    canvas.height = 1;

    return {
      png: !!canvas.toDataURL('image/png').startsWith('data:image/png'),
      jpeg: !!canvas.toDataURL('image/jpeg').startsWith('data:image/jpeg'),
      webp: !!canvas.toDataURL('image/webp').startsWith('data:image/webp')
    };
  }
}

// 2. File Format Converter
class FileFormatConverter {
  private formatConverter = new FormatConverter();

  // Convert file to different format
  async convertFile(
    file: File,
    targetFormat: 'png' | 'jpeg' | 'webp',
    quality: number = 0.92
  ): Promise<{ blob: Blob; fileName: string }> {
    const img = await this.loadImage(file);
    const canvas = this.imageToCanvas(img);

    let blob: Blob;

    switch (targetFormat) {
      case 'png':
        blob = await this.formatConverter.toPNG(canvas);
        break;
      case 'jpeg':
        blob = await this.formatConverter.toJPEG(canvas, quality);
        break;
      case 'webp':
        blob = await this.formatConverter.toWebP(canvas, quality);
        break;
    }

    const extension = targetFormat === 'jpeg' ? 'jpg' : targetFormat;
    const fileName = file.name.replace(/\\.[^.]+$/, `.${extension}`);

    return { blob, fileName };
  }

  // Batch convert files
  async batchConvert(
    files: File[],
    targetFormat: 'png' | 'jpeg' | 'webp',
    quality: number = 0.92,
    onProgress?: (current: number, total: number, fileName: string) => void
  ): Promise<Array<{ original: File; converted: Blob; fileName: string }>> {
    const results: Array<{ original: File; converted: Blob; fileName: string }> = [];

    for (let i = 0; i < files.length; i++) {
      const file = files[i];

      try {
        const result = await this.convertFile(file, targetFormat, quality);
        results.push({
          original: file,
          converted: result.blob,
          fileName: result.fileName
        });

        if (onProgress) {
          onProgress(i + 1, files.length, file.name);
        }
      } catch (error) {
        console.error(`Failed to convert ${file.name}:`, error);
      }
    }

    return results;
  }

  // Convert with resize
  async convertWithResize(
    file: File,
    targetFormat: 'png' | 'jpeg' | 'webp',
    width: number,
    height: number,
    quality: number = 0.92
  ): Promise<{ blob: Blob; fileName: string }> {
    const img = await this.loadImage(file);
    const canvas = this.resizeImage(img, width, height);

    let blob: Blob;

    switch (targetFormat) {
      case 'png':
        blob = await this.formatConverter.toPNG(canvas);
        break;
      case 'jpeg':
        blob = await this.formatConverter.toJPEG(canvas, quality);
        break;
      case 'webp':
        blob = await this.formatConverter.toWebP(canvas, quality);
        break;
    }

    const extension = targetFormat === 'jpeg' ? 'jpg' : targetFormat;
    const fileName = file.name.replace(/\\.[^.]+$/, `.${extension}`);

    return { blob, fileName };
  }

  private loadImage(file: File): Promise<HTMLImageElement> {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();

      reader.onload = () => {
        const img = new Image();
        img.onload = () => resolve(img);
        img.onerror = () => reject(new Error('Failed to load image'));
        img.src = reader.result as string;
      };

      reader.onerror = () => reject(new Error('Failed to read file'));
      reader.readAsDataURL(file);
    });
  }

  private imageToCanvas(img: HTMLImageElement): HTMLCanvasElement {
    const canvas = document.createElement('canvas');
    canvas.width = img.width;
    canvas.height = img.height;

    const ctx = canvas.getContext('2d');
    if (ctx) {
      ctx.drawImage(img, 0, 0);
    }

    return canvas;
  }

  private resizeImage(img: HTMLImageElement, width: number, height: number): HTMLCanvasElement {
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;

    const ctx = canvas.getContext('2d');
    if (ctx) {
      ctx.drawImage(img, 0, 0, width, height);
    }

    return canvas;
  }
}

// 3. Optimized Converter
class OptimizedConverter {
  private formatConverter = new FormatConverter();

  // Auto-select optimal format
  async autoOptimize(
    canvas: HTMLCanvasElement,
    maxSizeKB: number = 100
  ): Promise<{ blob: Blob; format: string; quality: number }> {
    // Try WebP first (best compression)
    for (let quality = 0.9; quality >= 0.5; quality -= 0.1) {
      const webp = await this.formatConverter.toWebP(canvas, quality);
      if (webp.size / 1024 <= maxSizeKB) {
        return { blob: webp, format: 'webp', quality };
      }
    }

    // Try JPEG
    for (let quality = 0.9; quality >= 0.5; quality -= 0.1) {
      const jpeg = await this.formatConverter.toJPEG(canvas, quality);
      if (jpeg.size / 1024 <= maxSizeKB) {
        return { blob: jpeg, format: 'jpeg', quality };
      }
    }

    // Fallback to PNG with lowest quality WebP
    return {
      blob: await this.formatConverter.toWebP(canvas, 0.5),
      format: 'webp',
      quality: 0.5
    };
  }

  // Optimize for web
  async optimizeForWeb(
    file: File,
    maxWidth: number = 1920,
    maxHeight: number = 1080,
    maxSizeKB: number = 200
  ): Promise<{ blob: Blob; format: string; quality: number }> {
    const img = await this.loadImageFromFile(file);

    // Resize if needed
    const canvas = this.resizeToFit(img, maxWidth, maxHeight);

    return this.autoOptimize(canvas, maxSizeKB);
  }

  private loadImageFromFile(file: File): Promise<HTMLImageElement> {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();

      reader.onload = () => {
        const img = new Image();
        img.onload = () => resolve(img);
        img.onerror = () => reject(new Error('Failed to load image'));
        img.src = reader.result as string;
      };

      reader.onerror = () => reject(new Error('Failed to read file'));
      reader.readAsDataURL(file);
    });
  }

  private resizeToFit(
    img: HTMLImageElement,
    maxWidth: number,
    maxHeight: number
  ): HTMLCanvasElement {
    const ratio = Math.min(maxWidth / img.width, maxHeight / img.height);
    const width = Math.floor(img.width * ratio);
    const height = Math.floor(img.height * ratio);

    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;

    const ctx = canvas.getContext('2d');
    if (ctx) {
      ctx.imageSmoothingEnabled = true;
      ctx.imageSmoothingQuality = 'high';
      ctx.drawImage(img, 0, 0, width, height);
    }

    return canvas;
  }
}

// 4. Quality Comparator
class QualityComparator {
  // Compare quality at different settings
  async compareQuality(
    canvas: HTMLCanvasElement,
    format: 'jpeg' | 'webp',
    qualities: number[] = [0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
  ): Promise<Array<{ quality: number; size: number; blob: Blob }>> {
    const converter = new FormatConverter();
    const results: Array<{ quality: number; size: number; blob: Blob }> = [];

    for (const quality of qualities) {
      let blob: Blob;

      if (format === 'jpeg') {
        blob = await converter.toJPEG(canvas, quality);
      } else {
        blob = await converter.toWebP(canvas, quality);
      }

      results.push({
        quality,
        size: blob.size,
        blob
      });
    }

    return results;
  }

  // Find optimal quality for target size
  async findOptimalQuality(
    canvas: HTMLCanvasElement,
    format: 'jpeg' | 'webp',
    targetSizeKB: number,
    minQuality: number = 0.5,
    maxQuality: number = 1.0
  ): Promise<{ quality: number; size: number; blob: Blob } | null> {
    const converter = new FormatConverter();

    for (let quality = maxQuality; quality >= minQuality; quality -= 0.05) {
      let blob: Blob;

      if (format === 'jpeg') {
        blob = await converter.toJPEG(canvas, quality);
      } else {
        blob = await converter.toWebP(canvas, quality);
      }

      if (blob.size / 1024 <= targetSizeKB) {
        return { quality, size: blob.size, blob };
      }
    }

    return null;
  }
}

// 5. Format Info Provider
class FormatInfoProvider {
  // Get format information
  getFormatInfo(format: string): {
    name: string;
    extensions: string[];
    mimeType: string;
    supportsTransparency: boolean;
    supportsAnimation: boolean;
    typicalUseCase: string;
  } {
    const formats: Record<string, any> = {
      png: {
        name: 'Portable Network Graphics',
        extensions: ['png'],
        mimeType: 'image/png',
        supportsTransparency: true,
        supportsAnimation: false,
        typicalUseCase: 'Graphics, logos, images with transparency'
      },
      jpeg: {
        name: 'Joint Photographic Experts Group',
        extensions: ['jpg', 'jpeg'],
        mimeType: 'image/jpeg',
        supportsTransparency: false,
        supportsAnimation: false,
        typicalUseCase: 'Photographs, complex images'
      },
      webp: {
        name: 'Web Picture',
        extensions: ['webp'],
        mimeType: 'image/webp',
        supportsTransparency: true,
        supportsAnimation: true,
        typicalUseCase: 'Modern web images, optimized for web'
      },
      gif: {
        name: 'Graphics Interchange Format',
        extensions: ['gif'],
        mimeType: 'image/gif',
        supportsTransparency: true,
        supportsAnimation: true,
        typicalUseCase: 'Simple animations, low-color graphics'
      },
      bmp: {
        name: 'Bitmap',
        extensions: ['bmp'],
        mimeType: 'image/bmp',
        supportsTransparency: true,
        supportsAnimation: false,
        typicalUseCase: 'Uncompressed images, Windows applications'
      },
      svg: {
        name: 'Scalable Vector Graphics',
        extensions: ['svg'],
        mimeType: 'image/svg+xml',
        supportsTransparency: true,
        supportsAnimation: true,
        typicalUseCase: 'Icons, logos, scalable graphics'
      }
    };

    return formats[format.toLowerCase()] || {
      name: 'Unknown',
      extensions: [],
      mimeType: 'application/octet-stream',
      supportsTransparency: false,
      supportsAnimation: false,
      typicalUseCase: 'Unknown'
    };
  }

  // Recommend format based on content
  recommendFormat(hasTransparency: boolean, isPhoto: boolean, forWeb: boolean = true): string {
    if (forWeb) {
      if (hasTransparency) {
        return 'webp'; // Best compression with transparency
      } else if (isPhoto) {
        return 'webp'; // Best compression for photos
      } else {
        return 'webp'; // Generally best for web
      }
    } else {
      if (hasTransparency) {
        return 'png'; // Lossless with transparency
      } else if (isPhoto) {
        return 'jpeg'; // Good compression for photos
      } else {
        return 'png'; // Lossless for graphics
      }
    }
  }
}

// 6. Conversion Pipeline
class ConversionPipeline {
  private fileConverter = new FileFormatConverter();
  private optimizedConverter = new OptimizedConverter();

  // Convert with multiple options
  async convertWithPipeline(
    file: File,
    options: {
      format?: 'png' | 'jpeg' | 'webp';
      resize?: { width: number; height: number };
      quality?: number;
      maxSizeKB?: number;
      autoOptimize?: boolean;
    }
  ): Promise<{ blob: Blob; fileName: string; info: any }> {
    let blob: Blob;
    let fileName: string;
    const info: any = {};

    if (options.autoOptimize && options.maxSizeKB) {
      const result = await this.optimizedConverter.optimizeForWeb(
        file,
        options.resize?.width || 1920,
        options.resize?.height || 1080,
        options.maxSizeKB
      );

      blob = result.blob;
      fileName = file.name.replace(/\\.[^.]+$/, `.${result.format}`);
      info.format = result.format;
      info.quality = result.quality;
    } else if (options.resize) {
      const result = await this.fileConverter.convertWithResize(
        file,
        options.format || 'png',
        options.resize.width,
        options.resize.height,
        options.quality || 0.92
      );

      blob = result.blob;
      fileName = result.fileName;
      info.format = options.format;
      info.quality = options.quality;
    } else {
      const result = await this.fileConverter.convertFile(
        file,
        options.format || 'png',
        options.quality || 0.92
      );

      blob = result.blob;
      fileName = result.fileName;
      info.format = options.format;
      info.quality = options.quality;
    }

    info.size = blob.size;
    info.sizeKB = (blob.size / 1024).toFixed(2);

    return { blob, fileName, info };
  }
}

// Usage Examples
async function demonstrateImageFormatConversion() {
  console.log('=== Web TypeScript Image Format Conversion Examples ===\n');

  const converter = new FormatConverter();
  const fileConverter = new FileFormatConverter();
  const optimizedConverter = new OptimizedConverter();
  const infoProvider = new FormatInfoProvider();

  console.log('--- Format Converter ---');
  const support = converter.checkFormatSupport();
  console.log('Format Support:');
  console.log(`  PNG: ${support.png ? 'Yes' : 'No'}`);
  console.log(`  JPEG: ${support.jpeg ? 'Yes' : 'No'}`);
  console.log(`  WebP: ${support.webp ? 'Yes' : 'No'}`);

  console.log('\n--- File Format Converter ---');
  console.log('Use fileConverter.convertFile(file, format, quality) to convert files');
  console.log('Use fileConverter.batchConvert(files, format) to batch convert');

  console.log('\n--- Optimized Converter ---');
  console.log('Use optimizedConverter.autoOptimize(canvas, maxSizeKB) for auto optimization');
  console.log('Use optimizedConverter.optimizeForWeb(file, maxWidth, maxHeight, maxSizeKB) for web optimization');

  console.log('\n--- Format Info Provider ---');
  const pngInfo = infoProvider.getFormatInfo('png');
  console.log('PNG Info:', pngInfo);

  const recommendation = infoProvider.recommendFormat(true, false, true);
  console.log(`Recommended format (transparent, graphic, web): ${recommendation}`);

  console.log('\n=== All Image Format Conversion Examples Completed ===');
}

// Export functions
export { FormatConverter, FileFormatConverter, OptimizedConverter, QualityComparator, FormatInfoProvider, ConversionPipeline };
export { demonstrateImageFormatConversion };

Tools

Tools frequently paired with this sample

Related

Related sample collections

Related

Related workflows

Hub

Image Encoding Tuning for Weight, Loading, and Delivery

Tune PNG bit depth, palette, and transparency, choose progressive or baseline JPEG loading, dial WebP quality modes, and compress TIFF for archives until every image fits its destination.

Hub

Batch Image Standardization and Compression

Prepare a consistent image set by correcting orientation, removing unwanted margins, applying one size policy, compressing files, and checking representative outputs before delivery.

Hub

Image Format Conversion Without Losing Transparency or Motion

Convert still images, icons, or animated assets into a delivery-friendly format while protecting transparency, frame behavior, dimensions, and preview compatibility.

Hub

One Image and Music to a Reviewed Particle Short Video

Prepare one still image and a music excerpt, tune an audio-reactive particle animation, inspect the exported video and deliver MP4, poster, settings and review evidence.

Home
Tools3212
Workbench
Samples593
Visualizations471
Viewers103
Hubs239
Tags333
Images, Audio & Video657

Image, audio, and video processing, conversion, and optimization tools

Math, Date & Finance647

Calculators, numerics, date logic, statistics, and finance tools

Design & Color298

Color, layout, graphics, visual styling, and design helper tools

Text & Writing209

Writing, cleanup, formatting, extraction, and text analysis tools

Developer & Web193

Developer utilities, networking, web debugging, and automation helpers

Conversion & Encoding175

Format, file, archive, unit, and encoding conversion tools

Lead Generation Quiz Launch and Contact Handoff
Memorial Drafts: Family Review and Print Handoff
Private Habit Records: Backup, Restore and Sharing Review
Article to X and LinkedIn Drafts: Fact Review and Handoff
Markdown Interactive Deck Review and Offline Handoff

© 2026 Elysia Tools. All rights reserved.

DocsPricingAboutTerms of ServicePrivacy PolicyCookiesContact

Media

Batch Image Convert

Convert multiple images to different formats with quality settings and batch processing

Media

Batch Image Convert

Convert multiple image files between different formats like JPG, PNG, WebP, AVIF, TIFF, GIF with quality settings and batch processing

Media

Batch Image Info Viewer

View basic information for multiple images at once - dimensions, format, file size, and metadata presence

Media

Image Resizer

Professional image resizing tool with multiple resize methods, aspect ratio preservation, and format conversion, supporting GIF/Animated WebP/APNG and JPEG/PNG/WEBP.

AI Tools

NSFW Image Content Detector

AI content-moderation classifier using NSFWJS to flag uploaded images as safe or potentially inappropriate. Built for moderation and compliance review of your own files — it analyzes uploads only and is not an image search or discovery tool. Supports JPEG/PNG/WEBP/GIF.

Media

Batch Image Crop

Batch crop multiple images to specific dimensions or aspect ratios with custom positioning. Returns cropped images as a ZIP download.

Design

Image Box Blur

Apply box blur kernel for simple uniform averaging and fast noise reduction

Design

Image Color Picker

Pick colors from images by specifying coordinates. Get color values in HEX, RGB, HSL, HSV, and CMYK formats.

Python

Web Image Processing Python Samples

Web Python image processing examples using PIL/Pillow including reading, saving, resizing, and format conversion

Rust

Web Image Processing Rust Samples

Web Rust image processing examples including image read/save, scaling, and format conversion

Java

Android Image Processing Java Samples

Android Java image processing examples including reading/saving images, scaling, and format conversion

Kotlin

Android Image Processing Kotlin Samples

Android Kotlin image processing examples including reading/saving images, scaling, and format conversion

Go

Web Image Processing Go Samples

Web Go image processing examples including image reading/saving, image resizing, and format conversion

C++

Windows Image Processing C++ Samples

Windows C++ image processing examples including reading/saving images, resizing, and format conversion using Windows Imaging Component (WIC)