houser-js-utils
Version:
A comprehensive collection of TypeScript utility functions for common development tasks including array manipulation, string processing, date handling, random number generation, validation, and much more.
1 lines • 32 kB
Source Map (JSON)
{"version":3,"file":"ImageUtils.mjs","sources":["../src/ImageUtils.ts"],"sourcesContent":["/**\n * @module ImageUtils\n * @description A comprehensive collection of utility functions for image manipulation, processing, and analysis.\n * Supports image format conversion, resizing, cropping, compression, metadata extraction, and various image effects.\n * @example\n * ```typescript\n * import { ImageUtils } from 'houser-js-utils';\n *\n * // Convert base64 to file\n * const file = await ImageUtils.convertBase64ToFile(base64String, 'image.jpg');\n *\n * // Resize image with quality settings\n * const resized = await ImageUtils.resizeImage(file, { maxWidth: 800, quality: 0.8 });\n *\n * // Get image metadata\n * const metadata = await ImageUtils.getImageMetadata(file);\n * ```\n */\n\n/**\n * Regular expression for validating base64 image data URLs\n * Matches data URLs for PNG, JPG, JPEG, GIF, SVG, and WebP images\n */\nconst base64RegEx = /^data:image\\/(png|jpg|jpeg|gif|svg|webp);base64,/;\n\n/**\n * Supported image formats for conversion and processing\n */\ntype ImageFormat = \"jpeg\" | \"png\" | \"webp\" | \"gif\";\n\n/**\n * Options for image resizing operations\n */\ninterface ImageResizeOptions {\n /** Maximum width of the resized image */\n maxWidth?: number;\n /** Maximum height of the resized image */\n maxHeight?: number;\n /** Quality of the output image (0-1) */\n quality?: number;\n /** Output format of the resized image */\n format?: ImageFormat;\n}\n\n/**\n * Metadata about an image file\n */\ninterface ImageMetadata {\n /** Width of the image in pixels */\n width: number;\n /** Height of the image in pixels */\n height: number;\n /** MIME type of the image */\n type: string;\n /** Size of the image file in bytes */\n size: number;\n}\n\n/**\n * Dimensions for a scaled image\n */\ninterface ScaledDimensions {\n /** Scaled width in pixels */\n width: number;\n /** Scaled height in pixels */\n height: number;\n}\n\nexport const ImageUtils = {\n /**\n * Applies a grayscale filter to an image by converting all pixels to their average RGB value.\n * @param file - The image file to convert to grayscale\n * @returns Promise resolving to the grayscale image as a Blob\n * @example\n * ```typescript\n * const grayscaleImage = await ImageUtils.applyGrayscale(imageFile);\n * // Use the grayscale blob as needed\n * ```\n */\n async applyGrayscale(file: File): Promise<Blob> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => {\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n reject(new Error(\"Could not get canvas context\"));\n return;\n }\n\n canvas.width = img.width;\n canvas.height = img.height;\n ctx.drawImage(img, 0, 0);\n\n const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n const data = imageData.data;\n\n for (let i = 0; i < data.length; i += 4) {\n const avg = (data[i] + data[i + 1] + data[i + 2]) / 3;\n data[i] = avg; // red\n data[i + 1] = avg; // green\n data[i + 2] = avg; // blue\n }\n\n ctx.putImageData(imageData, 0, 0);\n canvas.toBlob((blob) => {\n if (blob) resolve(blob);\n else reject(new Error(\"Failed to create blob\"));\n }, file.type);\n };\n img.onerror = reject;\n img.src = URL.createObjectURL(file);\n });\n },\n\n /**\n * Calculates the aspect ratio of an image from its dimensions.\n * @param width - The width of the image in pixels\n * @param height - The height of the image in pixels\n * @returns The aspect ratio as a decimal number (width/height)\n * @example\n * ```typescript\n * const ratio = ImageUtils.calculateAspectRatio(1920, 1080); // Returns 1.777...\n * const isWidescreen = ratio > 1.5; // true for 16:9 ratio\n * ```\n */\n calculateAspectRatio(width: number, height: number): number {\n return width / height;\n },\n\n /**\n * Converts a base64 string to a Blob object.\n * @param base64 - The base64 string to convert (without data URL prefix)\n * @param type - The MIME type of the image (default: \"image/jpeg\")\n * @returns Promise resolving to a Blob object\n * @example\n * ```typescript\n * const blob = await ImageUtils.base64ToBlob(base64String, 'image/png');\n * const url = URL.createObjectURL(blob);\n * ```\n */\n async base64ToBlob(\n base64: string,\n type: string = \"image/jpeg\"\n ): Promise<Blob> {\n const response = await fetch(`data:${type};base64,${base64}`);\n return response.blob();\n },\n\n /**\n * Converts a Blob to a base64 string (without data URL prefix).\n * @param blob - The Blob to convert\n * @returns Promise resolving to base64 string\n * @example\n * ```typescript\n * const base64 = await ImageUtils.blobToBase64(imageBlob);\n * console.log('data:image/jpeg;base64,' + base64); // Full data URL\n * ```\n */\n async blobToBase64(blob: Blob): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => {\n const base64 = reader.result as string;\n resolve(base64.split(\",\")[1]);\n };\n reader.onerror = reject;\n reader.readAsDataURL(blob);\n });\n },\n\n /**\n * Compresses an image file by reducing its quality while maintaining dimensions.\n * @param file - The image file to compress\n * @param quality - Compression quality from 0 (lowest) to 1 (highest, default: 0.7)\n * @returns Promise resolving to the compressed image as a Blob\n * @example\n * ```typescript\n * const compressed = await ImageUtils.compressImage(largeImage, 0.5);\n * console.log(`Original: ${largeImage.size} bytes, Compressed: ${compressed.size} bytes`);\n * ```\n */\n async compressImage(file: File, quality: number = 0.7): Promise<Blob> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => {\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n reject(new Error(\"Could not get canvas context\"));\n return;\n }\n\n canvas.width = img.width;\n canvas.height = img.height;\n ctx.drawImage(img, 0, 0);\n\n canvas.toBlob(\n (blob) => {\n if (blob) resolve(blob);\n else reject(new Error(\"Failed to create blob\"));\n },\n file.type,\n quality\n );\n };\n img.onerror = reject;\n img.src = URL.createObjectURL(file);\n });\n },\n\n /**\n * Converts a base64 data URL string to a File object.\n * @param base64 - The base64 data URL string (must include data:image/... prefix)\n * @param filename - The name for the resulting file\n * @returns Promise resolving to File object, or null if base64 is invalid\n * @example\n * ```typescript\n * const file = await ImageUtils.convertBase64ToFile(\n * 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==',\n * 'pixel.png'\n * );\n * ```\n */\n convertBase64ToFile(base64: string, filename: string): Promise<File> | null {\n if (!base64RegEx.test(base64)) return null;\n return this.base64ToBlob(base64).then((blob) => new File([blob], filename));\n },\n\n /**\n * Creates a thumbnail image with specified maximum dimensions.\n * @param file - The image file to create a thumbnail from\n * @param maxSize - Maximum size in pixels for the longest dimension (default: 200)\n * @returns Promise resolving to thumbnail as base64 data URL string\n * @example\n * ```typescript\n * const thumbnail = await ImageUtils.createThumbnail(imageFile, 150);\n * document.getElementById('preview').src = thumbnail;\n * ```\n */\n async createThumbnail(file: File, maxSize: number = 200): Promise<string> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => {\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n reject(new Error(\"Could not get canvas context\"));\n return;\n }\n\n let width = img.width;\n let height = img.height;\n\n if (width > height) {\n if (width > maxSize) {\n height = Math.round((height * maxSize) / width);\n width = maxSize;\n }\n } else {\n if (height > maxSize) {\n width = Math.round((width * maxSize) / height);\n height = maxSize;\n }\n }\n\n canvas.width = width;\n canvas.height = height;\n ctx.drawImage(img, 0, 0, width, height);\n resolve(canvas.toDataURL(\"image/jpeg\", 0.7));\n };\n img.onerror = reject;\n img.src = URL.createObjectURL(file);\n });\n },\n\n /**\n * Crops an image to specified rectangular dimensions.\n * @param file - The image file to crop\n * @param x - Starting x coordinate for the crop (pixels from left)\n * @param y - Starting y coordinate for the crop (pixels from top)\n * @param width - Width of the crop area in pixels\n * @param height - Height of the crop area in pixels\n * @returns Promise resolving to the cropped image as a Blob\n * @example\n * ```typescript\n * // Crop a 200x200 square from the center of the image\n * const cropped = await ImageUtils.cropImage(imageFile, 100, 100, 200, 200);\n * ```\n */\n async cropImage(\n file: File,\n x: number,\n y: number,\n width: number,\n height: number\n ): Promise<Blob> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => {\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n reject(new Error(\"Could not get canvas context\"));\n return;\n }\n\n canvas.width = width;\n canvas.height = height;\n ctx.drawImage(img, x, y, width, height, 0, 0, width, height);\n\n canvas.toBlob((blob) => {\n if (blob) resolve(blob);\n else reject(new Error(\"Failed to create blob\"));\n }, file.type);\n };\n img.onerror = reject;\n img.src = URL.createObjectURL(file);\n });\n },\n\n /**\n * Extracts metadata information from an image file.\n * @param file - The image file to analyze\n * @returns Promise resolving to object containing width, height, type, and size\n * @example\n * ```typescript\n * const metadata = await ImageUtils.getImageMetadata(imageFile);\n * console.log(`Image: ${metadata.width}x${metadata.height}, ${metadata.type}, ${metadata.size} bytes`);\n * ```\n */\n async getImageMetadata(file: File): Promise<ImageMetadata> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => {\n resolve({\n width: img.width,\n height: img.height,\n type: file.type,\n size: file.size,\n });\n };\n img.onerror = reject;\n img.src = URL.createObjectURL(file);\n });\n },\n\n /**\n * Analyzes an image to determine its most dominant color.\n * @param file - The image file to analyze\n * @returns Promise resolving to the dominant color as a hex string\n * @example\n * ```typescript\n * const dominantColor = await ImageUtils.getDominantColor(imageFile);\n * console.log(`Dominant color: ${dominantColor}`); // e.g., \"#ff5733\"\n * document.body.style.backgroundColor = dominantColor;\n * ```\n */\n async getDominantColor(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => {\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n reject(new Error(\"Could not get canvas context\"));\n return;\n }\n\n // Scale down image for faster processing\n const scale = Math.min(1, 100 / Math.max(img.width, img.height));\n canvas.width = img.width * scale;\n canvas.height = img.height * scale;\n ctx.drawImage(img, 0, 0, canvas.width, canvas.height);\n\n const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n const data = imageData.data;\n const colorCounts: { [key: string]: number } = {};\n\n // Sample pixels and count colors\n for (let i = 0; i < data.length; i += 4) {\n const r = data[i];\n const g = data[i + 1];\n const b = data[i + 2];\n const color = `#${r.toString(16).padStart(2, \"0\")}${g\n .toString(16)\n .padStart(2, \"0\")}${b.toString(16).padStart(2, \"0\")}`;\n colorCounts[color] = (colorCounts[color] || 0) + 1;\n }\n\n // Find most frequent color\n let maxCount = 0;\n let dominantColor = \"#000000\";\n for (const color in colorCounts) {\n if (colorCounts[color] > maxCount) {\n maxCount = colorCounts[color];\n dominantColor = color;\n }\n }\n\n resolve(dominantColor);\n };\n img.onerror = reject;\n img.src = URL.createObjectURL(file);\n });\n },\n\n /**\n * Calculates scaled dimensions for an image while maintaining aspect ratio.\n * @param img - The HTML image element to scale\n * @param maxWidth - Optional maximum width constraint\n * @param maxHeight - Optional maximum height constraint\n * @returns Object containing the calculated scaled width and height\n * @example\n * ```typescript\n * const scaled = ImageUtils.getScaledDimensions(imageElement, 800, 600);\n * console.log(`Scaled dimensions: ${scaled.width}x${scaled.height}`);\n * ```\n */\n getScaledDimensions(\n img: HTMLImageElement,\n maxWidth?: number,\n maxHeight?: number\n ): ScaledDimensions {\n const originalWidth = img.width;\n const originalHeight = img.height;\n let newWidth = originalWidth;\n let newHeight = originalHeight;\n\n if (maxWidth && maxHeight) {\n const aspectRatio = originalWidth / originalHeight;\n if (originalWidth > maxWidth || originalHeight > maxHeight) {\n if (aspectRatio > 1) {\n newWidth = maxWidth;\n newHeight = maxWidth / aspectRatio;\n } else {\n newHeight = maxHeight;\n newWidth = maxHeight * aspectRatio;\n }\n }\n } else if (maxWidth) {\n const aspectRatio = originalWidth / originalHeight;\n if (originalWidth > maxWidth) {\n newWidth = maxWidth;\n newHeight = maxWidth / aspectRatio;\n }\n } else if (maxHeight) {\n const aspectRatio = originalWidth / originalHeight;\n if (originalHeight > maxHeight) {\n newHeight = maxHeight;\n newWidth = maxHeight * aspectRatio;\n }\n }\n\n return {\n width: Math.round(newWidth),\n height: Math.round(newHeight),\n };\n },\n\n /**\n * Checks if an image exists and is accessible at the given URL.\n * @param url - The URL to check for image availability\n * @returns Promise resolving to true if the image exists and is accessible\n * @example\n * ```typescript\n * const exists = await ImageUtils.imageExists('https://example.com/image.jpg');\n * if (exists) {\n * console.log('Image is available');\n * }\n * ```\n */\n async imageExists(url: string): Promise<boolean> {\n try {\n const response = await fetch(url);\n return response.ok;\n } catch (e) {\n return false;\n }\n },\n\n /**\n * Validates whether a file is an image based on its MIME type.\n * @param file - The file to check\n * @returns True if the file is an image, false otherwise\n * @example\n * ```typescript\n * const isImage = ImageUtils.isImageFile(selectedFile);\n * if (!isImage) {\n * alert('Please select an image file');\n * }\n * ```\n */\n isImageFile(file: File): boolean {\n return file.type.startsWith(\"image/\");\n },\n\n /**\n * Loads an image from a URL and returns the HTMLImageElement.\n * @param url - The URL of the image to load\n * @returns Promise resolving to HTMLImageElement when image loads successfully\n * @throws {Error} If the image fails to load\n * @example\n * ```typescript\n * try {\n * const img = await ImageUtils.loadImage('https://example.com/image.jpg');\n * console.log(`Loaded image: ${img.width}x${img.height}`);\n * } catch (error) {\n * console.error('Failed to load image:', error);\n * }\n * ```\n */\n loadImage(url: string): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => resolve(img);\n img.onerror = reject;\n img.src = url;\n });\n },\n\n /**\n * Loads and decodes an image from a URL with error handling.\n * @param url - The URL of the image to load\n * @returns Promise resolving to HTMLImageElement or null if loading fails\n * @example\n * ```typescript\n * const img = await ImageUtils.loadImageElement('https://example.com/image.jpg');\n * if (img) {\n * document.body.appendChild(img);\n * } else {\n * console.log('Failed to load image');\n * }\n * ```\n */\n async loadImageElement(url: string): Promise<HTMLImageElement | null> {\n const img = new Image();\n img.src = url;\n\n try {\n await img.decode();\n } catch (e) {\n console.error(e);\n return null;\n }\n\n return img;\n },\n\n /**\n * Resizes an image file to fit within specified dimensions while maintaining aspect ratio.\n * @param file - The image file to resize\n * @param options - Resize options including max dimensions, quality, and output format\n * @returns Promise resolving to the resized image as a Blob\n * @example\n * ```typescript\n * const resized = await ImageUtils.resizeImage(originalFile, {\n * maxWidth: 800,\n * maxHeight: 600,\n * quality: 0.9,\n * format: 'jpeg'\n * });\n * ```\n */\n async resizeImage(\n file: File,\n options: ImageResizeOptions = {}\n ): Promise<Blob> {\n const {\n maxWidth = 1920,\n maxHeight = 1080,\n quality = 0.8,\n format = \"jpeg\",\n } = options;\n\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => {\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n reject(new Error(\"Could not get canvas context\"));\n return;\n }\n\n let width = img.width;\n let height = img.height;\n\n if (width > height) {\n if (width > maxWidth) {\n height = Math.round((height * maxWidth) / width);\n width = maxWidth;\n }\n } else {\n if (height > maxHeight) {\n width = Math.round((width * maxHeight) / height);\n height = maxHeight;\n }\n }\n\n canvas.width = width;\n canvas.height = height;\n ctx.drawImage(img, 0, 0, width, height);\n\n canvas.toBlob(\n (blob) => {\n if (blob) {\n resolve(blob);\n } else {\n reject(new Error(\"Failed to create blob\"));\n }\n },\n `image/${format}`,\n quality\n );\n };\n img.onerror = reject;\n img.src = URL.createObjectURL(file);\n });\n },\n\n /**\n * Rotates an image by the specified number of degrees around its center.\n * @param file - The image file to rotate\n * @param degrees - Degrees to rotate (0-360, positive for clockwise)\n * @returns Promise resolving to the rotated image as a Blob\n * @example\n * ```typescript\n * const rotated90 = await ImageUtils.rotateImage(imageFile, 90);\n * const rotatedMinus45 = await ImageUtils.rotateImage(imageFile, -45);\n * ```\n */\n async rotateImage(file: File, degrees: number): Promise<Blob> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => {\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n reject(new Error(\"Could not get canvas context\"));\n return;\n }\n\n // Calculate new canvas dimensions\n const rad = (degrees * Math.PI) / 180;\n const sin = Math.abs(Math.sin(rad));\n const cos = Math.abs(Math.cos(rad));\n const newWidth = img.width * cos + img.height * sin;\n const newHeight = img.width * sin + img.height * cos;\n\n canvas.width = newWidth;\n canvas.height = newHeight;\n\n // Rotate and draw\n ctx.translate(newWidth / 2, newHeight / 2);\n ctx.rotate(rad);\n ctx.drawImage(img, -img.width / 2, -img.height / 2);\n\n canvas.toBlob((blob) => {\n if (blob) resolve(blob);\n else reject(new Error(\"Failed to create blob\"));\n }, file.type);\n };\n img.onerror = reject;\n img.src = URL.createObjectURL(file);\n });\n },\n\n /**\n * Converts a URL to a File object by downloading the content.\n * @param url - The URL to convert to a file\n * @param filename - The name for the resulting file\n * @param mimeType - The MIME type for the file\n * @returns Promise resolving to a File object\n * @example\n * ```typescript\n * const file = await ImageUtils.urlToFile(\n * 'https://example.com/image.jpg',\n * 'downloaded-image.jpg',\n * 'image/jpeg'\n * );\n * ```\n */\n async urlToFile(\n url: string,\n filename: string,\n mimeType: string\n ): Promise<File> {\n const response = await fetch(url);\n const blob = await response.blob();\n return new File([blob], filename, { type: mimeType });\n },\n\n /**\n * Validates that image dimensions are within specified limits.\n * @param width - The width to validate\n * @param height - The height to validate\n * @param maxWidth - The maximum allowed width\n * @param maxHeight - The maximum allowed height\n * @returns True if dimensions are within limits, false otherwise\n * @example\n * ```typescript\n * const isValid = ImageUtils.validateImageDimensions(1920, 1080, 2000, 2000);\n * if (!isValid) {\n * console.log('Image is too large');\n * }\n * ```\n */\n validateImageDimensions(\n width: number,\n height: number,\n maxWidth: number,\n maxHeight: number\n ): boolean {\n return width <= maxWidth && height <= maxHeight;\n },\n};\n"],"names":[],"mappings":"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"}