Welcome to WordPress. This is your first post. Edit or delete it, then start writing!
Welcome to WordPress. This is your first post. Edit or delete it, then start writing!
*/ (function() { 'use strict'; // ─── CONFIGURACIÓN ─────────────────────────────────────────────── const CONFIG = { maxWidthHeight: 1280, // px máximo (ancho o alto) quality: 0.78, // calidad JPEG (0-1). 0.78 = buen balance calidad/peso maxSizeKB: 700, // peso máximo por foto en KB minQuality: 0.45, // calidad mínima antes de reducir más la resolución }; // IDs de los campos de archivo del formulario CF7 const FILE_FIELDS = ['fotos', 'fotos1', 'fotos2', 'fotos3', 'fotos4']; // ─── ESTADO VISUAL ─────────────────────────────────────────────── function crearIndicador(input) { const existente = input.parentNode.querySelector('.compress-status'); if (existente) existente.remove(); const div = document.createElement('div'); div.className = 'compress-status'; div.style.cssText = ` font-size: 12px; margin-top: 4px; padding: 4px 8px; border-radius: 4px; display: none; `; input.parentNode.insertBefore(div, input.nextSibling); return div; } function mostrarEstado(div, texto, tipo) { const colores = { procesando: { bg: '#fff3cd', color: '#856404', border: '#ffc107' }, listo: { bg: '#d1e7dd', color: '#0f5132', border: '#198754' }, error: { bg: '#f8d7da', color: '#842029', border: '#dc3545' }, }; const c = colores[tipo] || colores.procesando; div.style.display = 'block'; div.style.background = c.bg; div.style.color = c.color; div.style.border = `1px solid ${c.border}`; div.textContent = texto; } // ─── NÚCLEO: COMPRESIÓN ────────────────────────────────────────── function comprimirImagen(file, callback) { // Solo imágenes if (!file.type.startsWith('image/')) { callback(file); return; } const reader = new FileReader(); reader.onload = function(e) { const img = new Image(); img.onload = function() { // Calcular nuevas dimensiones manteniendo aspecto let { width, height } = img; const maxDim = CONFIG.maxWidthHeight; if (width > maxDim || height > maxDim) { if (width > height) { height = Math.round((height * maxDim) / width); width = maxDim; } else { width = Math.round((width * maxDim) / height); height = maxDim; } } const canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; const ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0, width, height); // Comprimir iterativamente hasta cumplir maxSizeKB let quality = CONFIG.quality; let dataUrl, blob; function intentar() { dataUrl = canvas.toDataURL('image/jpeg', quality); const bytes = Math.round((dataUrl.length * 3) / 4); const kb = bytes / 1024; if (kb > CONFIG.maxSizeKB && quality > CONFIG.minQuality) { quality = Math.max(quality - 0.08, CONFIG.minQuality); intentar(); return; } // Convertir dataUrl a Blob y luego a File const byteStr = atob(dataUrl.split(',')[1]); const arr = new Uint8Array(byteStr.length); for (let i = 0; i < byteStr.length; i++) { arr[i] = byteStr.charCodeAt(i); } blob = new Blob([arr], { type: 'image/jpeg' }); const archivoComprimido = new File( [blob], file.name.replace(/\.[^.]+$/, '') + '_c.jpg', { type: 'image/jpeg', lastModified: Date.now() } ); callback(archivoComprimido, { originalKB: Math.round(file.size / 1024), finalKB: Math.round(blob.size / 1024), quality: Math.round(quality * 100), }); } intentar(); }; img.src = e.target.result; }; reader.readAsDataURL(file); } // ─── REEMPLAZAR ARCHIVO EN INPUT ───────────────────────────────── function reemplazarArchivo(input, nuevoArchivo) { try { const dt = new DataTransfer(); dt.items.add(nuevoArchivo); input.files = dt.files; } catch (e) { // DataTransfer no disponible en algunos browsers antiguos console.warn('No se pudo reemplazar el archivo automáticamente:', e); } } // ─── INICIALIZAR CAMPOS ────────────────────────────────────────── function inicializarCampo(input) { const indicador = crearIndicador(input); input.addEventListener('change', function() { const file = this.files[0]; if (!file) return; // Si no es imagen, no comprimir if (!file.type.startsWith('image/')) return; const originalKB = Math.round(file.size / 1024); // Si ya pesa menos de maxSizeKB, no hace falta comprimir if (originalKB <= CONFIG.maxSizeKB) { mostrarEstado(indicador, `✅ ${file.name} (${originalKB} KB) — listo`, 'listo'); return; } mostrarEstado(indicador, `⏳ Optimizando foto... (${originalKB} KB)`, 'procesando'); comprimirImagen(file, function(archivoComprimido, info) { if (info) { reemplazarArchivo(input, archivoComprimido); mostrarEstado( indicador, `✅ Optimizada: ${info.originalKB} KB → ${info.finalKB} KB (${Math.round((1 - info.finalKB / info.originalKB) * 100)}% menos)`, 'listo' ); } else { mostrarEstado(indicador, `✅ ${file.name} lista`, 'listo'); } }); }); } // ─── BUSCAR Y CONECTAR CAMPOS ──────────────────────────────────── function conectarCampos() { FILE_FIELDS.forEach(function(nombre) { // CF7 genera inputs con name igual al tag const inputs = document.querySelectorAll(`input[type="file"][name="${nombre}"]`); inputs.forEach(inicializarCampo); }); } // Esperar a que CF7 cargue el DOM if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', conectarCampos); } else { conectarCampos(); } // Por si el formulario está en una página con carga dinámica document.addEventListener('wpcf7mailsent', function() { // Limpiar indicadores después del envío exitoso document.querySelectorAll('.compress-status').forEach(function(el) { el.style.display = 'none'; }); }); })();