Lote convertendo PNG para JPG no linux

163

Alguém sabe uma boa maneira de converter em lote um monte de PNGs em JPGs no linux? (Estou usando o Ubuntu).

Um binário png2jpg que eu pudesse colocar em um shell script seria o ideal.

nedned
fonte

Respostas:

237

Sua melhor aposta seria usar o Imagemagick

Não sou especialista no uso real, mas sei que você pode fazer praticamente qualquer imagem relacionada a isso!

Um exemplo é:

convert image.png image.jpg

e manterá o original, além de criar a imagem convertida. Quanto ao lote. Eu acho que você precisa usar a ferramenta Mogrify (na mesma linha de comando, quando estiver no imagemagick). Lembre-se de que isso substitui as imagens antigas.

O comando é:

mogrify -format jpg *.png  
William Hilsum
fonte
7
Incrível, era exatamente isso que eu procurava e usarei novamente. A propósito, só para esclarecer, como eu não percebi isso, o que você quis dizer: convert é usado para gerar um arquivo de saída separado, mogrify é usado para modificar a imagem original.
Nedned
11
imagens png com fundo transparente não são convertidas corretamente em jpg.
Vishnu
4
Para converter PNGs com fundo transparente, use o seguinte comando:mogrify -format jpg -background black -flatten *.png
hyperknot
3
@ KevinCox na minha caixa do linux depois de mogrify -format jpeg img.pngeu ter 2 arquivos e file img.*relatar um png, o original intocado e um novo jpeg. Portanto mogrify, não substitui os arquivos originais nesse caso.
Neurino 28/08/2013
4
Da mogrifydocumentação: " Esta ferramenta é semelhante a, convertexceto que o arquivo de imagem original é substituído (a menos que você altere o sufixo do arquivo com a opção -format ) com as alterações solicitadas. "
janko-m
82

Eu tenho mais algumas soluções.

A solução mais simples é como a maioria já publicada. Uma festança simples para loop.

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

Por alguma razão, eu tendem a evitar loops no bash, então aqui está uma abordagem xargs mais unix, usando o bash para a identificação de nomes.

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

O que eu uso. Ele usa o GNU Parallel para executar vários trabalhos ao mesmo tempo, oferecendo um aumento de desempenho. Ele é instalado por padrão em muitos sistemas e está quase definitivamente no seu repositório (é um bom programa para se ter por perto).

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

O número de trabalhos é padronizado com o número de processos que você possui. Encontrei melhor uso da CPU usando 3 tarefas no meu sistema dual-core.

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

E se você quiser algumas estatísticas (um ETA, trabalhos concluídos, tempo médio por trabalho ...)

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

Há também uma sintaxe alternativa se você estiver usando o GNU Parallel.

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

E uma sintaxe semelhante para algumas outras versões (incluindo debian).

parallel convert '{}' '{.}.jpg' -- *.png
Kevin Cox
fonte
2
+1 para a expansão correta da string bash no for, se eu pudesse lhe dar outro voto positivo por mencionar paralelo, eu o faria. Porém, há um erro de digitação - você precisa de um doneno final do loop for. Além disso, para o material paralela, você poderia evitar o uso que lse tubo com uma construção como: parallel -j 3 --eta convert '{}' '{.}.jpg' ::: *.png(ver aqui )
evilsoup
Corrigido erro de digitação. Essa é uma sintaxe legal que eu não conhecia. Eu não sei qual eu gosto mais, provavelmente pela mesma razão que prefiro não usar loops no bash. Eu coloquei a solução porque provavelmente é a maneira mais "adequada", mas provavelmente continuarei com o lsmétodo por mim mesmo, porque faz mais sentido para mim.
Kevin Cox
11
... embora se deva notar que essa sintaxe funciona apenas no GNU paralelo. O paralelo empacotado em algumas distribuições linux (como Debian e Ubuntu) é na verdade uma versão diferente com uma sintaxe ligeiramente diferente (use --ao invés de :::) - e mesmo assim, carece frustrantemente de alguns dos recursos do paralelo GNU.
precisa saber é
(embora aqueles em distros que não empacotar GNU paralelo pode instalá-lo a partir da fonte com bastante facilidade, usando as instruções aqui )
evilsoup
Acho que devo alterá-lo naquela época para que funcione com o maior número possível de versões.
Kevin Cox
26

O convertcomando encontrado em muitas distribuições Linux é instalado como parte do pacote ImageMagick. Aqui está o código bash para executar convertem todos os arquivos PNG em um diretório e evitar esse problema de extensão dupla:

for img in *.png; do
    filename=${img%.*}
    convert "$filename.png" "$filename.jpg"
done
Marcin
fonte
8
De acordo com a página do manual do convert: "O programa convert é um membro do conjunto de ferramentas ImageMagick (1)".
Nedned 16/11/2009
11
Você está certo. Por alguma razão, pensei que fazia parte de uma biblioteca diferente. De qualquer maneira, o código que publiquei acima é a maneira correta de automatizar a conversão em lote em um diretório.
217 Marcin
2
Você pode usar a expansão bash para melhorar esse comando como:for f in *.png; do convert "$f" "${f/%png/jpg}"; done
evilsoup
lembre-se de que diferencia maiúsculas de minúsculas. minha câmera o nomeou como * .JPG e não percebeu isso em primeira instância.
tsenapathy
10

tl; dr

Para quem quer apenas os comandos mais simples:

Converta e mantenha arquivos originais:

mogrify -format jpg *.png

Converta e remova arquivos originais:

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

Conversão de lote explicada

