An image cropper component for Angular applications with comprehensive cropping functionality
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
The LoadImageService manages image loading and transformation from various sources including files, URLs, and base64 strings, with automatic EXIF handling and format support.
Injectable service for loading and transforming images from multiple sources.
export class LoadImageService {
/**
* Load image from a File object
* @param file - File object containing image data
* @param options - Loading and transformation options
* @returns Promise resolving to LoadedImage with original and transformed data
*/
loadImageFile(file: File, options: LoadImageOptions): Promise<LoadedImage>;
/**
* Load image from a URL
* @param url - URL to fetch the image from
* @param options - Loading and transformation options
* @returns Promise resolving to LoadedImage with original and transformed data
*/
loadImageFromURL(url: string, options: LoadImageOptions): Promise<LoadedImage>;
/**
* Load image from base64 encoded string
* @param imageBase64 - Base64 encoded image string (with or without data URL prefix)
* @param options - Loading and transformation options
* @returns Promise resolving to LoadedImage with original and transformed data
*/
loadBase64Image(imageBase64: string, options: LoadImageOptions): Promise<LoadedImage>;
/**
* Transform an already loaded image with new options
* @param loadedImage - Partially loaded image data
* @param options - Transformation options to apply
* @param forceTransform - Force transformation even if no changes detected
* @returns Promise resolving to fully transformed LoadedImage
*/
transformLoadedImage(
loadedImage: Partial<LoadedImage>,
options: LoadImageOptions,
forceTransform?: boolean
): Promise<LoadedImage>;
}Usage Examples:
import { LoadImageService } from 'ngx-image-cropper';
const loadImageService = new LoadImageService();
// Load from file input
const fileInput = document.querySelector('input[type="file"]') as HTMLInputElement;
if (fileInput.files && fileInput.files[0]) {
const options: LoadImageOptions = {
format: 'png',
canvasRotation: 0,
aspectRatio: 16 / 9,
containWithinAspectRatio: false,
checkImageType: true
};
try {
const loadedImage = await loadImageService.loadImageFile(fileInput.files[0], options);
console.log('Original size:', loadedImage.original.size);
console.log('Transformed size:', loadedImage.transformed.size);
console.log('EXIF transform:', loadedImage.exifTransform);
} catch (error) {
console.error('Failed to load image:', error);
}
}
// Load from URL
try {
const loadedImage = await loadImageService.loadImageFromURL(
'https://example.com/image.jpg',
{ format: 'jpeg', checkImageType: true }
);
// Process loaded image
} catch (error) {
console.error('Failed to load image from URL:', error);
}
// Load from base64
const base64String = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==';
try {
const loadedImage = await loadImageService.loadBase64Image(base64String, {
format: 'png',
canvasRotation: 90,
aspectRatio: 1
});
// Process loaded image
} catch (error) {
console.error('Failed to load base64 image:', error);
}
// Transform existing loaded image
const existingLoadedImage = { /* partial loaded image */ };
const newOptions: LoadImageOptions = {
canvasRotation: 180,
containWithinAspectRatio: true,
aspectRatio: 4 / 3
};
try {
const transformedImage = await loadImageService.transformLoadedImage(
existingLoadedImage,
newOptions,
true // Force transformation
);
// Use transformed image
} catch (error) {
console.error('Failed to transform image:', error);
}Configuration options for image loading and transformation.
interface LoadImageOptions {
/** Output format for transformed images */
format?: OutputFormat;
/** Canvas rotation angle in degrees (0, 90, 180, 270) */
canvasRotation?: number;
/** Target aspect ratio for containment */
aspectRatio?: number;
/** Contain image within aspect ratio bounds */
containWithinAspectRatio?: boolean;
/** Validate image file type before loading */
checkImageType?: boolean;
}Data structure containing original and transformed image information.
interface LoadedImage {
/** Original image data as loaded */
original: {
/** Object URL for the original image */
objectUrl: string;
/** HTMLImageElement containing the original image */
image: HTMLImageElement;
/** Dimensions of the original image */
size: Dimensions;
};
/** Transformed image data after processing */
transformed: {
/** Object URL for the transformed image */
objectUrl: string;
/** HTMLImageElement containing the transformed image */
image: HTMLImageElement;
/** Dimensions of the transformed image */
size: Dimensions;
};
/** EXIF transformation data extracted from image metadata */
exifTransform: ExifTransform;
}EXIF metadata transformations automatically applied during image loading.
interface ExifTransform {
/** Rotation angle from EXIF data */
rotate: number;
/** Horizontal flip from EXIF data */
flip: boolean;
}The service supports loading the following image formats:
// Supported MIME types for image validation
type SupportedImageTypes =
| 'image/png'
| 'image/jpg'
| 'image/jpeg'
| 'image/heic'
| 'image/bmp'
| 'image/gif'
| 'image/tiff'
| 'image/svg+xml'
| 'image/webp'
| 'image/x-icon'
| 'image/vnd.microsoft.icon';// Loading with comprehensive options
const comprehensiveOptions: LoadImageOptions = {
format: 'jpeg',
canvasRotation: 90,
aspectRatio: 16 / 9,
containWithinAspectRatio: true,
checkImageType: true
};
// Load and handle different scenarios
async function loadImageWithErrorHandling(file: File) {
try {
const loadedImage = await loadImageService.loadImageFile(file, comprehensiveOptions);
// Check if transformation was applied
const wasTransformed = loadedImage.original.objectUrl !== loadedImage.transformed.objectUrl;
console.log('Image was transformed:', wasTransformed);
// Handle EXIF data
if (loadedImage.exifTransform.rotate !== 0) {
console.log('Image had EXIF rotation:', loadedImage.exifTransform.rotate);
}
if (loadedImage.exifTransform.flip) {
console.log('Image had EXIF flip transformation');
}
return loadedImage;
} catch (error) {
if (error instanceof Error) {
if (error.message === 'Invalid image type') {
console.error('Unsupported image format');
} else if (error.message === 'No image loaded') {
console.error('Image failed to load');
} else {
console.error('Unknown error:', error.message);
}
}
throw error;
}
}
// Transform image with different canvas rotations
async function rotateImage(loadedImage: LoadedImage, rotation: number) {
const rotationOptions: LoadImageOptions = {
...comprehensiveOptions,
canvasRotation: rotation
};
return await loadImageService.transformLoadedImage(
loadedImage,
rotationOptions,
true
);
}
// Load SVG with special handling
async function loadSvgImage(svgFile: File) {
const svgOptions: LoadImageOptions = {
format: 'png', // Convert SVG to PNG
checkImageType: true
};
try {
const loadedImage = await loadImageService.loadImageFile(svgFile, svgOptions);
// SVG images may have special size handling
console.log('SVG loaded and converted to:', loadedImage.transformed.size);
return loadedImage;
} catch (error) {
if (error instanceof Error && error.message.includes('Failed to load SVG')) {
console.error('SVG must have width + height or viewBox definition');
}
throw error;
}
}The service throws specific errors for different failure scenarios:
'Invalid image type' - When checkImageType is true and file type is not supported'No image loaded' - When image fails to load or is corrupted'Failed to parse SVG image' - When SVG structure is invalid'Failed to load SVG image. SVG must have width + height or viewBox definition.' - When SVG lacks size information'Failed to get Blob for transformed image.' - When canvas transformation fails