Files
imgPub/src/utils/cropUtils.js

115 lines
3.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const loadImage = (file) =>
new Promise((resolve, reject) => {
const image = new Image();
image.onload = () => {
URL.revokeObjectURL(image.src);
resolve(image);
};
image.onerror = (error) => {
URL.revokeObjectURL(image.src);
reject(error);
};
image.src = URL.createObjectURL(file);
});
const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
const normalizeCropConfig = (config) => {
if (!config?.imageWidth || !config?.imageHeight) {
throw new Error('Geçerli bir crop referansı bulunamadı.');
}
const safeWidth = Math.max(
1,
config.width - (config.left ?? 0) - (config.right ?? 0),
);
const safeHeight = Math.max(
1,
config.height - (config.top ?? 0) - (config.bottom ?? 0),
);
const xStart = Math.max(0, config.cropAreaX + (config.left ?? 0));
const yStart = Math.max(0, config.cropAreaY + (config.top ?? 0));
return {
xRatio: xStart / config.imageWidth,
yRatio: yStart / config.imageHeight,
widthRatio: safeWidth / config.imageWidth,
heightRatio: safeHeight / config.imageHeight,
};
};
const cropImage = async (file, normalizedConfig) => {
const image = await loadImage(file);
const { width: imgWidth, height: imgHeight } = image;
const cropWidth = clamp(
Math.round(normalizedConfig.widthRatio * imgWidth),
1,
imgWidth,
);
const cropHeight = clamp(
Math.round(normalizedConfig.heightRatio * imgHeight),
1,
imgHeight,
);
const startX = clamp(
Math.round(normalizedConfig.xRatio * imgWidth),
0,
imgWidth - cropWidth,
);
const startY = clamp(
Math.round(normalizedConfig.yRatio * imgHeight),
0,
imgHeight - cropHeight,
);
const canvas = document.createElement('canvas');
canvas.width = cropWidth;
canvas.height = cropHeight;
const ctx = canvas.getContext('2d');
ctx.drawImage(image, startX, startY, cropWidth, cropHeight, 0, 0, cropWidth, cropHeight);
const blob = await new Promise((resolve, reject) => {
canvas.toBlob((result) => {
if (result) {
resolve(result);
} else {
reject(new Error('Canvas blob oluşturulamadı.'));
}
}, 'image/png');
});
const url = URL.createObjectURL(blob);
return { blob, url };
};
const buildCropResult = (imageMeta, blob, url) => ({
id: imageMeta.id,
filename: imageMeta.file?.name || imageMeta.filename,
blob,
url,
order: imageMeta.order,
});
export const cropSingleImage = async (image, config) => {
if (!config || !config.imageWidth) {
throw new Error('Kapak için geçerli bir crop ayarı bulunamadı.');
}
const normalized = normalizeCropConfig(config);
const { blob, url } = await cropImage(image.file, normalized);
return buildCropResult(image, blob, url);
};
export const applyCropToImages = async (images, config) => {
if (!images?.length) {
throw new Error('Önce görsel yüklemelisin.');
}
if (!config || !config.imageWidth) {
throw new Error('Crop ayarı bulunamadı.');
}
const normalized = normalizeCropConfig(config);
const results = [];
for (const image of images) {
const { blob, url } = await cropImage(image.file, normalized);
results.push(buildCropResult(image, blob, url));
}
return results;
};