from krita import *
from PyQt5.QtCore import QPoint, QPointF, QEvent, QTimer
from PyQt5.QtGui import QImage,QMouseEvent,QCursor
def find_current_canvas():
q_window = application.activeWindow().qwindow()
q_stacked_widget = q_window.centralWidget()
canvas = q_stacked_widget.findChild(QOpenGLWidget)
return canvas
def click_canvas():
mouse_press = QMouseEvent(
QEvent.MouseButtonPress,
posF,
Qt.LeftButton,
Qt.LeftButton,
Qt.NoModifier)
mouse_release = QMouseEvent(
QEvent.MouseButtonRelease,
posF,
Qt.LeftButton,
Qt.LeftButton,
Qt.NoModifier)
QApplication.sendEvent(canvas, mouse_press)
QApplication.sendEvent(canvas, mouse_release)
def clipFillColor():
def fillColor(node):
image = QImage(w, h, QImage.Format_ARGB32)
image.fill(Qt.red)
pixel_ptr = image.constBits()
pixels = bytes(pixel_ptr.asarray(image.byteCount()))
node.setPixelData(pixels, 0, 0, w, h)
# clip red color
redNode = activeDoc.createNode("red", "paintlayer")
fillColor(redNode)
allSe.copy(redNode)
redNode.remove()
def makeSelection():
global lineSe
startSe = activeDoc.selection()#selection by first Click
application.action('deselect').trigger()
invertSe = startSe.duplicate()
invertSe.invert()
lineSe = invertSe.duplicate()
lineSe.border(1,1)#selection of line art
# selection that close gaps
gapSe = lineSe.duplicate()
gapSe.grow(5,5)
gapSe.shrink(5,5,True)
gapSe.grow(1,1)
gapSe.border(1,1)
# selection that can make hole in the gap selection
needleSe = lineSe.duplicate()
needleSe.grow(5,5)
needleSe.subtract(lineSe)
needleSe.shrink(3,3,True)
needleSe.grow(1,1)
# make hole in the gapSelection
gapSe.subtract(needleSe)
gapSe.paste(closerNode, 0, 0)# gap closer
# if aaBool:# restore state and ready for secondClick
# aaBox.setChecked(True)
def expand():
def parameter(selection):
# grow of selectoin
if box_grow_v >= 0:
selection.grow(box_grow_v, box_grow_v)
elif box_grow_v < 0:
selection.shrink(abs(box_grow_v), abs(box_grow_v), True)
# feathering of selection
if box_feather_v > 0:
selection.feather(box_feather_v)
return selection
global compSe
if activeDoc.selection():
currentSe = activeDoc.selection()
se = currentSe.duplicate()
se.subtract(lineSe)
for i in range(3):# fill inside
se.grow(1,1)
se.subtract(lineSe)
se.intersect(allSe)
compSe = parameter(se)
def mixSelection():
global compSe
global preSe
# Compatible with selection mode
if preSe != None:
if controlMode == 2:
preSe = compSe
elif controlMode == 3:
preSe.intersect(compSe)
elif controlMode == 4:
preSe.add(compSe)
elif controlMode == 5:
preSe.subtract(compSe)
elif controlMode == 6:
preSe.symmetricdifference(compSe)
compSe = preSe
def afterCare():
# restore state
buttons[controlMode].setChecked(True)
closerNode.remove()
activeDoc.setActiveNode(activeLayer)
box_grow.setValue(box_grow_v)
box_feather.setValue(box_feather_v)
def visualizer():
# to visualize the selection(krita has bag?)
if compSe == None:
activeDoc.setSelection(preSe)
else:
activeDoc.setSelection(compSe)
application.action('invert_selection').trigger()
application.action('invert_selection').trigger()
def settingTimer(ms, func):
timer = QTimer()
timer.setInterval(ms)
timer.setSingleShot(True)
timer.timeout.connect(func)
return timer
application = Krita.instance()
activeDoc = application.activeDocument()
activeLayer = activeDoc.activeNode()
rootNode = activeDoc.rootNode()
w = activeDoc.width()
h = activeDoc.height()
allSe = Selection()
allSe.select(0, 0, w, h, 255)
lineSe = Selection()
compSe = Selection()
compSe = None
if activeDoc.selection() != None:
preSe = activeDoc.selection()# memory original selection
application.action('deselect').trigger()
else:
preSe = None
canvas = find_current_canvas()
if not canvas.isActiveWindow():
canvas.activateWindow()
# click point
pos = QCursor.pos()#起動時点のカーソル位置
posF = QPointF(canvas.mapFromGlobal(pos))
# pick contiguous selection tool
tooldock = next((w for w in application.dockers() if w.objectName() == 'ToolBox'), None)
sebutton = tooldock.findChild(QToolButton,'KisToolSelectContiguous')
sebutton.click()
# the tool option docker
qdock = next((w for w in application.dockers() if w.objectName() == 'sharedtooldocker'), None)
wobj = qdock.findChild(QWidget,'KisToolSelectContiguousoption widget')
buttons = wobj.findChildren(QToolButton)
boxs = wobj.findChildren(QSpinBox)# input box
aaBox = wobj.findChild(QCheckBox)# antialiasing check box
n = 2
while n < 7:
if buttons[n].isChecked():
num = n
n += 1
controlMode = num # original mode
buttons[2].setChecked(True)# pick "replace"
# input to the box
box_grow = boxs[0]
box_feather = boxs[1]
box_grow_v = box_grow.value()
box_feather_v = box_feather.value()
box_grow.setValue(0)
box_feather.setValue(0)
# # check antiAliasing
# aaBool = aaBox.isChecked()
# if aaBool:
# aaBox.setChecked(False)# set AA "False" for running speed
closerNode = activeDoc.createNode("closerNode", "paintlayer")
closerNode.setBlendingMode("not_converse")
rootNode.addChildNode(closerNode, None)# add layer for closer
clipFillColor()# clip red color
timer1 = settingTimer(800, makeSelection)# selection
timer2 = settingTimer(1000, click_canvas)# selection
timer3 = settingTimer(1800, expand)# selection
timer4 = settingTimer(2200, mixSelection)# selection
timer5 = settingTimer(2400, afterCare)# selection
timer6 = settingTimer(2600, visualizer)# selection
def runAll():
click_canvas()
# timer0.start()# firstClick
activeDoc.waitForDone()
if activeDoc.selection():
timer1.start()#makeSelection()
# activeDoc.waitForDone()
timer2.start()#click_canvas()# secondClick
# activeDoc.waitForDone()
timer3.start()#expand()
# activeDoc.waitForDone()
timer4.start()#mixSelection()
# activeDoc.waitForDone()
timer5.start()#afterCare()
# activeDoc.waitForDone()
timer6.start()# Time difference required to visualize the selection
runAll()
This script is designed to run very slowly. If the selection does not appear, it is probably an environmental issue. (Note that it is a script that creates a selection, not fills it). Does anyone besides me get this script to work correctly in the first place?
Implementing it directly in Krita is not possible with my current knowledge.