{ "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": {} } ] }