Meio atrasado para a festa, mas apenas para esclarecer toda a confusão de alguém que pode não estar muito confortável com o CLI, aqui está uma referência e explicação super estúpidas.

Diretório de exemplo

bar.png
foo.png
foobar.jpg

Conversão Simples

Mantém todos os arquivos png originais, bem como cria arquivos jpg.

mogrify -format jpg *.png

Resultado

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

Explicação

  • O mogrify faz parte do conjunto de ferramentas ImageMagick para processamento de imagens.
    • mogrify processa as imagens no local , o que significa que o arquivo original é substituído, com exceção da -formatopção. (A partir do site : This tool is similar to convert except that the original image file is overwritten (unless you change the file suffix with the -format option))
  • A - formatopção especifica que você alterará o formato e o próximo argumento precisa ser do tipo (neste caso, jpg).
  • Por fim, *.pngestão os arquivos de entrada (todos os arquivos que terminam em .png).

Converter e remover

Converte todos os arquivos png em jpg, remove o original.

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

Resultado

bar.jpg
foo.jpg
foobar.jpg

Explicação

  • A primeira parte é exatamente a mesma que acima, ela criará novos arquivos jpg.
  • O &&é um operador booleano. Em resumo:
    • Quando um programa termina, ele retorna um status de saída. Um status de 0significa sem erros.
    • Como &&realiza a avaliação de curto-circuito , a parte correta somente será executada se não houver erros . Isso é útil porque você pode não querer excluir todos os arquivos originais se houver um erro ao convertê-los.
  • O rmcomando exclui arquivos.

Coisa chique

Agora, aqui estão alguns presentes para as pessoas que se sentem confortáveis ​​com o CLI.

Se você quiser alguma saída enquanto estiver convertendo arquivos:

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

Converta todos os arquivos png em todos os subdiretórios e dê saída para cada um:

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

Converta todos os arquivos png em todos os subdiretórios, coloque todos os jpgs resultantes no alldiretório, numere- os, remova os arquivos png originais e exiba a saída de cada arquivo conforme ele ocorre:

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
fonte
Provavelmente a melhor resposta desde que você se livrar da while readparte (substituí-lo ou removê-lo todos juntos) ...
don_crissti
@don_crissti, o que há de errado com a leitura?
91116 Steven
É propenso a erros (a menos que você tenha 100% de certeza de que está lidando com nomes de arquivos sãos) e lento (como em muito, muito, muito lento).
don_crissti
Qual é a qualidade padrão do JPG e como preservar os carimbos de data e hora do arquivo?
Dan Dascalescu
@DanDascalescu Os métodos acima (exceto o último) preservarão os nomes de arquivos, mas substituirão sua extensão, para que os arquivos com registro de data e hora sejam aceitáveis ​​(sempre faça uma cópia e teste primeiro). De acordo com o ImageMagick, "O padrão é usar a qualidade estimada da sua imagem de entrada, se puder ser determinada, caso contrário, 92" ( imagemagick.org/script/command-line-options.php#quality ) A qualidade pode ser especificada com -quality <número> em que <número> é de 1 a 100.
Steven Jeffries
8

O png2jpgcomando " " real que você está procurando é, na realidade, dividido em dois comandos chamados pngtopnme cjpeg, e eles fazem parte dos pacotes netpbme libjpeg-progs, respectivamente.

png2pnm foo.png | cjpeg > foo.jpeg
Teddy
fonte
6
find . -name "*.png" -print0 | xargs -0 mogrify -format jpg -quality 50
emdog4
fonte
11
Obrigado por uma solução de linha única de diretório profundo / recursivo que deixa os *.jpgarquivos resultantes próximos aos *.pngarquivos originais , mostra como reduzir o tamanho / qualidade e não quebra por causa de caracteres estranhos no diretório ou no nome do arquivo.
Joel Purra
5

minha solução rápida for i in $(ls | grep .png); do convert $i $(echo $i.jpg | sed s/.png//g); done

max
fonte
2
Isso tem que ser uma das mais feias, mais complicadas linhas de comando que eu já vi
evilsoup
11
@evilsoup honestamente, isso é elegante para scripts de shell. Afirmar que é complicado não é justo.
Max Howell
8
@MaxHowell man. Não. Aqui seria uma versão elegante desta: for f in ./*.png; do convert "$f" "${f%.*}.jpg"; done. Isso evita o completamente desnecessário ls, grepe sedchama (e echo, mas o IIRC que é um bash embutido e, portanto, terá pouco / muito pouco impacto no desempenho) e se livra de dois pipes e dois subshells, e envolve menos digitação. É ainda um pouco mais portátil, pois nem todas as versões lssão seguras para analisar.
evilsoup
@evilsoup Fico corrigido! Bom trabalho.
Max Howell
4

Muitos anos tarde demais, existe um utilitário png2jpeg especificamente para esse fim, que eu criei.

Adaptando o código por @Marcin:

#!/bin/sh

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

Para processamento em lote:

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

Você terminará com nomes de arquivo como image1.png.jpg.

Isso funcionará no bash e talvez no bourne. Não conheço outras conchas, mas a única diferença provavelmente seria a sintaxe do loop.

Jeffrey Aylesworth
fonte
1

É isso que eu uso para converter quando os arquivos abrangem mais de um diretório. Meu original era TGA para PNG

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

O conceito é que findvocê precisa dos arquivos, retire a extensão e adicione-a novamente xargs. Portanto, para PNG e JPG, você alteraria as extensões e faria uma coisa extra para lidar com canais alfa: definir o plano de fundo (neste exemplo, branco, mas você pode alterá-lo) e achatar a imagem.

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