Conversión por lotes de PNG a JPG en Linux

163

¿Alguien sabe una buena manera de convertir por lotes un montón de PNG en JPG en Linux? (Estoy usando Ubuntu).

Un binario png2jpg que podría colocar en un script de shell sería ideal.

nedned
fuente

Respuestas:

237

Su mejor opción sería usar Imagemagick

No soy un experto en el uso real, ¡pero sé que puedes hacer casi cualquier imagen relacionada con esto!

Un ejemplo es:

convert image.png image.jpg

y mantendrá el original y creará la imagen convertida. En cuanto a lote. Creo que necesitas usar la herramienta Mogrify (desde la misma línea de comando cuando estás en imagemagick). Tenga en cuenta que esto sobrescribe las imágenes antiguas.

El comando es:

mogrify -format jpg *.png  
William Hilsum
fuente
77
Impresionante, eso es exactamente lo que estaba buscando y volveré a usar. Por cierto, solo para aclarar, ya que no me di cuenta de que esto es lo que querías decir: convertir se usa para generar un archivo de salida separado, mogrify se usa para modificar la imagen original.
nedned
1
Las imágenes png con fondo transparente no se convierten correctamente a jpg.
vishnu
44
Para convertir PNG con fondo transparente, use el siguiente comando:mogrify -format jpg -background black -flatten *.png
hyperknot
3
@KevinCox en mi cuadro de Linux después de mogrify -format jpeg img.pngque tengo 2 archivos e file img.*informes uno png, el original sin tocar y uno nuevo JPEG. Por mogrifylo tanto , no sobrescribe los archivos originales en este caso.
neurino
44
A partir de mogrifyla documentación: " Esta herramienta es similar a convertexcepción de que el archivo de imagen original se sobrescribe (a menos que cambie el sufijo archivo con el -format opción) con los cambios solicitados. "
janko-m
82

Tengo un par de soluciones más.

La solución más simple es como la mayoría ya publicada. Una simple bash para bucle.

for i in *.png ; do convert "$i" "${i%.*}.jpg" ; done

Por alguna razón, tiendo a evitar los bucles en bash, así que aquí hay un enfoque xargs más unixy, usando bash para el cambio de nombre.

ls -1 *.png | xargs -n 1 bash -c 'convert "$0" "${0%.*}.jpg"'

El que yo uso. Utiliza GNU Parallel para ejecutar múltiples trabajos a la vez, lo que le brinda un aumento de rendimiento. Se instala por defecto en muchos sistemas y está casi definitivamente en su repositorio (es un buen programa para tener).

ls -1 *.png | parallel convert '{}' '{.}.jpg'

El número de trabajos predeterminado es el número de procesos que tiene. Encontré un mejor uso de la CPU usando 3 trabajos en mi sistema de doble núcleo.

ls -1 *.png | parallel -j 3 convert '{}' '{.}.jpg'

Y si desea algunas estadísticas (una ETA, trabajos completados, tiempo promedio por trabajo ...)

ls -1 *.png | parallel --eta convert '{}' '{.}.jpg'

También hay una sintaxis alternativa si está utilizando GNU Parallel.

parallel convert '{}' '{.}.jpg' ::: *.png

Y una sintaxis similar para algunas otras versiones (incluida debian).

parallel convert '{}' '{.}.jpg' -- *.png
Kevin Cox
fuente
2
+1 para la expansión correcta de la cadena bash en for, si pudiera darle otro voto positivo por mencionar el paralelo, lo haría. Sin embargo, hay un error tipográfico: necesita un donefinal para ese bucle. Además, para las cosas paralelas, podría evitar usar eso lsy canalizar con una construcción como: parallel -j 3 --eta convert '{}' '{.}.jpg' ::: *.png(ver aquí )
evilsoup
Error tipográfico fijo. Esa es una sintaxis genial que no conocía. No sé cuál me gusta más, probablemente por la misma razón por la que prefiero no usar bucles en bash. Puse la solución porque probablemente sea la forma más "adecuada", pero probablemente me quede con el lsmétodo porque tiene más sentido para mí.
Kevin Cox
1
... aunque debe tenerse en cuenta que esa sintaxis solo funciona en GNU paralelo. El paralelo que está empaquetado en algunas distribuciones de Linux (como Debian y Ubuntu) es en realidad una versión diferente con una sintaxis ligeramente diferente (usar en --lugar de :::), e incluso entonces, carece frustrantemente de algunas de las características del paralelo GNU.
evilsoup
(aunque aquellos en distribuciones que no empaquetan GNU en paralelo pueden instalarlo desde la fuente con bastante facilidad, siguiendo las instrucciones aquí )
evilsoup
Creo que debería cambiarlo en ese entonces para que funcione con tantas versiones como sea posible.
Kevin Cox
26

