API de Compresión de Imágenes#

Comprime imágenes PNG, JPEG y WebP con el endpoint POST /v1/convert/compress-image — el formato nunca cambia (entra PNG, sale PNG). La compresión es primero sin pérdida: se eliminan los metadatos y la imagen se recodifica con los ajustes sin pérdida más fuertes para su formato, por lo que el resultado nunca es más grande que la entrada. Pasa target_size_kb para fijar un presupuesto de tamaño de archivo; si la optimización sin pérdida por sí sola no lo alcanza, la imagen se reduce de escala con la relación de aspecto bloqueada hasta que quepa.


Endpoint#

POST /v1/convert/compress-image

Content-Type: multipart/form-data

Entrada aceptada: archivos .png, .jpg, .jpeg, .webp

Formato de salida: el mismo que la entrada (image/png, image/jpeg o image/webp)


Autenticación#

Requiere una clave de API privada o un token JWT de una clave pública.

X-API-Key: sk_live_your_private_key

O:

Authorization: Bearer <jwt_token>

Parámetros de la solicitud#

Parámetro Tipo Obligatorio Predeterminado Descripción
file file -- El archivo de imagen .png, .jpg, .jpeg o .webp a comprimir.
target_size_kb integer No -- Tamaño de archivo objetivo en kilobytes. Omitido: solo optimización sin pérdida. Establecido: la imagen además se reduce de escala (relación de aspecto bloqueada) hasta que quepa en el objetivo.
output_filename string No Nombre del archivo de entrada Nombre de archivo de salida personalizado. La extensión del archivo de entrada se conserva.
direct_download boolean No true Cuando es true, devuelve los bytes de la imagen sin procesar. Cuando es false, devuelve metadatos JSON con una URL de descarga prefirmada.

Detalles de la conversión#

Etapa 1 — sin pérdida (siempre se ejecuta):

  • Los metadatos (EXIF, XMP, fragmentos de texto PNG) se eliminan; el perfil de color ICC y el indicador de orientación EXIF se conservan para que los colores y la rotación no cambien
  • PNG: se recodifica con la máxima compresión zlib, más una conversión a paleta cuando la imagen tiene 256 colores únicos o menos y el resultado es demostrablemente idéntico píxel a píxel
  • JPEG: se recodifica reutilizando las tablas de cuantización originales con codificación Huffman progresiva optimizada — no se introduce pérdida de cuantización adicional
  • WebP: recodificación sin pérdida real (VP8L) con el máximo esfuerzo
  • Gana el más pequeño entre los bytes originales y todos los candidatos — la salida nunca es más grande que la entrada

Etapa 2 — reducción de dimensiones (solo con target_size_kb, y solo si la etapa 1 no lo alcanza):

  • La imagen se reduce de escala con la relación de aspecto bloqueada (remuestreo LANCZOS) y se recodifica, buscando de forma binaria el factor de escala con las mayores dimensiones que quepan en el objetivo
  • Los JPEG reducidos y los WebP de origen con pérdida se recodifican a calidad 85; los PNG y los WebP de origen sin pérdida permanecen sin pérdida en el tamaño reducido
Nota de mejor esfuerzo: Si el objetivo es inalcanzable incluso en la escala mínima, el endpoint devuelve el archivo más pequeño que consiguió en lugar de un error — comprueba file_size (o el encabezado X-File-Size) para ver qué se alcanzó.

Respuesta#

Descarga directa (direct_download=true, predeterminado)#

HTTP 200 OK
Content-Type: image/png
Content-Disposition: inline; filename="photo_20260717_123456789.png"

Devuelve los bytes de la imagen sin procesar en el mismo formato que la entrada.

Respuesta con metadatos (direct_download=false)#

{
    "presigned_url": "https://spaces.example.com/...",
    "object_key": "env/files/{project_id}/compress-image/photo_20260717_123456789.png",
    "filename": "photo_20260717_123456789.png",
    "file_size": 45678,
    "conversion_time_seconds": 0.5
}

Ejemplos de código#

Python#

import requests

with open("photo.png", "rb") as f:
    response = requests.post(
        "https://api.enconvert.com/v1/convert/compress-image",
        headers={"X-API-Key": "sk_live_your_private_key"},
        files={"file": ("photo.png", f)},
        data={"target_size_kb": 200}
    )

with open("photo_compressed.png", "wb") as out:
    out.write(response.content)

Node.js#

