Como criar um plugin Python para o Krita¶
Você pode ter alguns scripts interessantes escritos no editor de script Python, mas talvez queira fazer mais com eles e executá-los automaticamente, por exemplo. Encapsular seu script em um plugin pode lhe dar muito mais flexibilidade e poder do que executar scripts no editor de script.
Certo, mesmo que você conheça Python muito bem, existem alguns pequenos detalhes para fazer o Krita reconhecer um plugin Python. Portanto, esta página dará uma visão geral de como criar os vários tipos de script Python exclusivos do Krita.
Esses minitutoriais foram escritos para pessoas com conhecimento básico de Python e de forma a incentivar a experimentação em vez de simplesmente copiar e colar código. Portanto, leia o texto com atenção.
Fazendo o Krita reconhecer seu plugin¶
Um script no Krita tem dois componentes: a pasta do script (que contém os arquivos Python do seu script) e um arquivo “.desktop” que o Krita usa para carregar e registrar seu script. Para que o Krita carregue seu script, ambos devem estar na subpasta pykrita da sua pasta de recursos do Krita (consulte Gerenciamento de recursos para os caminhos por sistema operacional). Para encontrar sua pasta de recursos, inicie o Krita e clique no item de menu . Isso abrirá uma caixa de diálogo. Clique no botão Abrir pasta de recursos. Isso deve abrir o gerenciador de arquivos do seu sistema na sua pasta de recursos do Krita. Consulte a documentação API em “Inicialização automática de scripts”. Se não houver uma subpasta pykrita na pasta de recursos do Krita, use seu gerenciador de arquivos para criar uma.
Os scripts são identificados por um arquivo que termina com a extensão .desktop que contém informações sobre o próprio script.
Portanto, para cada plugin adequado, você precisará criar uma pasta e um arquivo na área de trabalho.
O arquivo desktop deve ter a seguinte aparência:
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=meuplugin
X-Python-2-Compatible=false
X-Krita-Manual=ManualmeuPlugin.html
Name=Meu Próprio Plugin
Comment=Nosso próprio plugin.
- Type (Tipo)
Isso sempre deve ser um serviço.
- ServiceTypes (Tipos de Serviço)
Isso deve ser sempre
Krita/PythonPluginpara plugins Python.- X-KDE-Library
Este deve ser o nome da pasta do plugin que você acabou de criar.
- X-Python-2-Compatible
Se é compatível com o Python 2. Se o Krita foi criado com o Python 2 em vez do 3 (
-DENABLE_PYTHON_2=ONna configuração do cmake), este plugin não aparecerá na lista.- X-Krita-Manual
Um valor opcional que apontará para o item manual. Isso é exibido no gerenciador de plugins do Python. Se for um arquivo HTML, será exibido como rich text, caso contrário, será exibido como texto simples.
- Name (Nome)
O nome que aparecerá no gerenciador de plugins Python.
- Comment (Comentário)
A descrição que será exibida no gerenciador de plugins Python.
Os plugins Python do Krita precisam ser módulos Python, então certifique-se de que haja um script __init__.py contendo algo como…
from .meuplugin import *
Onde .meuplugin é o nome do arquivo principal do seu plugin. Se você reiniciar o Krita, ele deverá exibir isso no gerenciador de plugins Python nas configurações, mas ficará esmaecido, pois não há meuplugin.py. Se você passar o mouse sobre os plugins desativados, poderá ver o erro com eles.
Nota
Você precisa habilitar seu plugin explicitamente. Acesse o menu Configurações, abra a caixa de diálogo Configurar Krita e acesse a página do Gerenciador de plugins Python para habilitar seu plugin.
Resumo¶
Em resumo, se você quiser criar um script chamado meuplugin:
- na sua pasta
resources/pykritado Krita crie uma pasta chamada
meupluginum arquivo chamado
meuplugin.desktop
- na sua pasta
- na pasta
meuplugincrie um arquivo chamado
__init__.pyum arquivo chamado
meuplugin.py
- na pasta
no arquivo
__init__.pycoloque este código:
from .meuplugin import *
no arquivo desktop coloque este código:
[Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=meuplugin X-Python-2-Compatible=false Name=Meu Próprio Plugin Comment=Nosso próprio plugin.
escreva seu script no arquivo
meuplugin/meuplugin.py.
Criando uma extensão¶
Extensões são scripts Python relativamente simples que rodam na inicialização do Krita. Elas são criadas estendendo a classe Extension, e a extensão mais básica se parece com isto:
from krita import *
class MinhaExtensao(Extension):
def __init__(self, parent):
# Isso está inicializando o pai, sempre importante ao criar subclasses.
super().__init__(parent)
def setup(self):
pass
def createActions(self, window):
pass
# E adiciona a extensão à lista de extensões do Krita:
Krita.instance().addExtension(MinhaExtensao(Krita.instance()))
Este código, claro, não faz nada. Normalmente, em createActions, adicionamos ações ao Krita, para que possamos acessar nosso script a partir do menu Ferramentas.
Primeiro, vamos criar uma ação. Podemos fazer isso facilmente com Window.createAction(). O Krita chamará createActions para cada janela criada e passará o objeto de janela correto que precisamos usar.
Então…
def createActions(self, window):
action = window.createAction("minhaAcao", "Meu Script", "tools/scripts")
- “minhaAcao”
Isso deve ser substituído por um ID exclusivo que o Krita usará para encontrar a ação.
- “Meu Script”
Isto é o que ficará visível no Menu Ferramentas.
Se você reiniciar o Krita agora, terá uma ação chamada “Meu Script”. Ela ainda não faz nada, porque não a conectamos a um script.
Então, vamos criar um script simples para exportar documentos. Adicione o seguinte à classe de extensão, certificando-se de que esteja acima de onde você adicionou a extensão ao Krita:
def exportDocument(self):
# Obtém o documento:
doc = Krita.instance().activeDocument()
# Salvar um documento inexistente causa travamentos, então vamos verificar isso primeiro.
if doc is not None:
# Isso abre a caixa de diálogo de salvamento. A caixa de diálogo de salvamento retorna uma tupla.
fileName = QFileDialog.getSaveFileName()[0]
# E exporta o documento para a localização de fileName.
# InfoObject é um dicionário com opções de exportação específicas, mas quando criamos um vazio, o Krita usará os padrões de exportação.
doc.exportImage(fileName, InfoObject())
E adicione a importação para o QFileDialog acima com as importações:
from krita import *
from PyQt5.QtWidgets import QFileDialog
Em seguida, para conectar a ação ao novo documento de exportação:
def createActions(self, window):
action = window.createAction("minhaAcao", "Meu Script")
action.triggered.connect(self.exportDocument)
Este é um exemplo de uma conexão sinal/slot, muito utilizada em aplicativos Qt como o Krita. Veremos como criar nossos próprios sinais e slots mais adiante.
Reinicie o Krita e sua nova ação deverá exportar o documento.
Criando atalhos de teclado configuráveis¶
Agora, sua nova ação não aparece em .
O Krita, por vários motivos, só adiciona ações ao Configurações de atalho quando elas estão presentes em um arquivo .action. O arquivo de ação para que nossa ação seja adicionada aos atalhos deve ser semelhante a este:
<?xml version="1.0" encoding="UTF-8"?>
<ActionCollection version="2" name="Scripts">
<Actions category="Scripts">
<text>Meus Scripts</text>
<Action name="myAction">
<icon></icon>
<text>Meu Script</text>
<whatsThis></whatsThis>
<toolTip></toolTip>
<iconText></iconText>
<activationFlags>10000</activationFlags>
<activationConditions>0</activationConditions>
<shortcut>ctrl+alt+shift+p</shortcut>
<isCheckable>false</isCheckable>
<statusTip></statusTip>
</Action>
</Actions>
</ActionCollection>
- <text>Meus Scripts</text>
Isso criará uma subcategoria em scripts chamada “Meus scripts” para adicionar seus atalhos.
- name
Isto deve ser o ID exclusivo que você criou para sua ação ao criá-la na configuração da extensão.
- icon
O nome de um possível ícone. Eles só aparecerão no KDE Plasma, porque usuários do Gnome e do Windows reclamaram que eles são feios.
- text
O texto que será exibido no editor de atalhos.
- whatsThis
O texto que será exibido quando um aplicativo Qt solicitar especificamente “o que é isso”, que é uma ação de ajuda.
- toolTip
A dica que aparecerá ao passar o mouse.
- iconText
O texto que será exibido quando exibido em uma barra de ferramentas. Por exemplo, “Redimensionar imagem para novo tamanho” poderia ser abreviado para “Redimensionar imagem” para economizar espaço, então colocaríamos isso aqui.
- activationFlags
Isso determina quando uma ação é desabilitada ou não.
- activationConditions
Isso determina as condições de ativação (por exemplo, ativar somente quando a seleção for editável). Veja o código para exemplos.
- shortcut
Atalho padrão.
- isCheckable
Se é uma caixa de seleção ou não.
- statusTip
A dica de status que é exibida em uma barra de status.
Salve este arquivo como meuplugin.action, onde meuplugin é o nome do seu plugin. O arquivo de ação deve ser salvo não na pasta de recursos do pykrita, mas sim em uma pasta de recursos chamada “actions”. (Portanto, share/pykrita é onde ficam os plugins Python e os arquivos do desktop, e share/actions é onde ficam os arquivos de ação.) Reinicie o Krita. O atalho agora deve aparecer na lista de ações de atalho.
Criando um painel¶
Criar um painel personalizado é muito parecido com criar uma extensão. Os painéis são, em alguns aspectos, um pouco mais fáceis, mas também exigem mais uso de widgets. Este é o código básico de um painel:
from PyQt5.QtWidgets import *
from krita import *
class MeuDocker(DockWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Meu Docker")
def canvasChanged(self, canvas):
pass
Krita.instance().addDockWidgetFactory(DockWidgetFactory("meuDocker", DockWidgetFactoryBase.DockRight, MeuDocker))
O título da janela (setWindowTitle) é como ele aparecerá na lista de painéis no Krita. canvasChanged sempre precisa estar presente, mas você não precisa fazer nada com ele, então basta “passar”.
Para o addDockWidgetFactory…
- “meuDocker”
Substitua isso por um ID exclusivo para seu painel que o Krita usa para rastreá-lo.
- DockWidgetFactoryBase.DockRight
A localização. Podem ser
DockTornOff,DockTop,DockBottom,DockRight,DockLeftouDockMinimized- MeuDocker
Substitua isso pelo nome da classe do painel que você deseja adicionar.
Então, se adicionarmos a função de exportação de documentos que criamos na seção de extensões a este código de painel, como permitimos que o usuário a ative? Primeiro, precisamos codificar a interface gráfica do usuário em Qt: vamos adicionar um botão!
Por padrão, o Krita usa PyQt, mas sua documentação é bem ruim, principalmente porque a documentação regular do Qt é muito boa, e você frequentemente descobrirá que a documentação PyQt de uma classe, digamos, QWidget é como uma cópia estranha da documentação regular do Qt para essa classe.
De qualquer forma, o que precisamos fazer primeiro é criar um QWidget. Não é muito complicado. Em setWindowTitle, adicione:
mainWidget = QWidget(self)
self.setWidget(mainWidget)
Então, criamos um botão:
buttonExportDocument = QPushButton("Exportar documento", mainWidget)
Agora, para conectar o botão à nossa função, precisamos consultar os sinais na documentação. QPushButton não possui sinais únicos, mas diz que herda 4 sinais de QAbstractButton, o que significa que também podemos usá-los. No nosso caso, queremos que seja clicado.
buttonExportDocument.clicked.connect(self.exportDocument)
Se reiniciarmos o Krita agora, teremos um novo painel e, nesse painel, há um botão. Clicar no botão abrirá a função de exportação.
No entanto, o botão parece alinhado de forma um pouco estranha. Isso ocorre porque nosso mainWidget não tem layout. Vamos fazer isso rapidamente:
mainWidget.setLayout(QVBoxLayout())
mainWidget.layout().addWidget(buttonExportDocument)
O Qt tem vários layouts, mas o QHBoxLayout e o QVBoxLayout são os mais fáceis de usar, eles apenas organizam os widgets horizontalmente ou verticalmente.
Reinicie o Krita e o botão deverá estar bem disposto.
Sinais e Slots do PyQt¶
Já usamos sinais e slots do PyQt, mas há momentos em que você deseja criar seus próprios sinais e slots. Como a documentação do PyQt é bastante difícil de entender, e a maneira como os sinais e slots são criados é muito diferente do Qt em C++, estamos explicando aqui:
Todas as funções Python que você cria em PyQt podem ser entendidas como slots, o que significa que podem ser conectadas a sinais como Action.triggered ou QPushButton.clicked. No entanto, QCheckBox tem um sinal para toggled, que envia um booleano. Como fazemos para que nossa função aceite esse booleano?
Primeiro, certifique-se de ter a importação correta para criar slots personalizados:
from PyQt5.QtCore import pyqtSlot
(Se já houver from PyQt5.QtCore import * na lista de importações, você não precisará fazer isso, é claro.)
Então, você precisa adicionar uma definição de slot PyQt antes da sua função:
@pyqtSlot(bool)
def myFunction(self, enabled):
enabledString = "disabled"
if (enabled == True):
enabledString = "enabled"
print("A caixa de seleção está"+enabledString)
Então, quando você tiver criado sua caixa de seleção, você pode fazer algo como myCheckbox.toggled.connect(self.myFunction).
Da mesma forma, para criar seus próprios sinais PyQt, faça o seguinte:
# o nome do sinal é adicionado às variáveis membro da classe
signal_name = pyqtSignal(bool, name='signalName')
def emitMySignal(self):
# E é assim que você aciona o sinal a ser emitido.
self.signal_name.emit(True)
E use a importação correta:
from PyQt5.QtCore import pyqtSignal
Para emitir ou criar slots para objetos que não são objetos Python padrão, você só precisa colocar seus nomes entre aspas.
Uma nota sobre testes unitários¶
Se você quiser escrever testes unitários para seu plugin, dê uma olhada no módulo krita mock.
Conclusão¶
Certo, isso abrange todos os detalhes específicos do Krita para a criação de plugins em Python. Não aborda como analisar os dados de pixel nem as melhores práticas com documentos, mas se você tiver um pouco de experiência com Python, poderá começar a criar seus próprios plugins.
Como sempre, leia o código com atenção e leia a documentação da API para Python, Krita e Qt com atenção para ver o que é possível, e você chegará bem longe.