El convertcomando que se encuentra en muchas distribuciones de Linux se instala como parte de la suite ImageMagick. Aquí está el código bash para ejecutarse converten todos los archivos PNG en un directorio y evitar ese problema de doble extensión:

for img in *.png; do
    filename=${img%.*}
    convert "$filename.png" "$filename.jpg"
done
Marcin
fuente
8
Según la página del manual para convertir: "El programa de conversión es miembro del conjunto de herramientas ImageMagick (1)".
nedned
1
Estás en lo correcto. Por alguna razón, pensé que era parte de una biblioteca diferente. De cualquier manera, el código que publiqué anteriormente es la forma correcta de automatizar la conversión por lotes dentro de un directorio.
Marcin el
2
Puede usar la expansión bash para mejorar ese comando como:for f in *.png; do convert "$f" "${f/%png/jpg}"; done
evilsoup
solo recuerda que es sensible a mayúsculas y minúsculas. mi cámara lo nombró como * .JPG y no me di cuenta de esto en primera instancia.
tsenapathy
10

tl; dr

Para aquellos que solo quieren los comandos más simples:

Convierte y guarda archivos originales:

mogrify -format jpg *.png

Convierte y elimina archivos originales:

mogrify -format jpg *.png && rm *.png

Conversión por lotes explicada

Un poco tarde para la fiesta, pero solo para aclarar toda la confusión para alguien que puede no estar muy cómodo con cli, aquí hay una referencia y explicación súper tonta.

Directorio de ejemplo

bar.png
foo.png
foobar.jpg

Conversión simple

Mantiene todos los archivos png originales y crea archivos jpg.

mogrify -format jpg *.png

Resultado

bar.png
bar.jpg
foo.png
foo.jpg
foobar.jpg

Explicación

  • mogrify es parte del conjunto de herramientas ImageMagick para el procesamiento de imágenes.
    • mogrify procesa las imágenes en su lugar , lo que significa que el archivo original se sobrescribe, con la excepción de la -formatopción. (Desde el sitio : This tool is similar to convert except that the original image file is overwritten (unless you change the file suffix with the -format option))
  • La - formatopción especifica que va a cambiar el formato, y el siguiente argumento debe ser el tipo (en este caso, jpg).
  • Por último, *.pngson los archivos de entrada (todos los archivos que terminan en .png).

Convertir y quitar

Convierte todos los archivos png a jpg, elimina el original.

mogrify -format jpg *.png && rm *.png

Resultado

bar.jpg
foo.jpg
foobar.jpg

Explicación

  • La primera parte es exactamente igual a la anterior, creará nuevos archivos jpg.
  • El &&es un operador booleano. En breve:
    • Cuando un programa termina, devuelve un estado de salida. Un estado de 0significa sin errores.
    • Dado que &&realiza una evaluación de cortocircuito , la parte correcta solo se realizará si no hubo errores . Esto es útil porque es posible que no desee eliminar todos los archivos originales si hubo un error al convertirlos.
  • El rmcomando elimina archivos.

Cosas lujosas

Ahora aquí hay algunas golosinas para las personas que se sienten cómodas con el cli.

Si quieres algo de salida mientras está convirtiendo archivos:

for i in *.png; do mogrify -format jpg "$i" && rm "$i"; echo "$i converted to ${i%.*}.jpg"; done

Convierta todos los archivos png en todos los subdirectorios y dé salida para cada uno:

find . -iname '*.png' | while read i; do mogrify -format jpg "$i" && rm "$i"; echo "Converted $i to ${i%.*}.jpg"; done

Convierta todos los archivos png en todos los subdirectorios, coloque todos los jpgs resultantes en el alldirectorio, numerelos , elimine los archivos png originales y muestre la salida de cada archivo a medida que se realiza:

n=0; find . -iname '*.png' | while read i; do mogrify -format jpg "$i" && rm "$i"; fn="all/$((n++)).jpg"; mv "${i%.*}.jpg" "$fn"; echo "Moved $i to $fn"; done
Steven Jeffries
fuente
Probablemente la mejor respuesta siempre que se deshaga de la while readpieza (reemplácela o retírela por completo) ...
don_crissti
@don_crissti, ¿qué tiene de malo leer?
Steven Jeffries
Es propenso a errores (a menos que esté 100% seguro de que está tratando con nombres de archivos sanos) y lento (como en muy, muy, muy lento).
don_crissti
¿Cuál es la calidad JPG predeterminada y cómo se pueden conservar las marcas de tiempo del archivo?
Dan Dascalescu
@DanDascalescu Los métodos anteriores (excepto el último) conservarán los nombres de los archivos, pero reemplazarán su extensión, por lo que los archivos con sello de tiempo deberían estar bien (siempre haga una copia y pruebe primero). Según ImageMagick, "El valor predeterminado es utilizar la calidad estimada de su imagen de entrada si se puede determinar, de lo contrario 92" ( imagemagick.org/script/command-line-options.php#quality ) La calidad se puede especificar con -quality <número> donde <número> es del 1 al 100.
Steven Jeffries
8

El png2jpgcomando " " real que está buscando se divide en realidad en dos comandos llamados pngtopnmy cjpeg, y son parte de los paquetes netpbmy libjpeg-progs, respectivamente.

png2pnm foo.png | cjpeg > foo.jpeg
Osito de peluche
fuente
6
find . -name "*.png" -print0 | xargs -0 mogrify -format jpg -quality 50
emdog4
fuente
1
Gracias por una solución de directorio de línea profunda / recursiva que deja los *.jpgarchivos resultantes al lado de los *.pngarchivos originales , muestra cómo reducir el tamaño / calidad del archivo y no se rompe debido a los caracteres extraños en el directorio o el nombre del archivo.
Joel Purra
5

mi solucion rapida for i in $(ls | grep .png); do convert $i $(echo $i.jpg | sed s/.png//g); done

max
fuente
2
Esta tiene que ser una de las líneas de comando más feas y enrevesadas que he visto jamás
evilsoup
1
@evilsoup honestamente, esto es elegante para los scripts de shell. Afirmar que es complicado no es justo.
Max Howell
8
@MaxHowell hombre. No. Aquí sería una versión elegante de este: for f in ./*.png; do convert "$f" "${f%.*}.jpg"; done. Eso evita los completamente innecesarios ls, grepy sedlas llamadas (y echo, pero IIRC que es una fiesta de orden interna y por lo tanto no tendrá ningún / muy poco impacto en el rendimiento), y se deshace de dos tubos y dos subniveles, y cuenta con menores a escribir. Es incluso un poco más portátil, ya que no todas las versiones lsson seguras de analizar.
evilsoup
@evilsoup ¡Estoy corregido! Buen trabajo.
Max Howell el
4

Muchos años demasiado tarde, hay una utilidad png2jpeg específicamente para este propósito, que escribí .

Adaptando el código por @Marcin:

#!/bin/sh

for img in *.png
do
    filename=${img%.*}
    png2jpeg -q 95 -o "$filename.jpg" "$filename.png"
done
usuario7023624
fuente
3

Para procesamiento por lotes:

for img in *.png; do
  convert "$img" "$img.jpg"
done

Sin embargo, terminarás con nombres de archivo como image1.png.jpg.

Esto funcionará en bash, y quizás en bourne. No sé sobre otros shells, pero la única diferencia probablemente sería la sintaxis del bucle.

Jeffrey Aylesworth
fuente
1

Esto es lo que uso para convertir cuando los archivos abarcan más de un directorio. Mi original era TGA a PNG

find . -name "*.tga" -type f | sed 's/\.tga$//' | xargs -I% convert %.tga %.png

El concepto es que tienes findlos archivos que necesitas, quita la extensión y luego vuelve a agregarla xargs. Entonces, para PNG a JPG, cambiaría las extensiones y haría una cosa adicional para lidiar con los canales alfa, a saber, establecer el fondo (en este ejemplo blanco, pero puede cambiarlo) y luego aplanar la imagen

find . -name "*.png" -type f | sed 's/\.png$//' | xargs -I% convert %.png -background white -flatten  %.jpg
Arquímedes Trajano
fuente