Conversione batch di PNG in JPG in Linux


163

Qualcuno conosce un buon modo per convertire in batch un sacco di PNG in JPG in Linux? (Sto usando Ubuntu).

Un binario png2jpg che potrei semplicemente inserire in uno script di shell sarebbe l'ideale.

Risposte:


237

La tua scommessa migliore sarebbe usare Imagemagick

Non sono un esperto nell'uso effettivo, ma so che puoi praticamente fare qualsiasi immagine relativa a questo!

Un esempio è:

convert image.png image.jpg

e manterrà l'originale oltre a creare l'immagine convertita. Per quanto riguarda il lotto. Penso che devi usare lo strumento Mogrify (dalla stessa riga di comando quando sei in imagemagick). Tieni presente che questo sovrascrive le vecchie immagini.

Il comando è:

mogrify -format jpg *.png  

7
Fantastico, è esattamente quello che stavo cercando e che userò di nuovo. A proposito, solo per chiarire perché non avevo capito che questo era ciò che intendevi: convert è usato per generare un file di output separato, mogrify è usato per modificare l'immagine originale.
nedned il

1
le immagini png con sfondo trasparente non vengono convertite correttamente in jpg.
Vishnu,

4
Per convertire PNG con sfondo trasparente, usa il seguente comando:mogrify -format jpg -background black -flatten *.png
hyperknot,

3
@KevinCox sulla mia scatola di Linux dopo mogrify -format jpeg img.pngche ho 2 file e file img.*riporta un png, l'originale intatto e uno nuovo jpeg. Quindi mogrifynon non sovrascrivere i file originali in questo caso.
neurino,

4
Dalla mogrifydocumentazione: " Questo strumento è simile all'eccezione del convertfatto che il file di immagine originale viene sovrascritto (a meno che non si cambi il suffisso del file con l' opzione -format ) con qualsiasi modifica richiesta. "
janko-m

82

Ho un altro paio di soluzioni.

La soluzione più semplice è come la maggior parte già pubblicata. Un semplice bash per loop.

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

Per qualche motivo, tendo ad evitare i loop in bash, quindi ecco un approccio xargs più univoco, usando bash per la modifica del nome.

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

Quello che uso. Utilizza GNU Parallel per eseguire più lavori contemporaneamente, aumentando le prestazioni. È installato di default su molti sistemi ed è quasi sicuramente nel tuo repository (è un buon programma da avere in giro).

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

Il numero di lavori predefinito è il numero di processi che hai. Ho trovato un migliore utilizzo della CPU usando 3 lavori sul mio sistema dual-core.

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

E se vuoi delle statistiche (un ETA, lavori completati, tempo medio per lavoro ...)

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

Esiste anche una sintassi alternativa se si utilizza GNU Parallel.

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

E una sintassi simile per alcune altre versioni (incluso debian).

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

2
+1 per l'espansione corretta della stringa bash nel for, se potessi darti un altro voto per menzionare il parallelo, lo farei. C'è un errore di battitura, tuttavia - è necessario un donealla fine di quello per il ciclo. Inoltre, per le cose parallele, potresti evitare di usarlo lse pipe con un costrutto come: parallel -j 3 --eta convert '{}' '{.}.jpg' ::: *.png(vedi qui )
evilsoup

Errore di battitura fisso. Questa è una sintassi interessante che non conoscevo. Non so quale mi piace di più per lo stesso motivo per cui preferisco non usare loop in bash. Ho messo la soluzione perché è probabilmente il modo più "corretto", ma probabilmente seguirò il lsmetodo per me stesso perché ha più senso per me.
Kevin Cox,

1
... anche se va notato che quella sintassi funziona solo su parallelo GNU. Il parallelo che è impacchettato in alcune distribuzioni di Linux (come Debian e Ubuntu) è in realtà una versione diversa con una sintassi leggermente diversa (usa --piuttosto che :::) - e anche in questo caso, manca frustrantemente alcune delle caratteristiche del parallelo GNU.
evilsoup,

(anche se quelli su distribuzioni che non comprimono GNU parallel possono installarlo abbastanza facilmente dalla sorgente, usando le istruzioni qui )
evilsoup

Penso che dovrei cambiarlo allora in modo che funzioni con quante più versioni possibili.
Kevin Cox,

26

Il convertcomando trovato su molte distribuzioni Linux è installato come parte della suite ImageMagick. Ecco il codice bash da eseguire convertsu tutti i file PNG in una directory ed evitare quel doppio problema di estensione:

for img in *.png; do
    filename=${img%.*}
    convert "$filename.png" "$filename.jpg"
done

8
Secondo la pagina man per convert: "Il programma convert è un membro della suite di strumenti ImageMagick (1)".
nedned il

1
Hai ragione. Per qualche ragione ho pensato che facesse parte di un'altra libreria. In entrambi i casi il codice che ho pubblicato sopra è il modo corretto di automatizzare la conversione batch all'interno di una directory.
Marcin,

2
Puoi usare l'espansione bash per migliorare quel comando come:for f in *.png; do convert "$f" "${f/%png/jpg}"; done
evilsoup,

ricorda solo che è case sensitive. la mia macchina fotografica lo chiama come * .JPG e non me ne sono reso conto in primo luogo.
tsenapatia il

10

tl; dr

Per coloro che vogliono solo i comandi più semplici:

Converti e conserva i file originali:

mogrify -format jpg *.png

Converti e rimuovi file originali:

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

Spiegazione della conversione in lotti

