🎯 Рекомендуемые коллекции
Балансированные коллекции примеров кода из различных категорий, которые вы можете исследовать
Примеры Обработки Изображений Web TypeScript
Примеры обработки изображений Web TypeScript включая чтение/сохранение, масштабирование и конвертацию форматов
💻 Чтение/Сохранение Изображений typescript
🟢 simple
⭐⭐
Чтение и сохранение изображений используя FileReader, Canvas API и различные методы скачивания
⏱️ 20 min
🏷️ typescript, web, image processing
Prerequisites:
Basic TypeScript, File API, Canvas API
// 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 };
💻 Масштабирование Изображений typescript
🟡 intermediate
⭐⭐⭐
Изменение размера изображений с различными алгоритмами включая билинейную, бикубическую и масштабирование высокого качества
⏱️ 25 min
🏷️ typescript, web, image processing
Prerequisites:
Intermediate TypeScript, Canvas API
// 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 };
💻 Конвертация Форматов Изображений typescript
🟡 intermediate
⭐⭐⭐
Конвертация между форматами изображений включая PNG, JPEG, WebP, GIF и BMP
⏱️ 25 min
🏷️ typescript, web, image processing
Prerequisites:
Intermediate TypeScript, Canvas API, File API
// 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 };