first commit

This commit is contained in:
2025-11-10 23:35:59 +03:00
commit 68165014ad
33 changed files with 2084 additions and 0 deletions

103
src/utils/cropUtils.js Normal file
View File

@@ -0,0 +1,103 @@
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 };
};
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({
id: image.id,
filename: image.file.name,
blob,
url,
order: image.order,
});
}
return results;
};

46
src/utils/epubUtils.js Normal file
View File

@@ -0,0 +1,46 @@
const base64ToBlob = (base64, mimeType) => {
const binary = atob(base64);
const len = binary.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i += 1) {
bytes[i] = binary.charCodeAt(i);
}
return new Blob([bytes], { type: mimeType });
};
const API_BASE = import.meta.env.VITE_API_BASE_URL || 'http://localhost:4000';
export const createEpubFromOcr = async (text) => {
if (!text?.trim()) {
throw new Error('Önce OCR adımını tamamlamalısın.');
}
const response = await fetch(`${API_BASE}/generate-epub`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
text,
meta: {
title: 'imgPub OCR Export',
author: 'imgPub',
filename: `imgpub${Date.now()}.epub`,
},
}),
});
if (!response.ok) {
const message = await response.text();
throw new Error(message || 'EPUB oluşturma isteği başarısız.');
}
const payload = await response.json();
const blob = base64ToBlob(payload.data, 'application/epub+zip');
const url = URL.createObjectURL(blob);
return {
filename: payload.filename,
blob,
url,
generatedAt: Date.now(),
};
};

9
src/utils/fileUtils.js Normal file
View File

@@ -0,0 +1,9 @@
export const downloadBlob = (blobUrl, filename) => {
const anchor = document.createElement('a');
anchor.href = blobUrl;
anchor.download = filename;
anchor.style.display = 'none';
document.body.appendChild(anchor);
anchor.click();
document.body.removeChild(anchor);
};

6
src/utils/ocrUtils.js Normal file
View File

@@ -0,0 +1,6 @@
export const correctTurkishCharacters = (text = '') =>
text
.replace(/İ/g, 'İ')
.replace(/i̇/g, 'i')
.replace(/\s+/g, ' ')
.trim();