fix: comprimir imagen pegada hasta <250KB con calidad progresiva
OpenSSL 3.x en contenedor hace renegociacion TLS con Facebook >~300KB causando errno 55. Forzar imagen a quedar bajo 250KB: - Escalar a max 1920px si es más grande - Intentar JPEG q=0.85, 0.70, 0.55, 0.40, 0.25 hasta pasar el umbral - JPEG/WebP ya bajo 250KB se pasan sin modificar
This commit is contained in:
+40
-16
@@ -2200,14 +2200,16 @@ if (!isset($_SESSION['user_id'])) {
|
||||
const cd = (e.clipboardData || window.clipboardData);
|
||||
if (!cd) return;
|
||||
|
||||
// ─── Comprimir imagen pegada a JPEG vía Canvas ────────────────────────
|
||||
// Las imágenes del portapapeles llegan como PNG sin comprimir (1-5 MB).
|
||||
// Facebook resetea la conexión TCP al recibir payloads grandes desde este
|
||||
// contenedor → errno 55. Comprimir a JPEG 0.85 reduce el tamaño ~10x.
|
||||
// Si el tipo ya es JPEG o WebP, se mantiene sin recomprimir.
|
||||
// ─── Comprimir imagen pegada a JPEG ─────────────────────────────────────
|
||||
// El contenedor usa OpenSSL 3.x que hace renegociación TLS con Facebook
|
||||
// para payloads >~300KB → errno 55 "Send failure". Solución: forzar
|
||||
// que la imagen quede bajo 250KB mediante calidad progresiva + escala.
|
||||
const TARGET_BYTES = 250 * 1024; // 250KB
|
||||
const MAX_DIM = 1920; // máximo ancho/alto antes de escalar
|
||||
|
||||
const compressToJpeg = (blob) => new Promise((resolve) => {
|
||||
// Si ya es JPEG o WebP, no recomprimir (ya están comprimidos)
|
||||
if (blob.type === 'image/jpeg' || blob.type === 'image/webp') {
|
||||
// Si ya es pequeño JPEG/WebP, no recomprimir
|
||||
if ((blob.type === 'image/jpeg' || blob.type === 'image/webp') && blob.size <= TARGET_BYTES) {
|
||||
resolve(blob);
|
||||
return;
|
||||
}
|
||||
@@ -2215,17 +2217,39 @@ if (!isset($_SESSION['user_id'])) {
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
// Escalar si la imagen es más grande que MAX_DIM
|
||||
let w = img.naturalWidth, h = img.naturalHeight;
|
||||
if (w > MAX_DIM || h > MAX_DIM) {
|
||||
const ratio = Math.min(MAX_DIM / w, MAX_DIM / h);
|
||||
w = Math.round(w * ratio);
|
||||
h = Math.round(h * ratio);
|
||||
}
|
||||
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = img.naturalWidth;
|
||||
canvas.height = img.naturalHeight;
|
||||
canvas.width = w; canvas.height = h;
|
||||
const ctx = canvas.getContext('2d');
|
||||
// Fondo blanco para transparencias PNG
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.drawImage(img, 0, 0);
|
||||
canvas.toBlob((jpegBlob) => {
|
||||
resolve(jpegBlob || blob); // fallback al original si toBlob falla
|
||||
}, 'image/jpeg', 0.85);
|
||||
ctx.fillStyle = '#ffffff'; // fondo blanco para PNGs con transparencia
|
||||
ctx.fillRect(0, 0, w, h);
|
||||
ctx.drawImage(img, 0, 0, w, h);
|
||||
|
||||
// Calidades a intentar hasta quedar bajo TARGET_BYTES
|
||||
const qualities = [0.85, 0.70, 0.55, 0.40, 0.25];
|
||||
let idx = 0;
|
||||
const tryNext = () => {
|
||||
if (idx >= qualities.length) { resolve(blob); return; } // fallback
|
||||
canvas.toBlob((b) => {
|
||||
if (!b) { resolve(blob); return; }
|
||||
if (b.size <= TARGET_BYTES || idx === qualities.length - 1) {
|
||||
console.log(`Paste compress: ${(blob.size/1024).toFixed(0)}KB → ${(b.size/1024).toFixed(0)}KB (q=${qualities[idx]} ${w}×${h}px)`);
|
||||
resolve(b);
|
||||
} else {
|
||||
idx++;
|
||||
tryNext();
|
||||
}
|
||||
}, 'image/jpeg', qualities[idx]);
|
||||
};
|
||||
tryNext();
|
||||
};
|
||||
img.onerror = () => { URL.revokeObjectURL(url); resolve(blob); };
|
||||
img.src = url;
|
||||
|
||||
Reference in New Issue
Block a user