Questão Conversão em lote de PNG para JPG no linux


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 poderia colocar em um script de shell seria ideal.


141


origem




Respostas:


Sua melhor aposta seria usar Imagemagick

Eu não sou um especialista no uso real, mas eu sei que você pode fazer qualquer coisa relacionada com 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 (da mesma linha de comando quando no imagemagick). Tenha em mente que isso sobrescreve as imagens antigas.

O comando é:

mogrify -format jpg *.png  

210



Incrível, isso é exatamente o que eu estava depois e vou usar novamente. By the way, apenas para esclarecer como eu não percebi isso é o que você quis dizer: converter é usado para gerar um arquivo de saída separado, mogrify é usado para modificar a imagem original. - nedned
png imagens com fundo transparente não converte corretamente para jpg. - vishnu
Para converter PNGs com fundo transparente, use o seguinte comando: mogrify -format jpg -background black -flatten *.png - hyperknot
@ KevinCox na minha caixa de linux depois mogrify -format jpeg img.png Eu tenho 2 arquivos e file img.* relata um png, o original intocado e um novo jpeg. assim mogrify faz não Sobrescrever arquivos originais neste caso. - neurino
A partir de mogrify documentação: "Esta ferramenta é semelhante a convert exceto que o arquivo de imagem original é sobrescrito (a menos que você altere o sufixo do arquivo -formato opção) com todas as alterações solicitadas." - janko-m


Eu tenho mais algumas soluções.

A solução mais simples é como a maioria já postada. Um simples golpe para loop.

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

Por alguma razão eu costumo evitar loops no bash, então aqui está uma abordagem xargs mais unixy, usando bash para o nome-mangling.

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

O que eu uso. Ele usa o GNU Parallel para executar várias tarefas de uma só vez, oferecendo um aumento de desempenho. Ele é instalado por padrão em muitos sistemas e está quase definitivamente em seu repositório (é um bom programa para ter por perto).

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

O número de trabalhos é padronizado para o número de processos que você possui. Eu 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'

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

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

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

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

67



+1 para a expansão correta do string bash no for, se eu pudesse lhe dar outro upvote para mencionar o parallel, eu faria. Há um erro de digitação, no entanto - você precisa de um done no final desse loop. Além disso, para as coisas paralelas, você poderia evitar usar isso lse cano com uma construção como: parallel -j 3 --eta convert '{}' '{.}.jpg' ::: *.png (Vejo 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 eu prefiro não usar loops no bash. Eu coloquei a solução, porque é provavelmente a maneira mais "adequada", mas eu provavelmente vou ficar com o ls método para mim porque faz mais sentido para mim. - Kevin Cox
... embora deva ser notado que essa sintaxe funciona apenas no GNU paralelo. O paralelo que é 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, falta frustrantemente alguns dos recursos do GNU paralelo. - evilsoup
(embora aqueles em distros que não empacotam o GNU paralelo possam instalá-lo da fonte com bastante facilidade, usando as instruções Aqui) - evilsoup
Acho que devo mudar isso para que funcione com tantas versões quanto possível. - Kevin Cox


o convert O comando encontrado em muitas distribuições Linux é instalado como parte do pacote ImageMagick. Aqui está o código bash para executar convert em 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

25



De acordo com a página man do convert: "O programa convert é um membro do conjunto de ferramentas ImageMagick (1)". - nedned
Você está certo. Por alguma razão, achei que fazia parte de uma biblioteca diferente. De qualquer forma, o código que eu postei acima é a maneira correta de automatizar a conversão em lote dentro de um diretório. - Marcin
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 que é sensível a maiúsculas. Minha câmera nomeou como * .JPG e não percebeu isso em primeira instância. - tsenapathy


O real "png2jpg"comando que você está procurando é, na realidade, dividido em dois comandos chamados pngtopnm e cjpeg, e eles são parte do netpbm e libjpeg-progs pacotes, respectivamente.

png2pnm foo.png | cjpeg > foo.jpeg

7





tl; dr

Para aqueles que querem apenas os comandos mais simples:

Converter e guarda arquivos originais:

mogrify -format jpg *.png

Converter e remover arquivos originais:

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

Conversão em lote explicada

Meio tarde para a festa, mas só para esclarecer toda a confusão para alguém que pode não estar muito confortável com cli, aqui está uma referência e explicação super idiotas.

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

  • mocrificar faz parte do ImageMagick conjunto de ferramentas para processamento de imagens.
    • mocrificar processos imagens no lugar, ou seja, o arquivo original é sobrescrito, com exceção do arquivo -format opção. (Por o 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))
  • o - format opção especifica que você estará alterando o formato, e o próximo argumento precisa ser o tipo (neste caso, jpg).
  • Por fim, *.png é os arquivos de entrada (todos os arquivos terminados em .png).

