/** * @fileoverview Image Compressor & Thumbnail Generator Engine * @module utils/image-compressor * @description محرك معالجة وضغط الصور وتوليد الصور المصغرة محلياً عبر Canvas لتحسين سرعة الإرسال وتقليل استهلاك الذاكرة. */ (global => { 'use strict'; /** * كائن معالجة وضغط الصور */ const ImageCompressor = { /** * ضغط الصورة وتقليص أبعادها للحد الأقصى المسموح (1200px) مع الحفاظ على نسبة العرض للارتفاع * @param {File|Blob} file - ملف الصورة المراد ضغطه * @param {number} maxSize - أقصى بُعد مسموح به (افتراضياً 1200px) * @param {number} quality - جودة ضغط الـ JPEG (من 0.1 إلى 1.0) * @returns {Promise} الـ Blob المضغوط */ compressImage: function(file, maxSize = 1200, quality = 0.85) { return new Promise((resolve) => { if (!(file instanceof Blob)) { resolve(file); return; } const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = (event) => { const img = new Image(); img.src = event.target.result; img.onload = () => { const canvas = document.createElement('canvas'); let width = img.width; let height = img.height; if (width > height) { if (width > maxSize) { height = Math.round(height * (maxSize / width)); width = maxSize; } } else { if (height > maxSize) { width = Math.round(width * (maxSize / height)); height = maxSize; } } canvas.width = width; canvas.height = height; const ctx = canvas.getContext('2d'); if (ctx) { ctx.drawImage(img, 0, 0, width, height); } canvas.toBlob((blob) => { resolve(blob || file); }, 'image/jpeg', quality); }; img.onerror = () => resolve(file); }; reader.onerror = () => resolve(file); }); }, /** * @param {File|Blob} fileBlob * @param {number} thumbSize * @param {number} quality * @returns {Promise} */ generateThumbnail: function(fileBlob, thumbSize = 120, quality = 0.80) { return new Promise((resolve) => { if (!(fileBlob instanceof Blob)) { resolve(fileBlob); return; } const reader = new FileReader(); reader.readAsDataURL(fileBlob); reader.onload = (event) => { const img = new Image(); img.src = event.target.result; img.onload = () => { const canvas = document.createElement('canvas'); canvas.width = thumbSize; canvas.height = thumbSize; const ctx = canvas.getContext('2d'); if (ctx) { const minDim = Math.min(img.width, img.height); const sx = (img.width - minDim) / 2; const sy = (img.height - minDim) / 2; ctx.drawImage(img, sx, sy, minDim, minDim, 0, 0, thumbSize, thumbSize); } canvas.toBlob((blob) => { resolve(blob || fileBlob); }, 'image/jpeg', quality); }; img.onerror = () => resolve(fileBlob); }; reader.onerror = () => resolve(fileBlob); }); } }; global.FritreeImageCompressor = ImageCompressor; })(typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : this);