const form = new FormData();
form.append("file", fs.createReadStream("photo.png"));
form.append("target_size_kb", "200");

const response = await fetch("https://api.enconvert.com/v1/convert/compress-image", {
    method: "POST",
    headers: { "X-API-Key": "sk_live_your_private_key" },
    body: form
});

fs.writeFileSync("photo_compressed.png", Buffer.from(await response.arrayBuffer()));

PHP#

$ch = curl_init("https://api.enconvert.com/v1/convert/compress-image");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ["X-API-Key: sk_live_your_private_key"],
    CURLOPT_POSTFIELDS => [
        "file" => new CURLFile("photo.png"),
        "target_size_kb" => 200
    ]
]);
$output = curl_exec($ch);
curl_close($ch);
file_put_contents("photo_compressed.png", $output);

Go#

body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, _ := writer.CreateFormFile("file", "photo.png")
file, _ := os.Open("photo.png")
io.Copy(part, file)
writer.WriteField("target_size_kb", "200")
writer.Close()

req, _ := http.NewRequest("POST", "https://api.enconvert.com/v1/convert/compress-image", body)
req.Header.Set("Content-Type", writer.FormDataContentType())
req.Header.Set("X-API-Key", "sk_live_your_private_key")
resp, _ := http.DefaultClient.Do(req)

Respuestas de error#

Estado Condición
400 Bad Request El archivo no es un archivo .png, .jpg, .jpeg o .webp
400 Bad Request El contenido del archivo no coincide con su extensión (el endpoint nunca cambia de formato)
400 Bad Request Imagen animada (APNG / WebP animado) — no compatible
400 Bad Request target_size_kb es cero o negativo
422 Unprocessable Entity target_size_kb está presente pero no es un número entero
400 Bad Request La conversión de la imagen falló (archivo corrupto o no compatible)
401 Unauthorized Falta la clave de API/token JWT o no es válida
402 Payment Required Se alcanzó el límite mensual de conversiones
402 Payment Required Se alcanzó el límite de almacenamiento
413 Payload Too Large El archivo supera el tamaño máximo permitido por tu plan
400 Bad Request El lienzo de la imagen supera los 40.000.000 de píxeles (protección contra bombas de descompresión)

Límites#

Límite Valor
Tamaño máximo de archivo Según el plan (Free: 5 MB)
Dimensiones máximas de imagen 40.000.000 de píxeles (p. ej. 8000x5000)
Formatos PNG, JPEG, WebP (solo estáticos — sin animaciones)
Tamaño objetivo Mejor esfuerzo — los objetivos inalcanzables devuelven el archivo más pequeño alcanzable
Conversiones mensuales Según el plan

Preguntas frecuentes#

¿Cómo comprimo una imagen sin perder calidad?#

Envía la imagen a /v1/convert/compress-image sin target_size_kb. El endpoint elimina los metadatos y recodifica con los ajustes sin pérdida más fuertes para el formato — los PNG y los WebP sin pérdida permanecen idénticos píxel a píxel, y el JPEG conserva sus tablas de cuantización originales, por lo que no se introduce pérdida de cuantización adicional. El resultado nunca es más grande que tu entrada.

¿Cómo comprimo una imagen a un tamaño de archivo específico?#

Pasa target_size_kb con tu presupuesto en kilobytes (por ejemplo, 200 para 200 KB). La optimización sin pérdida se ejecuta primero; si el archivo sigue por encima del presupuesto, la imagen se reduce de escala con la relación de aspecto bloqueada hasta que quepa. Si el objetivo es inalcanzable incluso en la escala mínima, obtienes el archivo más pequeño alcanzable en lugar de un error.

¿La compresión cambia el formato de la imagen?#

No, nunca. PNG sigue siendo PNG, JPEG sigue siendo JPEG y WebP sigue siendo WebP — el endpoint rechaza los archivos cuyo contenido no coincide con su extensión en lugar de convertirlos silenciosamente.

¿Se eliminan los metadatos de mi imagen?#

Los EXIF, XMP y fragmentos de texto PNG se eliminan, lo que a menudo ahorra espacio por sí solo. Dos cosas se conservan deliberadamente: el perfil de color ICC (para que los colores no cambien en visores con gestión de color) y el indicador de orientación EXIF (para que las fotos rotadas se sigan mostrando correctamente).

¿Puedo comprimir imágenes animadas?#

No. Los archivos APNG y WebP animados se rechazan con un error 400 en lugar de aplanarse silenciosamente a un solo fotograma.