{
"metadata": {
"name": ""
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"[Python para Desenvolvedores](http://ricardoduarte.github.io/python-para-desenvolvedores/#conteudo)\n",
"===================================\n",
"2ª edi\u00e7\u00e3o, revisada e ampliada\n",
"-----------------------------------\n",
"\n",
"Ap\u00eandice D: Inkscape\n",
"=============================\n",
"_____________________________\n",
"O editor de imagens vetoriais [Inkscape](http://www.inkscape.org/) permite o uso do Python como linguagem *script*, para a cria\u00e7\u00e3o de extens\u00f5es. O aplicativo utiliza o SVG como formato nativo e implementa v\u00e1rios recursos previstos no padr\u00e3o.\n",
"\n",
"As extens\u00f5es para o Inkscape servem principalmente para a implementa\u00e7\u00e3o de filtros e efeitos. Enquanto outros aplicativos (como o Blender) apresentam uma API na forma de m\u00f3dulos para o interpretador, o Inkscape passa argumentos pela linha de comando e transfere informa\u00e7\u00f5es pela entrada e sa\u00edda padr\u00e3o do sistema operacional, de forma similar aos utilit\u00e1rios de tratamento de texto encontrados em sistemas UNIX. Com isso, a extens\u00e3o tem acesso apenas aos elementos que fazem parte do documento, e n\u00e3o a interface gr\u00e1fica do aplicativo. Qualquer intera\u00e7\u00e3o com o usu\u00e1rio durante a execu\u00e7\u00e3o fica por conta da extens\u00e3o.\n",
"\n",
"A cria\u00e7\u00e3o e manipula\u00e7\u00e3o das estruturas de dados \u00e9 feita usando XML, como prev\u00ea a especifica\u00e7\u00e3o do formato SVG, permitindo com isso o uso de m\u00f3dulos como o *ElementTree*.\n",
"\n",
"Para simplificar o processo, o Inkscape prov\u00ea o m\u00f3dulo chamado *inkex*, que define estruturas b\u00e1sicas para extens\u00f5es. Com esse m\u00f3dulo, novas extens\u00f5es podem ser criadas por heran\u00e7a a partir de uma classe chamada *Effect*.\n",
"\n",
"Exemplo (randomtext.py):"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"import random\n",
"import inkex\n",
"import simplestyle\n",
"\n",
"\n",
"class RandomText(inkex.Effect):\n",
" \"\"\"\n",
" Repete um texto aleatoriamente dentro de uma \u00e1rea.\n",
" \"\"\"\n",
" def __init__(self):\n",
"\n",
" # Evoca a inicializa\u00e7\u00e3o da superclasse\n",
" inkex.Effect.__init__(self)\n",
"\n",
" # Adiciona um par\u00e2metro para ser recebido do Inkscape\n",
" self.OptionParser.add_option('-t', '--texto',\n",
" action = 'store', type = 'string',\n",
" dest = 'texto', default = 'Python',\n",
" help = 'Texto para ser randomizado')\n",
"\n",
" self.OptionParser.add_option('-q', '--quantidade',\n",
" action='store', type='int',\n",
" dest='quantidade', default=20,\n",
" help='Quantidade de vezes que o texto ir\u00e1 aparecer')\n",
"\n",
" self.OptionParser.add_option('-l', '--largura',\n",
" action='store', type='int',\n",
" dest='largura', default=1000,\n",
" help='Largura da \u00e1rea')\n",
"\n",
" self.OptionParser.add_option('-c', '--altura',\n",
" action='store', type='int',\n",
" dest='altura', default=1000,\n",
" help='Altura da \u00e1rea')\n",
"\n",
" def effect(self):\n",
"\n",
" # Pega as vari\u00e1veis que foram passadas como\n",
" # op\u00e7\u00f5es de linha de comando pelo Inkscape\n",
" texto = self.options.texto\n",
" quantidade = self.options.quantidade\n",
" largura = self.options.largura\n",
" altura = self.options.altura\n",
"\n",
" # Raiz do SVG\n",
" svg = self.document.getroot()\n",
"\n",
" # Altura e largura do documento\n",
" doc_largura = inkex.unittouu(svg.attrib['width'])\n",
" doc_altura = inkex.unittouu(svg.attrib['height'])\n",
"\n",
" # Cria uma camada no documento\n",
" camada = inkex.etree.SubElement(svg, 'g')\n",
" camada.set(inkex.addNS('label', 'inkscape'), 'randomtext')\n",
" camada.set(inkex.addNS('groupmode', 'inkscape'), 'camada')\n",
"\n",
" for i in xrange(quantidade):\n",
"\n",
" # Cria um elemento para o texto\n",
" xmltexto = inkex.etree.Element(inkex.addNS('text','svg'))\n",
" xmltexto.text = texto\n",
"\n",
" # Posiciona o elemento no documento\n",
" x = random.randint(0, largura) + (doc_largura - largura) / 2\n",
" xmltexto.set('x', str(x))\n",
" y = random.randint(0, altura) + (doc_altura - altura) / 2\n",
" xmltexto.set('y', str(y))\n",
"\n",
" # Centraliza na vertical e na horizontal\n",
" # e muda a cor de preenchimento usando CSS\n",
" c = random.randint(100, 255)\n",
" style = {'text-align' : 'center',\n",
" 'text-anchor': 'middle',\n",
" 'fill': '#%02x%02x%02x' % (c, c - 30, c - 60)}\n",
" xmltexto.set('style', simplestyle.formatStyle(style))\n",
"\n",
" # Coloca o texto na camada\n",
" camada.append(xmltexto)\n",
"\n",
"\n",
"if __name__ == '__main__':\n",
" rt = RandomText()\n",
" rt.affect()"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Para que o Inkscape reconhe\u00e7a a nova extens\u00e3o, \u00e9 necess\u00e1rio criar um arquivo XML com a configura\u00e7\u00e3o, que informa ao aplicativo os m\u00f3dulos e os par\u00e2metros usados pela extens\u00e3o, incluindo os tipos, limites e valores padr\u00e3o desses par\u00e2metros, para que ele possa interagir com o usu\u00e1rio atrav\u00e9s de uma caixa de dialogo antes da execu\u00e7\u00e3o para obter os valores desejados. Os par\u00e2metros s\u00e3o passados como argumentos na linha de comando quando o *script* \u00e9 executado.\n",
"\n",
"Arquivo de configura\u00e7\u00e3o (randomtext.inx):"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"\n",
"\n",
" <_name>RandomText\n",
" org.ekips.filter.randomtext\n",
" randomtext.py\n",
" inkex.py\n",
" Python\n",
" 20\n",
" 1000\n",
" 1000\n",
" \n",
" all\n",
" \n",
" \n",
" \n",
" \n",
" \n",
""
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Janela com os par\u00e2metros da extens\u00e3o:\n",
"\n",
"![Inkscape](files/inkscape1.png)\n",
"\n",
"Exemplo de sa\u00edda (quantidade igual a 100, largura igual a 600 e altura igual a 200):\n",
"\n",
"![Inkscape](files/inkscape2.png)\n",
"\n",
"Tanto o programa quanto o arquivo de configura\u00e7\u00e3o precisam ficar na pasta de extens\u00f5es (`share\\extensions`, dentro da pasta de instala\u00e7\u00e3o, para a vers\u00e3o Windows) para que sejam encontrados pelo aplicativo e o nome do arquivo de configura\u00e7\u00e3o precisa ter extens\u00e3o `.inx`."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": [
{
"html": [
"\n",
""
],
"output_type": "pyout",
"prompt_number": 1,
"text": [
""
]
}
],
"prompt_number": 1
}
],
"metadata": {}
}
]
}