import { err, ok, Result } from "neverthrow"; /** * Compresses an image represented as a Base64 string. * * This function resizes the image to fit within the specified maximum width and height while maintaining the aspect ratio. * The image is then compressed to a JPEG format with the given quality level. * * @param base64String - The Base64 string of the image to be compressed. * @param maxWidth - The maximum width of the compressed image. The aspect ratio is preserved. * @param maxHeight - The maximum height of the compressed image. The aspect ratio is preserved. * @param quality - The quality of the compressed image, ranging from 0 to 1, where 1 is the best quality. * * @returns A Promise that resolves to a `Result` containing either: * - `ok` with the compressed image as a Base64 string, or * - `err` with an error if the image fails to load or compress. * * @example * ```typescript * compressImageBase64('data:image/png;base64,...', 800, 600, 0.8) * .then(result => { * if (result.isOk()) { * console.log('Compressed image:', result.value); * } else { * console.error('Error compressing image:', result.error); * } * }); * ``` */ export function compressImageBase64(base64String: string, maxWidth: number, maxHeight: number, quality: number): Promise> { return new Promise((resolve, reject) => { const image = new Image(); image.src = base64String; image.onload = async () => { const canvas = document.createElement('canvas'); let newWidth = image.width; let newHeight = image.height; if (newWidth > maxWidth) { newHeight *= maxWidth / newWidth; newWidth = maxWidth; } if (newHeight > maxHeight) { newWidth *= maxHeight / newHeight; newHeight = maxHeight; } canvas.width = newWidth; canvas.height = newHeight; const context = canvas.getContext('2d'); context?.drawImage(image, 0, 0, newWidth, newHeight); const compressedBase64 = canvas.toDataURL('image/jpeg', quality); // Calculate the compression percentage const originalSize = base64String.length; const compressedSize = compressedBase64.length; const compressionPercentage = ((originalSize - compressedSize) / originalSize) * 100; console.log(`Compression achieved: ${compressionPercentage.toFixed(2)}%`); resolve(ok(compressedBase64)); }; image.onerror = (error) => { resolve(err(error)); }; }); }