Como faço para converter um svgpara png, em Python? Estou armazenando svgem uma instância de StringIO. Devo usar a biblioteca pyCairo? Como faço para escrever esse código?
Esse tópico deixou o problema sem solução. A resposta aceita veio do autor da pergunta que estava compartilhando sua tentativa de código falhada. A outra resposta sugeria ImageMagick, mas um comentarista disse que ImageMagick faz "um trabalho horrível de interpretação de SVG." Eu não quero que meus pngs pareçam horríveis, então estou fazendo a pergunta novamente.
Os exemplos nesse link são específicos para Win32. Estou executando o Linux.
ram1
Dê uma olhada nesta postagem do blog, parece que pode ser o que você precisa.
giodamelio
Respostas:
60
A resposta é " pyrsvg " - uma ligação Python para librsvg .
Existe um pacote Ubuntu python-rsvg que o fornece. Pesquisar seu nome no Google é ruim porque seu código-fonte parece estar contido no repositório GIT do projeto Gnome "gnome-python-desktop".
Fiz um "hello world" minimalista que renderiza SVG em uma superfície do Cairo e grava em disco:
Atualização : a partir de 2014 o pacote necessário para a distribuição Fedora Linux é: gnome-python2-rsvg. A lista de trechos acima ainda funciona como está.
Ótimo, funciona bem. Mas existe uma maneira de cairodeterminar a ALTURA e a LARGURA da imagem por conta própria? Verifiquei o *.svgarquivo para extrair ALTURA e LARGURA de lá, mas ambos estão configurados para 100%. Claro, posso examinar as propriedades da imagem, mas, como essa é apenas uma etapa do processamento da imagem, não é isso que eu quero.
quapka
1
Se a "largura" e a "altura" dos seus arquivos estão definidas para 100%, não há mágica que Cairo ou rsvg possam fazer para adivinhar o tamanho: esses arquivos SVG foram deixados em tamanho independente pelo software criador (/ pessoa). O código HTML circundante para importar o arquivo SVG forneceria o tamanho físico. No entanto, o objeto "Handle" do rsvg tem um .get_dimension_data()método que funcionou para o meu arquivo de exemplo (um SVG bem comportado) - experimente.
jsbueno
1
a partir de 2014, para ubuntu, você pode usar: apt-get install python-rsvg
t1m0
1
Existe um comando rápido para adicionar um fundo branco à imagem se o fundo atual for transparente?
fiatjaf
@jsbueno Eu uso o Windows 8.1 e python 2.7.11 Como posso instalar o Cairo e o rsvg e fazer com que funcionem. Eu estava lutando para fazer isso funcionar. BTW +1 para sua explicação detalhada.
Oi. Você sabe como posso fazer o mesmo, mas sem gravar em um arquivo? Preciso enviar o conteúdo do png para o navegador a partir de um servidor da web, para que o usuário possa baixar a imagem. Salvar o arquivo png não é uma opção válida em nosso projeto, por isso preciso disso. Obrigado
estemendoza
4
Eu tenho feito isso sozinho. Basicamente depende de quais ferramentas ou estruturas você tem em mãos ao lidar com suas solicitações da web, mas não importa o que seja, a ideia básica é que svg2pngleva um streamobjeto no write_toparâmetro, e este pode ser seu objeto de resposta HTTP (que em a maioria das estruturas é um objeto semelhante a um arquivo) ou algum outro fluxo, que você serve ao navegador usando o Content-Dispositioncabeçalho. veja aqui: stackoverflow.com/questions/1012437/…
nemesisfixx
4
Para quem tem problemas com esse código, como eu: 1). bytestringaceita bytes, portanto, converta primeiro a string com bytestring=bytes(svg,'UTF-8') 2). o modo de arquivo deve ser binário, entãoopen('output.png','wb')
Serj Zaharchenko
3
cairosvg oferece suporte apenas a Python 3.4+. Eles abandonaram o suporte ao Python 2
Marlon Abeykoon,
1
Não havia um svg2pngpara mim, eu tinha que usar cairosvg.surface.PNGSurface.convert(svg_str, write_to='output.png').
tobltobs
39
Instale o Inkscape e chame-o como linha de comando:
Você também pode capturar uma área retangular específica usando apenas o parâmetro -j, por exemplo, coordenada "0: 125: 451: 217"
${INKSCAPE_PATH}-z -f ${source_svg}-w ${width}-j -a ${coordinates}-e ${dest_png}
Se quiser mostrar apenas um objeto no arquivo SVG, você pode especificar o parâmetro -icom o id do objeto que você configurou no SVG. Ele esconde todo o resto.
${INKSCAPE_PATH}-z -f ${source_svg}-w ${width}-i ${object}-j -a ${coordinates}-e ${dest_png}
+1 porque isso também é extremamente útil para scripts de shell. Veja inkscape.org/doc/inkscape-man.html para documentos completos sobre a linha de comando do Inkscape.
Dia
Obrigado, esta foi a maneira mais fácil que encontrei de fazer isso. No Windows, para que você não precise digitar o caminho completo para o Inkscape todas as vezes, você pode adicioná-lo ao seu Caminho nas Variáveis Ambientais .
Alex S
3
Esta não é uma resposta. É uma solução alternativa. OP pediu uma solução Python.
lamino
31
Estou usando o Wand-py (uma implementação do wrapper Wand em torno do ImageMagick) para importar alguns SVGs bastante avançados e até agora tenho visto ótimos resultados! Este é todo o código necessário:
with wand.image.Image( blob=svg_file.read(), format="svg")as image:
png_image = image.make_blob("png")
Acabei de descobrir isso hoje e senti que valia a pena compartilhar com qualquer pessoa que possa ter dúvidas sobre essa resposta, pois já faz um tempo que a maioria dessas perguntas não foi respondida.
NOTA: Tecnicamente em testes, descobri que você nem mesmo precisa passar o parâmetro de formato para ImageMagick, então with wand.image.Image( blob=svg_file.read() ) as image:foi tudo o que realmente foi necessário.
EDIT: A partir de uma tentativa de edição por qris, aqui está um código útil que permite usar o ImageMagick com um SVG que tem um fundo transparente:
Wand funcionou muito melhor do que Cairo para meus PNGs.
qris
3
Recebo o erro image.read(blob=svg_file.read(), format="svg") NameError: name 'svg_file' is not defined
adrienlucca.wordpress.com
2
svg_fileé considerado um objeto "arquivo" neste exemplo, a configuração svg_fileseria algo como:svg_file = File.open(file_name, "r")
streetlogics
2
Obrigado, o método cairoe rsvg'aceito' não funcionou para o meu PDF. pip install wande seu snippet funcionou;)
nmz787
5
Se você tem um SVG str, em seguida, você primeiro precisa codificar em binário da seguinte forma: svg_blob = svg_str.encode('utf-8'). Agora você pode usar o método acima, substituindo blob=svg_file.read()por blob=svg_blob.
Infelizmente, há dois problemas com isso. Primeiro, ele não lida com o <clipPath><rect ... /></clipPath>. Em segundo lugar, não é necessária a opção -d (DPI).
Raio de
2
@Ray, envie relatórios de erros / solicitações de recursos no rastreador CairoSVG !
Simon Sapin
@Simon, você pode fazer isso por favor? Estou muito ocupado e estarei nos próximos 1-2 meses.
Ray
2
@Ray, na verdade a opção -d / --dpi já existe há um tempo, e fui informado que o suporte para <clippath> foi adicionado algumas semanas atrás na versão git.
Eu usei a extração de largura e altura SVG. Não tenho certeza sobre o padrão svg, mas em alguns dos meus arquivos svg a largura ou altura eram seguidas por uma string não numérica, como 'mm' ou 'px' (ex: '250mm'). O int ('250mm') lança uma exceção e eu tive que fazer alguns ajustes adicionais.
WigglyWorld
3
Não achei nenhuma das respostas satisfatória. Todas as bibliotecas mencionadas têm algum problema ou outro, como Cairo abandonando o suporte para python 3.6 (elas abandonaram o suporte para Python 2 há cerca de 3 anos!). Além disso, instalar as bibliotecas mencionadas no Mac foi uma dor.
Finalmente, descobri que a melhor solução era svglib + reportlab . Ambos instalados sem problemas usando pip e a primeira chamada para converter de SVG para PNG funcionaram perfeitamente! Muito feliz com a solução.
Apenas 2 comandos fazem o truque:
from svglib.svglib import svg2rlg
from reportlab.graphics import renderPM
drawing = svg2rlg("my.svg")
renderPM.drawToFile(drawing,"my.png", fmt="PNG")
Há alguma limitação dessas que eu deva estar ciente?
Usando pycairo e librsvg, consegui dimensionar SVG e renderizar para um bitmap. Supondo que seu SVG não seja exatamente 256x256 pixels, a saída desejada, você pode ler no SVG para um contexto Cairo usando rsvg e, em seguida, dimensioná-lo e gravar em PNG.
Obrigado por isso, foi muito útil em um projeto meu. Embora Handle.get_dimension_datanão funcione para mim. Tive que substituí-lo por uma simples busca de self.props.widthe self.props.height. Tentei primeiro definir a RsvgDimensionDataEstrutura conforme descrito no site do cairo, mas sem sucesso.
JeanOlivier
Estou tentando usar isso em um projeto meu. Como obtenho os arquivos DLL necessários?
Andoo de
0
Aqui está uma abordagem em que o Inkscape é chamado pelo Python.
Observe que ele suprime certas saídas crufty que o Inkscape grava no console (especificamente, stderr e stdout) durante a operação normal sem erros. A saída é capturada em duas variáveis de string oute err.
import subprocess # May want to use subprocess32 instead
cmd_list =['/full/path/to/inkscape','-z','--export-png','/path/to/output.png','--export-width',100,'--export-height',100,'/path/to/input.svg']# Invoke the command. Divert output that normally goes to stdout or stderr.
p = subprocess.Popen( cmd_list, stdout=subprocess.PIPE, stderr=subprocess.PIPE )# Below, < out > and < err > are strings or < None >, derived from stdout and stderr.
out, err = p.communicate()# Waits for process to terminate# Maybe do something with stdout output that is in < out ># Maybe do something with stderr output that is in < err >if p.returncode:raiseException('Inkscape error: '+(err or'?'))
Por exemplo, ao executar um determinado trabalho em meu sistema Mac OS, outacabou sendo:
Background RRGGBBAA: ffffff00
Area0:0:339:339 exported to 100 x 100 pixels (72.4584 dpi)Bitmap saved as:/path/to/output.png
(O arquivo svg de entrada tinha um tamanho de 339 por 339 pixels.)
Não é Python ponta a ponta se você depende do Inkscape.
Joel
1
@Joel: A primeira linha foi modificada para superar sua objeção. Mas é claro, mesmo uma solução Python "pura" depende de elementos fora da linguagem central e, em última análise, é executada com linguagem de máquina, então talvez não exista algo de ponta a ponta!
Travesseiro de ferro de
0
Na verdade, eu não queria depender de mais nada além de Python (Cairo, Ink .., etc.). Meus requisitos eram para ser o mais simples possível, no máximo, um simples pip install "savior"seria suficiente, é por isso que nenhum dos acima t terno para mim.
Respostas:
A resposta é " pyrsvg " - uma ligação Python para librsvg .
Existe um pacote Ubuntu python-rsvg que o fornece. Pesquisar seu nome no Google é ruim porque seu código-fonte parece estar contido no repositório GIT do projeto Gnome "gnome-python-desktop".
Fiz um "hello world" minimalista que renderiza SVG em uma superfície do Cairo e grava em disco:
Atualização : a partir de 2014 o pacote necessário para a distribuição Fedora Linux é:
gnome-python2-rsvg
. A lista de trechos acima ainda funciona como está.fonte
cairo
determinar a ALTURA e a LARGURA da imagem por conta própria? Verifiquei o*.svg
arquivo para extrair ALTURA e LARGURA de lá, mas ambos estão configurados para100%
. Claro, posso examinar as propriedades da imagem, mas, como essa é apenas uma etapa do processamento da imagem, não é isso que eu quero..get_dimension_data()
método que funcionou para o meu arquivo de exemplo (um SVG bem comportado) - experimente.Aqui está o que eu fiz usando cairosvg :
E funciona como um encanto!
Veja mais: documento cairosvg
fonte
svg2png
leva umstream
objeto nowrite_to
parâmetro, e este pode ser seu objeto de resposta HTTP (que em a maioria das estruturas é um objeto semelhante a um arquivo) ou algum outro fluxo, que você serve ao navegador usando oContent-Disposition
cabeçalho. veja aqui: stackoverflow.com/questions/1012437/…bytestring
aceita bytes, portanto, converta primeiro a string combytestring=bytes(svg,'UTF-8')
2). o modo de arquivo deve ser binário, entãoopen('output.png','wb')
svg2png
para mim, eu tinha que usarcairosvg.surface.PNGSurface.convert(svg_str, write_to='output.png')
.Instale o Inkscape e chame-o como linha de comando:
Você também pode capturar uma área retangular específica usando apenas o parâmetro
-j
, por exemplo, coordenada "0: 125: 451: 217"Se quiser mostrar apenas um objeto no arquivo SVG, você pode especificar o parâmetro
-i
com o id do objeto que você configurou no SVG. Ele esconde todo o resto.fonte
Estou usando o Wand-py (uma implementação do wrapper Wand em torno do ImageMagick) para importar alguns SVGs bastante avançados e até agora tenho visto ótimos resultados! Este é todo o código necessário:
Acabei de descobrir isso hoje e senti que valia a pena compartilhar com qualquer pessoa que possa ter dúvidas sobre essa resposta, pois já faz um tempo que a maioria dessas perguntas não foi respondida.
NOTA: Tecnicamente em testes, descobri que você nem mesmo precisa passar o parâmetro de formato para ImageMagick, então
with wand.image.Image( blob=svg_file.read() ) as image:
foi tudo o que realmente foi necessário.EDIT: A partir de uma tentativa de edição por qris, aqui está um código útil que permite usar o ImageMagick com um SVG que tem um fundo transparente:
fonte
image.read(blob=svg_file.read(), format="svg") NameError: name 'svg_file' is not defined
svg_file
é considerado um objeto "arquivo" neste exemplo, a configuraçãosvg_file
seria algo como:svg_file = File.open(file_name, "r")
cairo
ersvg
'aceito' não funcionou para o meu PDF.pip install wand
e seu snippet funcionou;)str
, em seguida, você primeiro precisa codificar em binário da seguinte forma:svg_blob = svg_str.encode('utf-8')
. Agora você pode usar o método acima, substituindoblob=svg_file.read()
porblob=svg_blob
.Experimente: http://cairosvg.org/
O site diz:
Atualização em 25 de novembro de 2016 :
fonte
<clipPath><rect ... /></clipPath>
. Em segundo lugar, não é necessária a opção -d (DPI).Outra solução que acabei de encontrar aqui Como renderizar um SVG em escala para um QImage?
PySide é facilmente instalado a partir de um pacote binário no Windows (e eu o uso para outras coisas, então é fácil para mim).
No entanto, notei alguns problemas ao converter bandeiras de países da Wikimedia, então talvez não seja o analisador / renderizador svg mais robusto.
fonte
Uma pequena extensão na resposta de jsbueno:
fonte
Não achei nenhuma das respostas satisfatória. Todas as bibliotecas mencionadas têm algum problema ou outro, como Cairo abandonando o suporte para python 3.6 (elas abandonaram o suporte para Python 2 há cerca de 3 anos!). Além disso, instalar as bibliotecas mencionadas no Mac foi uma dor.
Finalmente, descobri que a melhor solução era svglib + reportlab . Ambos instalados sem problemas usando pip e a primeira chamada para converter de SVG para PNG funcionaram perfeitamente! Muito feliz com a solução.
Apenas 2 comandos fazem o truque:
Há alguma limitação dessas que eu deva estar ciente?
fonte
Escala SVG e renderização PNG
Usando pycairo e librsvg, consegui dimensionar SVG e renderizar para um bitmap. Supondo que seu SVG não seja exatamente 256x256 pixels, a saída desejada, você pode ler no SVG para um contexto Cairo usando rsvg e, em seguida, dimensioná-lo e gravar em PNG.
main.py
Ligação RSVG C
Do site Cario com algumas pequenas modificações. Também é um bom exemplo de como chamar uma biblioteca C do Python
fonte
Handle.get_dimension_data
não funcione para mim. Tive que substituí-lo por uma simples busca deself.props.width
eself.props.height
. Tentei primeiro definir aRsvgDimensionData
Estrutura conforme descrito no site do cairo, mas sem sucesso.Aqui está uma abordagem em que o Inkscape é chamado pelo Python.
Observe que ele suprime certas saídas crufty que o Inkscape grava no console (especificamente, stderr e stdout) durante a operação normal sem erros. A saída é capturada em duas variáveis de string
out
eerr
.Por exemplo, ao executar um determinado trabalho em meu sistema Mac OS,
out
acabou sendo:(O arquivo svg de entrada tinha um tamanho de 339 por 339 pixels.)
fonte
Na verdade, eu não queria depender de mais nada além de Python (Cairo, Ink .., etc.). Meus requisitos eram para ser o mais simples possível, no máximo, um simples
pip install "savior"
seria suficiente, é por isso que nenhum dos acima t terno para mim.Eu superei isso (indo além do Stackoverflow na pesquisa). https://www.tutorialexample.com/best-practice-to-python-convert-svg-to-png-with-svglib-python-tutorial/
Parece bom, até agora. Então, eu compartilho no caso de alguém na mesma situação.
fonte