Converter e Remover

Converte todos os arquivos png para jpg, remove 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 0 significa sem erros.
    • Desde a && realiza avaliação de curto-circuito, a parte direita só será executada se não houve erros. Isso é útil porque você pode não querer excluir todos os arquivos originais se houver um erro ao convertê-los.
  • o rm comando exclui arquivos.

Coisa chique

Agora, aqui estão algumas guloseimas para as pessoas que estamos Confortável 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 deles:

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 all diretório, numerá-los, remover arquivos originais png e exibir a saída para cada arquivo como 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

6



Provavelmente a melhor resposta desde que você se livrar do while read parte (substituí-lo ou removê-lo todos juntos) ... - don_crissti
@don_crissti, o que há de errado com a leitura? - Steven Jeffries
É 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 JPG padrão e como os registros de data e hora dos arquivos podem ser preservados? - Dan Dascalescu
@DanDascalescu Os métodos acima (exceto o último) preservarão nomes de arquivos, mas substituirão suas extensões, portanto os arquivos com timestamp devem estar ok (sempre faça uma cópia e teste primeiro). De acordo com o ImageMagick, "O padrão é usar a qualidade estimada de sua imagem de entrada, se ela puder ser determinada, caso contrário, 92" (imagemagick.org/script/command-line-options.php#quality) A qualidade pode ser especificada com -qualidade <número> em que <número> é de 1 a 100. - Steven Jeffries


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

4



Obrigado por um diretório profundo / recursivo solução de uma linha que deixa o resultado *.jpg arquivos ao lado do original *.png arquivos, mostra como reduzir o tamanho / qualidade do arquivo e não quebra por causa de quaisquer caracteres estranhos no diretório ou nome do arquivo. - Joel Purra


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


3



Isso tem que ser uma das linhas de comando mais feias e complicadas que eu já vi - evilsoup
@evilsoup honestamente, isso é elegante para scripts de shell. Afirmar que é complicado não é justo. - Max Howell
@MaxHowell homem. Não. Aqui seria uma versão elegante disso: for f in ./*.png; do convert "$f" "${f%.*}.jpg"; done. Isso evita completamente desnecessário ls, grep e sed chamadas (e echo, mas IIRC que é um bash builtin e assim não terá impacto de desempenho / muito pouco), e se livrar de dois tubos e duas subcasas, e envolve menos digitação. É até um pouco mais portátil, já que nem todas as versões do ls são seguros para analisar. - evilsoup
@evilsoup Eu estou corrigido! Bom trabalho. - Max Howell


Para processamento em lote:

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

Você vai acabar com nomes de arquivos como image1.png.jpg embora.

Isso vai funcionar na festa e talvez no bourne. Eu não sei sobre outros shells, mas a única diferença provavelmente seria a sintaxe do loop.


2





Muitos anos atrasado, há um png2jpeg utilitário especificamente para este 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

2





Isso é o que eu uso para converter quando os arquivos abrangem mais de um diretório. Meu original foi TGA para PNG

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

O conceito é você find os arquivos que você precisa, retire a extensão e adicione-a novamente xargs. Assim, para PNG para JPG, você mudaria as extensões e faria uma coisa extra para lidar com canais alfa, ou seja, definir o plano de fundo (neste exemplo, branco, mas você pode alterá-lo) e, em seguida, nivelar a imagem

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

0