[dyad] Refactoring the app for modularity - wrote 12 file(s)
This commit is contained in:
128
src/lib/image-processor.ts
Normal file
128
src/lib/image-processor.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import { ConversionSettings, ImageFile } from "@/types";
|
||||
|
||||
export function generateFinalFilename(
|
||||
baseFilename: string,
|
||||
settings: ConversionSettings,
|
||||
index: number
|
||||
): string {
|
||||
const { prefix, suffix, useCounter, counterStart, counterDigits } = settings;
|
||||
let finalName = `${prefix}${baseFilename}${suffix}`;
|
||||
|
||||
if (useCounter) {
|
||||
const counter = (index + counterStart).toString().padStart(counterDigits, '0');
|
||||
finalName += `${counter}`;
|
||||
}
|
||||
|
||||
return finalName;
|
||||
}
|
||||
|
||||
export function processImage(
|
||||
imageFile: ImageFile,
|
||||
settings: ConversionSettings
|
||||
): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = new Image();
|
||||
img.crossOrigin = "anonymous";
|
||||
img.src = imageFile.previewUrl;
|
||||
|
||||
img.onload = () => {
|
||||
const canvas = document.createElement("canvas");
|
||||
const sourceRatio = img.naturalWidth / img.naturalHeight;
|
||||
|
||||
let targetWidth: number;
|
||||
let targetHeight: number;
|
||||
|
||||
const inputWidth = settings.width ? Number(settings.width) : 0;
|
||||
const inputHeight = settings.height ? Number(settings.height) : 0;
|
||||
|
||||
if (inputWidth && !inputHeight) {
|
||||
targetWidth = inputWidth;
|
||||
targetHeight = Math.round(targetWidth / sourceRatio);
|
||||
} else if (!inputWidth && inputHeight) {
|
||||
targetHeight = inputHeight;
|
||||
targetWidth = Math.round(targetHeight * sourceRatio);
|
||||
} else if (inputWidth && inputHeight) {
|
||||
targetWidth = inputWidth;
|
||||
targetHeight = inputHeight;
|
||||
} else {
|
||||
targetWidth = img.naturalWidth;
|
||||
targetHeight = img.naturalHeight;
|
||||
}
|
||||
|
||||
if (settings.keepOrientation && (inputWidth || inputHeight)) {
|
||||
const isOriginalPortrait = img.naturalHeight > img.naturalWidth;
|
||||
const isTargetPortrait = targetHeight > targetWidth;
|
||||
if (isOriginalPortrait !== isTargetPortrait) {
|
||||
[targetWidth, targetHeight] = [targetHeight, targetWidth];
|
||||
}
|
||||
}
|
||||
|
||||
canvas.width = targetWidth;
|
||||
canvas.height = targetHeight;
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
||||
if (ctx) {
|
||||
const sWidth = img.naturalWidth;
|
||||
const sHeight = img.naturalHeight;
|
||||
const dWidth = targetWidth;
|
||||
const dHeight = targetHeight;
|
||||
|
||||
if (settings.scaleMode === 'fill' || !settings.width || !settings.height) {
|
||||
ctx.drawImage(img, 0, 0, dWidth, dHeight);
|
||||
} else {
|
||||
const sourceRatio = sWidth / sHeight;
|
||||
const targetRatio = dWidth / dHeight;
|
||||
let sx = 0, sy = 0, sRenderWidth = sWidth, sRenderHeight = sHeight;
|
||||
let dx = 0, dy = 0, dRenderWidth = dWidth, dRenderHeight = dHeight;
|
||||
const [hPos, vPos] = settings.objectPosition.split(' ');
|
||||
|
||||
if (settings.scaleMode === 'cover') {
|
||||
if (sourceRatio > targetRatio) {
|
||||
sRenderHeight = sHeight;
|
||||
sRenderWidth = sHeight * targetRatio;
|
||||
if (hPos === 'center') sx = (sWidth - sRenderWidth) / 2;
|
||||
if (hPos === 'right') sx = sWidth - sRenderWidth;
|
||||
} else {
|
||||
sRenderWidth = sWidth;
|
||||
sRenderHeight = sWidth / targetRatio;
|
||||
if (vPos === 'center') sy = (sHeight - sRenderHeight) / 2;
|
||||
if (vPos === 'bottom') sy = sHeight - sRenderHeight;
|
||||
}
|
||||
ctx.drawImage(img, sx, sy, sRenderWidth, sRenderHeight, 0, 0, dWidth, dHeight);
|
||||
} else if (settings.scaleMode === 'contain') {
|
||||
if (sourceRatio > targetRatio) {
|
||||
dRenderWidth = dWidth;
|
||||
dRenderHeight = dWidth / sourceRatio;
|
||||
if (vPos === 'center') dy = (dHeight - dRenderHeight) / 2;
|
||||
if (vPos === 'bottom') dy = dHeight - dRenderHeight;
|
||||
} else {
|
||||
dRenderHeight = dHeight;
|
||||
dRenderWidth = dHeight * sourceRatio;
|
||||
if (hPos === 'center') dx = (dWidth - dRenderWidth) / 2;
|
||||
if (hPos === 'right') dx = dWidth - dRenderWidth;
|
||||
}
|
||||
ctx.drawImage(img, 0, 0, sWidth, sHeight, dx, dy, dRenderWidth, dRenderHeight);
|
||||
}
|
||||
}
|
||||
|
||||
const mimeType = `image/${settings.format}`;
|
||||
const dataUrl = canvas.toDataURL(mimeType, settings.format === 'png' ? undefined : settings.quality / 100);
|
||||
resolve(dataUrl);
|
||||
} else {
|
||||
reject(new Error(`Could not get canvas context for ${imageFile.file.name}.`));
|
||||
}
|
||||
};
|
||||
img.onerror = () => {
|
||||
reject(new Error(`Failed to load ${imageFile.file.name} for conversion.`));
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export function downloadDataUrl(dataUrl: string, filename: string) {
|
||||
const link = document.createElement("a");
|
||||
link.href = dataUrl;
|
||||
link.download = filename;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
}
|
||||
Reference in New Issue
Block a user