Alirezamw3 commited on
Commit
f445a91
·
verified ·
1 Parent(s): 683ee2c

عکس رو از گالری که انتخاب میکنه،شناسایی نمیکنه سایت،انگار که من عکسی انتخاب نکردم

Browse files
Files changed (2) hide show
  1. README.md +9 -5
  2. index.html +388 -18
README.md CHANGED
@@ -1,10 +1,14 @@
1
  ---
2
- title: Mangamagicfixer Wand
3
- emoji: 👁
4
- colorFrom: red
5
- colorTo: green
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
1
  ---
2
+ title: MangaMagicFixer Wand
3
+ colorFrom: green
4
+ colorTo: pink
5
+ emoji: 🐳
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite-v3
10
  ---
11
 
12
+ # Welcome to your new DeepSite project!
13
+ This project was created with [DeepSite](https://deepsite.hf.co).
14
+
index.html CHANGED
@@ -1,19 +1,389 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>MangaMagic Translator</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://unpkg.com/feather-icons"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
10
+ <script src="https://cdn.jsdelivr.net/npm/tesseract.js@4/dist/tesseract.min.js"></script>
11
+ <style>
12
+ .dropzone {
13
+ border: 2px dashed #94a3b8;
14
+ transition: all 0.3s ease;
15
+ }
16
+ .dropzone.active {
17
+ border-color: #6366f1;
18
+ background-color: #e0e7ff;
19
+ }
20
+ #outputCanvas {
21
+ max-width: 100%;
22
+ height: auto;
23
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
24
+ }
25
+ .progress-bar {
26
+ height: 4px;
27
+ transition: width 0.3s ease;
28
+ }
29
+ </style>
30
+ </head>
31
+ <body class="bg-gray-50 min-h-screen">
32
+ <div class="container mx-auto px-4 py-8">
33
+ <header class="text-center mb-12">
34
+ <h1 class="text-4xl font-bold text-indigo-600 mb-2">MangaMagic Translator Wand ✨</h1>
35
+ <p class="text-lg text-gray-600">One-click manga translation with AI-powered tools</p>
36
+ </header>
37
+
38
+ <div class="max-w-4xl mx-auto bg-white rounded-xl shadow-md overflow-hidden p-6">
39
+ <div class="grid md:grid-cols-2 gap-8">
40
+ <!-- Input Section -->
41
+ <div>
42
+ <h2 class="text-xl font-semibold text-gray-800 mb-4">Upload Manga Page</h2>
43
+ <div id="dropzone" class="dropzone rounded-lg p-8 text-center cursor-pointer mb-4">
44
+ <i data-feather="upload" class="w-12 h-12 mx-auto text-gray-400 mb-3"></i>
45
+ <p class="text-gray-500 mb-2">Drag & drop your manga image here</p>
46
+ <p class="text-sm text-gray-400">or click to browse files (JPEG, PNG)</p>
47
+ <input type="file" id="fileInput" accept="image/*" class="hidden">
48
+ </div>
49
+
50
+ <div class="space-y-4">
51
+ <div>
52
+ <label class="block text-sm font-medium text-gray-700 mb-1">Processing Options</label>
53
+ <div class="flex items-center space-x-4">
54
+ <label class="inline-flex items-center">
55
+ <input type="checkbox" id="upscaleCheck" checked class="rounded text-indigo-600">
56
+ <span class="ml-2 text-gray-700">2x Upscale</span>
57
+ </label>
58
+ <label class="inline-flex items-center">
59
+ <input type="checkbox" id="cleanCheck" checked class="rounded text-indigo-600">
60
+ <span class="ml-2 text-gray-700">Clean Text Areas</span>
61
+ </label>
62
+ </div>
63
+ </div>
64
+
65
+ <div class="pt-2">
66
+ <button id="processBtn" disabled class="w-full py-3 px-4 bg-indigo-600 hover:bg-indigo-700 text-white font-medium rounded-lg transition duration-200 flex items-center justify-center">
67
+ <i data-feather="wand" class="w-5 h-5 mr-2"></i>
68
+ Process & Translate
69
+ </button>
70
+ </div>
71
+ </div>
72
+ </div>
73
+
74
+ <!-- Output Section -->
75
+ <div>
76
+ <h2 class="text-xl font-semibold text-gray-800 mb-4">Translated Result</h2>
77
+ <div id="progressContainer" class="hidden mb-4">
78
+ <div class="flex justify-between text-sm text-gray-600 mb-1">
79
+ <span id="progressStatus">Processing image...</span>
80
+ <span id="progressPercent">0%</span>
81
+ </div>
82
+ <div class="w-full bg-gray-200 rounded-full h-2">
83
+ <div id="progressBar" class="progress-bar bg-indigo-600 rounded-full h-2" style="width: 0%"></div>
84
+ </div>
85
+ </div>
86
+
87
+ <div id="outputContainer" class="hidden">
88
+ <canvas id="outputCanvas" class="rounded-lg border border-gray-200"></canvas>
89
+ <div class="mt-4 flex justify-end">
90
+ <button id="downloadBtn" class="py-2 px-4 bg-white border border-indigo-600 text-indigo-600 hover:bg-indigo-50 rounded-lg transition duration-200 flex items-center">
91
+ <i data-feather="download" class="w-4 h-4 mr-2"></i>
92
+ Download
93
+ </button>
94
+ </div>
95
+ </div>
96
+
97
+ <div id="emptyState" class="flex flex-col items-center justify-center py-12 bg-gray-50 rounded-lg">
98
+ <i data-feather="image" class="w-12 h-12 text-gray-300 mb-4"></i>
99
+ <p class="text-gray-500">Your translated manga will appear here</p>
100
+ </div>
101
+ </div>
102
+ </div>
103
+ </div>
104
+
105
+ <div class="mt-12 bg-white rounded-xl shadow-md overflow-hidden p-6">
106
+ <h2 class="text-xl font-semibold text-gray-800 mb-4">How It Works</h2>
107
+ <div class="grid md:grid-cols-4 gap-6">
108
+ <div class="text-center p-4">
109
+ <div class="bg-indigo-100 w-12 h-12 rounded-full flex items-center justify-center mx-auto mb-3">
110
+ <i data-feather="upload" class="text-indigo-600"></i>
111
+ </div>
112
+ <h3 class="font-medium text-gray-800 mb-1">Upload</h3>
113
+ <p class="text-sm text-gray-600">Upload your manga page image</p>
114
+ </div>
115
+ <div class="text-center p-4">
116
+ <div class="bg-indigo-100 w-12 h-12 rounded-full flex items-center justify-center mx-auto mb-3">
117
+ <i data-feather="maximize" class="text-indigo-600"></i>
118
+ </div>
119
+ <h3 class="font-medium text-gray-800 mb-1">Enhance</h3>
120
+ <p class="text-sm text-gray-600">Image upscaling for better OCR</p>
121
+ </div>
122
+ <div class="text-center p-4">
123
+ <div class="bg-indigo-100 w-12 h-12 rounded-full flex items-center justify-center mx-auto mb-3">
124
+ <i data-feather="globe" class="text-indigo-600"></i>
125
+ </div>
126
+ <h3 class="font-medium text-gray-800 mb-1">Translate</h3>
127
+ <p class="text-sm text-gray-600">AI-powered text translation</p>
128
+ </div>
129
+ <div class="text-center p-4">
130
+ <div class="bg-indigo-100 w-12 h-12 rounded-full flex items-center justify-center mx-auto mb-3">
131
+ <i data-feather="image" class="text-indigo-600"></i>
132
+ </div>
133
+ <h3 class="font-medium text-gray-800 mb-1">Render</h3>
134
+ <p class="text-sm text-gray-600">Natural-looking text placement</p>
135
+ </div>
136
+ </div>
137
+ </div>
138
+ </div>
139
+
140
+ <script>
141
+ feather.replace();
142
+
143
+ // Global variables
144
+ let originalImage = null;
145
+ let translatedImage = null;
146
+
147
+ // DOM elements
148
+ const dropzone = document.getElementById('dropzone');
149
+ const fileInput = document.getElementById('fileInput');
150
+ const processBtn = document.getElementById('processBtn');
151
+ const outputCanvas = document.getElementById('outputCanvas');
152
+ const outputContainer = document.getElementById('outputContainer');
153
+ const emptyState = document.getElementById('emptyState');
154
+ const progressContainer = document.getElementById('progressContainer');
155
+ const progressBar = document.getElementById('progressBar');
156
+ const progressStatus = document.getElementById('progressStatus');
157
+ const progressPercent = document.getElementById('progressPercent');
158
+ const downloadBtn = document.getElementById('downloadBtn');
159
+ const upscaleCheck = document.getElementById('upscaleCheck');
160
+ const cleanCheck = document.getElementById('cleanCheck');
161
+
162
+ // Event listeners
163
+ dropzone.addEventListener('click', () => fileInput.click());
164
+ dropzone.addEventListener('dragover', (e) => {
165
+ e.preventDefault();
166
+ dropzone.classList.add('active');
167
+ });
168
+ dropzone.addEventListener('dragleave', () => {
169
+ dropzone.classList.remove('active');
170
+ });
171
+ dropzone.addEventListener('drop', (e) => {
172
+ e.preventDefault();
173
+ dropzone.classList.remove('active');
174
+ if (e.dataTransfer.files.length) {
175
+ handleFile(e.dataTransfer.files[0]);
176
+ }
177
+ });
178
+ fileInput.addEventListener('change', () => {
179
+ if (fileInput.files.length) {
180
+ handleFile(fileInput.files[0]);
181
+ }
182
+ });
183
+
184
+ // Reset dropzone content when clicking to select new file
185
+ dropzone.addEventListener('click', (e) => {
186
+ if (!fileInput.files.length) {
187
+ // Reset to original state if no file is selected
188
+ dropzone.innerHTML = `
189
+ <i data-feather="upload" class="w-12 h-12 mx-auto text-gray-400 mb-3"></i>
190
+ <p class="text-gray-500 mb-2">Drag & drop your manga image here</p>
191
+ <p class="text-sm text-gray-400">or click to browse files (JPEG, PNG)</p>
192
+ `;
193
+ feather.replace();
194
+ }
195
+ fileInput.click();
196
+ });
197
+ processBtn.addEventListener('click', async () => {
198
+ if (!originalImage) return;
199
+
200
+ // Show progress
201
+ progressContainer.classList.remove('hidden');
202
+ progressStatus.textContent = "Processing image...";
203
+ progressBar.style.width = "10%";
204
+
205
+ try {
206
+ // Step 1: Upscale if selected
207
+ let workingImage = originalImage;
208
+ if (upscaleCheck.checked) {
209
+ progressStatus.textContent = "Upscaling image (2x)...";
210
+ workingImage = await upscaleImage(workingImage);
211
+ progressBar.style.width = "30%";
212
+ }
213
+
214
+ // Step 2: OCR text detection
215
+ progressStatus.textContent = "Detecting text areas...";
216
+ const { data: ocrResult } = await performOCR(workingImage);
217
+ progressBar.style.width = "50%";
218
+
219
+ // Step 3: Text cleaning
220
+ let cleanedImage = workingImage;
221
+ if (cleanCheck.checked) {
222
+ progressStatus.textContent = "Cleaning text areas...";
223
+ cleanedImage = await cleanTextAreas(workingImage, ocrResult);
224
+ progressBar.style.width = "70%";
225
+ }
226
+
227
+ // Step 4: Translation
228
+ progressStatus.textContent = "Translating text...";
229
+ const translatedTexts = await translateTexts(ocrResult);
230
+ progressBar.style.width = "90%";
231
+
232
+ // Step 5: Render translated text
233
+ progressStatus.textContent = "Rendering translated text...";
234
+ translatedImage = await renderTranslation(cleanedImage, ocrResult, translatedTexts);
235
+ progressBar.style.width = "100%";
236
+
237
+ // Display result
238
+ displayResult(translatedImage);
239
+ progressStatus.textContent = "Translation complete!";
240
+
241
+ } catch (error) {
242
+ console.error("Processing error:", error);
243
+ progressStatus.textContent = "Error: " + error.message;
244
+ progressBar.style.backgroundColor = "#ef4444";
245
+ }
246
+ });
247
+
248
+ downloadBtn.addEventListener('click', () => {
249
+ if (!translatedImage) return;
250
+
251
+ const link = document.createElement('a');
252
+ link.download = 'translated-manga.png';
253
+ link.href = translatedImage.toDataURL('image/png');
254
+ link.click();
255
+ });
256
+
257
+ // Functions
258
+ function handleFile(file) {
259
+ // Fix for gallery images that might have different MIME types
260
+ const validImageTypes = ['image/jpeg', 'image/png', 'image/jpg', 'image/webp', 'image/gif'];
261
+
262
+ if (!validImageTypes.includes(file.type.toLowerCase())) {
263
+ alert('Please select a valid image file (JPEG, PNG, WEBP, GIF)');
264
+ return;
265
+ }
266
+
267
+ const reader = new FileReader();
268
+ reader.onload = (e) => {
269
+ const img = new Image();
270
+ img.onload = () => {
271
+ originalImage = img;
272
+ processBtn.disabled = false;
273
+
274
+ // Show success feedback to user
275
+ dropzone.innerHTML = `
276
+ <i data-feather="check-circle" class="w-12 h-12 mx-auto text-green-500 mb-3"></i>
277
+ <p class="text-green-600 font-medium mb-1">Image loaded successfully!</p>
278
+ <p class="text-sm text-gray-500">${file.name}</p>
279
+ <p class="text-xs text-gray-400 mt-2">Click to select a different image</p>
280
+ `;
281
+ feather.replace();
282
+ };
283
+ img.onerror = () => {
284
+ alert('Error loading image. Please try another file.');
285
+ };
286
+ img.src = e.target.result;
287
+ };
288
+ reader.onerror = () => {
289
+ alert('Error reading file. Please try again.');
290
+ };
291
+ reader.readAsDataURL(file);
292
+ }
293
+ function displayResult(image) {
294
+ outputContainer.classList.remove('hidden');
295
+ emptyState.classList.add('hidden');
296
+
297
+ const ctx = outputCanvas.getContext('2d');
298
+ outputCanvas.width = image.width;
299
+ outputCanvas.height = image.height;
300
+ ctx.clearRect(0, 0, outputCanvas.width, outputCanvas.height);
301
+ ctx.drawImage(image, 0, 0);
302
+ }
303
+
304
+ async function upscaleImage(image) {
305
+ // In a real app, you would use a proper upscaling algorithm or API
306
+ // This is a simplified placeholder implementation
307
+ return new Promise((resolve) => {
308
+ const canvas = document.createElement('canvas');
309
+ canvas.width = image.width * 2;
310
+ canvas.height = image.height * 2;
311
+ const ctx = canvas.getContext('2d');
312
+ ctx.imageSmoothingEnabled = true;
313
+ ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
314
+
315
+ const upscaled = new Image();
316
+ upscaled.onload = () => resolve(upscaled);
317
+ upscaled.src = canvas.toDataURL('image/png');
318
+ });
319
+ }
320
+
321
+ async function performOCR(image) {
322
+ // Using Tesseract.js for OCR
323
+ progressStatus.textContent = "Initializing OCR engine...";
324
+
325
+ return await Tesseract.recognize(
326
+ image.src,
327
+ 'jpn+eng', // Japanese and English
328
+ {
329
+ logger: (m) => {
330
+ if (m.status) {
331
+ progressStatus.textContent = `OCR: ${m.status}`;
332
+ }
333
+ }
334
+ }
335
+ );
336
+ }
337
+
338
+ async function cleanTextAreas(image, ocrResult) {
339
+ // This would be handled by ZITS in a real implementation
340
+ // Placeholder that just returns the original image
341
+ return image;
342
+ }
343
+
344
+ async function translateTexts(ocrResult) {
345
+ // In a real app, this would use DeepL API or similar
346
+ // Placeholder that returns mock translations
347
+ return ocrResult.words.map(word => {
348
+ return {
349
+ text: `[فارسی] ${word.text}`,
350
+ bbox: word.bbox
351
+ };
352
+ });
353
+ }
354
+
355
+ async function renderTranslation(image, ocrResult, translations) {
356
+ const canvas = document.createElement('canvas');
357
+ canvas.width = image.width;
358
+ canvas.height = image.height;
359
+ const ctx = canvas.getContext('2d');
360
+
361
+ // Draw original image (cleaned)
362
+ ctx.drawImage(image, 0, 0);
363
+
364
+ // Draw translated texts (simplified)
365
+ ctx.font = 'bold 16px Arial'; // Would use a better font matching the original
366
+ ctx.fillStyle = '#000000';
367
+ ctx.textAlign = 'left';
368
+
369
+ translations.forEach(item => {
370
+ const { x0, y0, x1, y1 } = item.bbox;
371
+ const width = x1 - x0;
372
+ const height = y1 - y0;
373
+
374
+ // Calculate font size to fit the box
375
+ const fontSize = Math.min(height * 0.7, width / (item.text.length * 0.6));
376
+ ctx.font = `bold ${fontSize}px Arial`;
377
+
378
+ // Draw text (simple version - would need more sophisticated rendering)
379
+ ctx.fillText(item.text, x0, y0 + height * 0.8);
380
+ });
381
+
382
+ const result = new Image();
383
+ result.src = canvas.toDataURL('image/png');
384
+ await new Promise(resolve => result.onload = resolve);
385
+ return result;
386
+ }
387
+ </script>
388
+ </body>
389
  </html>