Optimiza PNG con Oxipng desde la CLI y Rust
Para comprimir un PNG con Oxipng y conservar el archivo original, usa
--out con un nombre de archivo diferente.
El siguiente tutorial permite anticipar el resultado, guardar una copia optimizada y realizar
la misma operación desde Rust. Utiliza PNG comunes, sin animación, y mantiene desactivadas las
transformaciones opcionales con pérdida.
La optimización de PNG sin pérdida puede cambiar la compresión, el filtrado, la distribución de la paleta y la representación del color sin modificar los valores de los píxeles decodificados. Por lo tanto, un hash de archivo diferente no significa que la imagen haya perdido calidad. Tampoco demuestra que se hayan conservado todos los metadatos. Conserva el archivo de origen cuando necesites un original para archivo.
Instala Oxipng
Estos ejemplos de Bash se probaron en Linux con Rust y Cargo 1.98.1 y Oxipng 10.2.1. Necesitas Cargo
en tu PATH, un compilador y un enlazador de C para la dependencia nativa
de compresión, y el directorio de binarios de Cargo en tu PATH.
Oxipng 10.2.1 declara Rust 1.88.0 como versión mínima.
cargo install oxipng --version 10.2.1 --locked &&
oxipng --version
El comando de versión debería mostrar oxipng 10.2.1. Si muestra otra versión,
comprueba qué binario encuentra tu shell antes de continuar.
cargo install compila en modo release de forma
predeterminada; --locked utiliza el archivo de bloqueo de dependencias
incluido en el paquete del crate.
Optimiza un solo PNG
Coloca tu PNG en el directorio actual con el nombre input.png. Primero,
consulta el resultado de la optimización sin escribir nada:
oxipng -o 4 --dry-run -v -- input.png
--dry-run sigue realizando el trabajo de optimización; solo omite la escritura
del resultado. La versión 10
reemplazó la antigua opción --pretend.
Para guardar el resultado por separado y comparar los tamaños de archivo:
oxipng -o 4 -v --out optimized.png -- input.png &&
wc -c input.png optimized.png
Esto deja input.png intacto.
Reemplaza cualquier optimized.png existente sin preguntar, incluso en una
nueva ejecución no interactiva. Elige un nombre de destino nuevo si necesitas conservar un
resultado anterior. El directorio padre del destino ya debe existir.
El ajuste preestablecido cuatro es un punto de partida, no una promesa de ahorro. Los niveles disponibles van del cero al seis; el predeterminado es dos. Los ajustes preestablecidos más altos dedican más trabajo a la búsqueda, pero no garantizan un resultado más pequeño. Un PNG ya optimizado puede no reducirse. Con esta configuración, se escribe un archivo de salida separado de todos modos, utilizando los bytes originales cuando Oxipng no puede mejorarlos. Sin un destino separado, en ese caso no se modifica el archivo de entrada.
Oxipng utiliza de forma predeterminada las CPU lógicas disponibles. Añade
--threads 4 para limitar sus hilos de trabajo en una máquina compartida.
Consulta el manual de la CLI para esta versión
para ver la lista completa de opciones.
Elige qué conservar
Aquí importan tres tipos de conservación diferentes:
| Configuración | Significado |
|---|---|
Sin --alpha | Conserva los valores RGB incluso en los píxeles totalmente transparentes. Añadir --alpha permite cambiar esos colores ocultos para la compresión; no hay pérdida visual, pero cambian los datos de los píxeles. |
Sin --strip | Conserva los metadatos PNG que siguen siendo válidos después de la optimización, con las excepciones que se indican a continuación. |
--preserve | Intenta conservar los permisos del sistema de archivos y la hora de modificación. No controla los metadatos PNG ni conserva la hora de acceso. |
Las opciones de la biblioteca también mantienen desactivadas de
forma predeterminada la optimización alfa y la reducción con pérdida de 16 a ocho bits.
No añadas --scale16 si necesitas conservar los valores de los píxeles sin pérdida.
La conservación predeterminada de metadatos no equivale a una preservación exacta para archivo.
Oxipng descarta bKGD, sBIT y
hIST si un cambio en el tipo de color o la profundidad de bits los invalida.
También elimina de forma predeterminada los bloques caBX de C2PA y
iDOT de Apple. Un perfil ICC incrustado puede volver a comprimirse.
Estos comportamientos se describen en la
implementación del manejo de bloques y en el manual de la CLI.
Usa --strip safe solo cuando quieras descartar información auxiliar como texto y EXIF.
Esta opción conserva determinados bloques relacionados con la visualización, incluidos
sRGB y pHYs, pero no garantiza que se conserven todos
los metadatos. --strip all va más allá y puede eliminar información de gestión del
color, lo que cambia la forma en que se muestra una imagen. Ninguna de estas opciones es necesaria
para los ejemplos de este tutorial.
Si quieres reemplazar deliberadamente el archivo de entrada y conservar sus permisos y su hora de modificación, usa:
oxipng -o 4 --preserve -- input.png
Esta operación modifica el archivo original: guarda una copia de seguridad antes de ejecutarla. Se intenta conservar los atributos, pero no se garantiza; Oxipng advierte si no puede restaurar un atributo.
Procesa una carpeta por lotes
Para un directorio de archivos PNG que estés dispuesto a reemplazar, ejecuta:
find ./images -type f -name '*.png' -exec oxipng -o 4 --preserve -- {} +
Esto recorre los directorios anidados y pasa de forma segura los nombres de archivo que contienen
espacios. Busca extensiones .png en minúsculas y modifica los archivos
originales; una nueva ejecución opera sobre esos mismos archivos. Añade --dry-run
a los argumentos de Oxipng para consultar el resultado sin escribirlo. Usa una copia del directorio
de archivos cuando necesites conservar los originales.
Integra Oxipng en tu código Rust
Crea un proyecto nuevo y fija la misma versión del crate:
cargo new --bin --vcs none png-optimize &&
cd png-optimize &&
cargo add oxipng@=10.2.1
Continúa solo cuando esta operación se complete correctamente. Si ya existe un directorio
png-optimize, cargo new falla; elige un nombre de proyecto nuevo
en lugar de eliminar uno existente. Conserva el archivo Cargo.lock generado
para mantener las versiones de las dependencias que se resolvieron.
Coloca una copia de tu PNG en el directorio del proyecto con el nombre input.png.
Reemplaza el archivo src/main.rs generado por este programa completo:
use oxipng::{optimize, InFile, Options, OutFile};
use std::path::PathBuf;
fn main() -> Result<(), oxipng::PngError> {
let input = InFile::Path(PathBuf::from("input.png"));
let output = OutFile::from_path(PathBuf::from("output.png"));
let options = Options::from_preset(4);
let (before, after) = optimize(&input, &output, &options)?;
println!("{before} -> {after} bytes: output.png");
Ok(())
}
Desde png-optimize, ejecuta:
cargo run --release
El programa lee input.png con una ruta relativa al directorio actual, escribe
output.png y muestra los recuentos de bytes de entrada y salida devueltos por
optimize. Si ya existe
output.png, se reemplaza sin pedir confirmación. Que los recuentos sean iguales
es un resultado válido, no un fallo.
OutFile::from_path elige un archivo separado y no solicita
la conservación de atributos. Usa OutFile::None para una prueba de la biblioteca
sin escritura, o OutFile::Path { path: Some(PathBuf::from("output.png")), preserve_attrs: true } cuando necesites que el archivo de salida conserve
los permisos y la hora de modificación del archivo de entrada.
Maneja entradas fallidas en una compilación
Una entrada ausente o malformada hace que la CLI termine con un error. El ejemplo de Rust propaga
PngError mediante ?, por lo que también termina con
un error y no muestra los recuentos de bytes de una ejecución correcta. Ejecútalo una vez sin
input.png para ver esta ruta de error. Un directorio de salida ausente o un
error de permisos de escritura también pueden hacer que la operación falle.
Comprueba el estado de salida antes de utilizar un archivo de salida: puede seguir existiendo un resultado anterior después de una ejecución fallida. Una optimización correcta tampoco equivale a una reducción de tamaño. Al compilar los archivos del proyecto, trata los fallos como errores y registra los recuentos reales de bytes en lugar de exigir un ahorro fijo.