Un po 'tardi alla festa, ma solo per chiarire tutta la confusione per qualcuno che potrebbe non essere molto a suo agio con cli, ecco un riferimento e una spiegazione super stupidi.

Directory di esempio

bar.png
foo.png
foobar.jpg

Converti semplice

Mantiene tutti i file png originali e crea file jpg.

mogrify -format jpg *.png

Risultato

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

Spiegazione

  • mogrify fa parte della suite di strumenti ImageMagick per l'elaborazione delle immagini.
    • mogrify elabora le immagini sul posto , il che significa che il file originale viene sovrascritto, ad eccezione -formatdell'opzione. (Dal sito : This tool is similar to convert except that the original image file is overwritten (unless you change the file suffix with the -format option))
  • L' - formatopzione specifica che modificherai il formato e il prossimo argomento deve essere il tipo (in questo caso, jpg).
  • Infine, *.pngsono i file di input (tutti i file che terminano con .png).

Converti e rimuovi

Converte tutti i file png in jpg, rimuove l'originale.

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

Risultato

bar.jpg
foo.jpg
foobar.jpg

Spiegazione

  • La prima parte è esattamente la stessa di sopra, creerà nuovi file jpg.
  • Il &&è un operatore booleano. In breve:
    • Quando un programma termina, restituisce uno stato di uscita. Uno stato di 0significa nessun errore.
    • Poiché &&esegue la valutazione del corto circuito , la parte giusta verrà eseguita solo se non ci sono errori . Questo è utile perché potresti non voler eliminare tutti i file originali se si è verificato un errore durante la loro conversione.
  • Il rmcomando elimina i file.

Roba di fantasia

Ora ecco alcune chicche per le persone che si sentono a proprio agio con il cli.

Se vuoi un output mentre sta convertendo i file:

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

Converti tutti i file png in tutte le sottodirectory e dai un output per ognuno:

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

Converti tutti i file png in tutte le sottodirectory, inserisci tutti i jpg risultanti nella alldirectory, numerali , rimuovi i file png originali e visualizza l'output per ogni file mentre si svolge:

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

Probabilmente la migliore risposta a patto di sbarazzarsi della while readparte (sostituirla o rimuoverla tutta insieme) ...
don_crissti,

@don_crissti, cosa c'è che non va durante la lettura?
Steven Jeffries,

È soggetto a errori (a meno che tu non sia sicuro al 100% di avere a che fare con nomi di file sani) e lento (come in molto, molto, molto lento).
don_crissti,

Qual è la qualità JPG predefinita e come si possono conservare i timestamp dei file?
Dan Dascalescu il

@DanDascalescu I metodi sopra (tranne l'ultimo) conserveranno i nomi dei file, ma sostituiranno la loro estensione, quindi i file con timestamp dovrebbero essere a posto (fai sempre una copia e prova prima). Secondo ImageMagick, "L'impostazione predefinita è utilizzare la qualità stimata dell'immagine di input se può essere determinata, altrimenti 92" ( imagemagick.org/script/command-line-options.php#quality ) La qualità può essere specificata con -quality <numero> dove <numero> è compreso tra 1 e 100.
Steven Jeffries,

8

Il png2jpgcomando " " che stai cercando è in realtà diviso in due comandi chiamati pngtopnme cjpeg, e fanno parte rispettivamente dei pacchetti netpbme libjpeg-progs.

png2pnm foo.png | cjpeg > foo.jpeg

6
find . -name "*.png" -print0 | xargs -0 mogrify -format jpg -quality 50

1
Grazie per una soluzione a una riga di directory profonda / ricorsiva che lascia i *.jpgfile risultanti accanto ai *.pngfile originali , mostra come ridurre le dimensioni / la qualità del file e non si interrompe a causa di caratteri dispari nella directory o nel nome del file.
Joel Purra,

5

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


2
Questa deve essere una delle righe di comando più brutte e contorte che abbia mai visto
evilsoup,

1
@evilsoup onestamente, questo è elegante per gli script di shell. Affermare che è contorto non è giusto.
Max Howell,

8
@MaxHowell man. No. Qui sarebbe una versione elegante di questo: for f in ./*.png; do convert "$f" "${f%.*}.jpg"; done. Che evita il completamente inutili ls, grepe sedle chiamate (e echo, ma IIRC questo è un builtin Bash e così non avrà / molto poco impatto sulle prestazioni), e si libera di due tubi e due sotto-shell, e coinvolge meno di battitura. È anche leggermente più portatile, poiché non tutte le versioni di lssono sicure da analizzare.
evilsoup,

@evilsoup Sono corretto! Buon lavoro.
Max Howell,

4

Molti anni troppo tardi, c'è un'utilità png2jpeg appositamente per questo scopo, che ho creato.

Adattamento del codice di @Marcin:

#!/bin/sh

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

3

Per l'elaborazione batch:

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

Finirai con nomi di file come image1.png.jpg però.

Funzionerà in bash, e forse bourne. Non conosco altre shell, ma l'unica differenza sarebbe probabilmente la sintassi del loop.


1

Questo è ciò che uso per convertire quando i file si estendono su più di una directory. Il mio originale era da TGA a PNG

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

Il concetto è che sei findil file che ti serve, togli l'estensione e poi aggiungilo di nuovo con xargs. Quindi per PNG in JPG, dovresti cambiare le estensioni e fare una cosa in più per gestire i canali alfa, vale a dire impostare lo sfondo (in questo esempio bianco, ma puoi cambiarlo) quindi appiattire l'immagine

find . -name "*.png" -type f | sed 's/\.png$//' | xargs -I% convert %.png -background white -flatten  %.jpg
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.