jan 12
logo python

2012 chegou e o 2011 se foi, com isso novos artigos sobre novos assuntos aparecem, neste artigo vamos falar sobre a parte básica da criação de plugins para o Inkcape, utilizando a linguagem Python para o desenvolvimento. Eu possuo pouco conhecimento em Python, todo o meu conhecimento se baseia na sintaxe básica da linguagem e um plugin para Gimp que desenvolvi, mas isso não é suficiente para impedir alguém de criar uma extensão para Inkscape.

Como não existe a necessidade de reescrever o conhecimento básico, se achar necessário pode dar uma conferida em http://wiki.inkscape.org/wiki/index.php/ScriptingHOWTO (em inglês).

Inicialmente, para criarmos uma extensão para Inkscape devemos saber onde de encontra a pasta com o conteúdo das extensões, ou seja com os cripts, normalmente essas pasta ficam em:
Linux:

/usr/share/inkscape/extensions
~/.config/inkscape/extensions

Após isto teremos que criar dois arquivos plugin.inx e plugin.py onde plugin é o nome do plugin, uma observação importante é que eles não podem ficar dentro de pastas dentro da pasta extensions. Vale citar que os dois arquivos precisam de permissão de execucação (chmod +x plugin.inx).

O arquivo inx é o arquivo que define a interface inicial do plugin, sua interface (tela), parâmetros que vai receber e qual script python será chamado.

Já o arquivo py é o script python que será chamado.

Vamos começar com a descrição do arquivo inx, que basicamente é um XML com descrição do que o  Inkscape deve fazer. Segue exemplo de extensão (comentada) que está sendo criada para o editor de cenários da Engine Nostaljia, que utilizará o Inkscape como base.

Mais informações sobre o arquivos inx pode ser encontradas em : http://wiki.inkscape.org/wiki/index.php/INX_extension_descriptor_format ( em inglês).

Onde a extensão aparece no menu do inkscape

Onde a extensão aparece no menu do inkscape

<inkscape-extension>
<_name>Nostaljia Scenario Attributes</_name> <!-- Nome que aparecerá no inkscape-->
<id>Edit Scenario object</id> <!--Não sei onde é usado-->
<dependency type="executable" location="extensions">nostaljia.py</dependency> <!-- o script python deve estar nas dependências-->
<dependency type="executable" location="extensions">inkex.py</dependency> <!--dependência padrão do python-->
<param name="label" type="description">Apply some Nostaljia Scenario attributes to selected elements</param>
<param name="layer" type="int" _gui-text="Layer">0</param> <!-- parâmetros que aparecerão na interface-->
<param name="solid" type="boolean" _gui-text="Solid">true</param>
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu _name="Nostaljia"/> <!-- Submenu no qual ele aparecerá dentro de Extensões-->
</effects-menu>
</effect>
<script>
<command reldir="extensions" interpreter="python">nostaljia.py</command> <!-- o script python que será chamado e qual interpretador o inkscape deve utilizar-->
</script>
</inkscape-extension>

Então através de poucas linhas conseguimos definir o que o Inkscape deve fazer, quais scripts incluir, qual chamar, onde colocar no menu e quais parâmetros criar.

Devemos descrever com um pouco mais de atenção a questão dos parâmetros:

<param name="solid" type="boolean" _gui-text="Solid">true</param>

Neste caso definimos como name o nome utilizado pelo inkscape, como type o tipo que deverá ser esse dado, e como _gui-text o texto que aparecerá na interface, e no caso true representa o valor padrão.

Parâmetros são bem trabalhados, com definição de tipos possíveis em http://wiki.inkscape.org/wiki/index.php/INX_Parameters (em inglês).

Abaixo vemos uma imagem do resultado do arquivo inx.

A execucão do arquivo inx

A execucão do arquivo inx

Pode ver que a palavra layer foi traduzida para camada através da opção _gui-text, entraremos em detalhes sobre tradução em outro artigo.

Vale citar que o arquivo inx é lido pelo Inkscape, no momento da abertura do programa, para que ele seja recarregado é necessário fechar e abrir novamente o programa.

Após o passo inicial de criação de arquivo inx iniciaremos a criação do arquivo py, arquivo este que é chamado e executado diretamente na hora de apertarmos em “Aplicar”, então podemos ir modificando e testando a sua execução.

Segue o exemplo do arquivo nostaljia.py, uma versão bem simples para demonstração:

import inkex
 
class C(inkex.Effect):
    def __init__(self):
        inkex.Effect.__init__(self)
        self.OptionParser.add_option("-l", "--layer", action="store", type="int",dest="layer", default=32, help="Force some layer")
        self.OptionParser.add_option("-s", "--solid", action="store", type="inkbool",dest="solid", default=1, help="Make it solid or not")
 
    def effect(self):
        #inkex.errormsg("Esta eh uma mensagem de erro")
        for id, node in self.selected.iteritems():
            node.set('solid', str(self.options.solid) )
 
            if self.options.layer != 0:
                node.set('layer', str(self.options.layer) )
 
c = C()
c.affect()

Importante:

Na construção da classe é importante sempre estender o efeito e fazer a interpretação (parser)de todos os campos criados pela interface, caso faça o parser de algum campo a mais ou a menos um erro será disparado.

class C(inkex.Effect):
    def __init__(self):
        inkex.Effect.__init__(self)
        self.OptionParser.add_option("-l", "--layer", action="store", type="int",dest="layer", default=32, help="Force some layer")
        self.OptionParser.add_option("-s", "--solid", action="store", type="inkbool",dest="solid", default=1, help="Make it solid or not")

Após isso na função de efeito o laço pelos itens selecionados ( self.selected.iteritems() ) após isso aplicamos a lógica da extensão que no caso adicionas os atributos solid e layer ao objeto de acordo com a situação. Vale lembrar que esses não são atributos lidos ou utilizados pelo Inkscape, mas sim pela Engine, e de forma muito inteligente o Inkscape manter este atributos durante a sua edição, caso um objeto seja copia dentro do programa estes atributos são copiados em conjunto.

    def effect(self):
        #inkex.errormsg("Esta eh uma mensagem de erro")
        for id, node in self.selected.iteritems():
            node.set('solid', str(self.options.solid) )
 
            if self.options.layer != 0:
                node.set('layer', str(self.options.layer) )

Finalmente instanciamos a classe e chamamos a sua função:

c = C()
c.affect()

Vale citar que caso queiramos mandar uma mensagem de erro ao Inkscape podemos utilizar o comando abaixo:

inkex.errormsg("Esta eh uma mensagem de erro")

O inkex.py é o script básico do Inkscape para padrão, é o que faz a integração, mas outros ótimos scripts podem ser adicionados como o simplestyle.py que gera estilos para o Inkscape de forma simplificada.

A listagem completa de scripts padrões pode ser encontradas em http://wiki.inkscape.org/wiki/index.php/Python_modules_for_extensions.

Após a execucação do script podemos visualizar o editor de xml que os atributos citados foram adicionados ao retângulo.

Resultado da extensão

Resultado da extensão

Poderiamos facilmente modificar as cores e posicionamentos dos elementos basicamente mexendo nos nodos via Dom, nodos que nada mais são do que os elementos no SVG.

Por hoje era isso pessoal!

Leia também :