Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Selections, filters, erasing, transforms

✅ verified

Selections

from krita import Selection
sel = Selection()
sel.select(x, y, w, h, 255)                     # a rectangle
sel.setPixelData(mask.tobytes(), 0, 0, w, h)    # an arbitrary shape, built with numpy
sel.feather(15); sel.grow(20, 20); sel.shrink(...); sel.border(5, 5)
sel.invert(); sel.smooth(); sel.dilate(); sel.erode()
sel.add(o); sel.subtract(o); sel.intersect(o); sel.symmetricdifference(o)
doc.setSelection(sel)
  • A selection confines paintLine: a rectangle at x in [50,200) lands the stroke in [50,199]; a circle plus feather(15) feathers 15 outward. All of it exact.
  • It does not confine filter.apply(): run a gaussian blur with half the canvas selected and the whole canvas is processed. But the Selection overloads of createFilterMask and createFilterLayer are confined by the selection, feather with it, and are non-destructive (ch. 15).
  • It cannot keep fractional coverage: feed it a 0-to-255 antialiased mask and what is painted improves only from aliased 100% to 25.5% (boundary-band deviation 0.367 to 0.331, against a vector layer’s 0.083). Do not look to selections for a smooth edge.
  • Building one on 8192x12288 takes about 1.1 s, which is the cost of a full-canvas setPixelData.
  • There is exactly one way to clear a selection: doc.setSelection(None). setSelection(Selection()) and sel.clear() mean “select nothing”, after which every stroke silently paints 0 px and nothing raises. The symptom is “suddenly no brush works at all”.
  • sel.selectAll() takes two arguments, (node, value).

filter

f = Krita.instance().filter("gaussian blur")
c = f.configuration(); c.setProperty("horizRadius", 25.0); c.setProperty("vertRadius", 25.0)
f.setConfiguration(c)
f.apply(node, x, y, w, h)        # it returns None on success too, so check the pixels yourself

52 of them: asc-cdl, autocontrast, blur, burn, colorbalance, colortoalpha, colortransfer, crosschannel, desaturate, dodge, edge detection, emboss (and five more), fastcoloroverlay, gaussian blur, gaussianhighpass, gaussiannoisereducer, gradientmap, halftone, height to normal, hsvadjustment, indexcolors, invert, lens blur, levels, maximize, mean removal, minimize, motion blur, noise, normalize, oilpaint, palettize, perchannel, phongbumpmap, pixelize, posterize, propagatecolors, raindrops, randompick, resettransparent, roundcorners, sharpen, smalltiles, threshold, unsharp, wave, waveletnoisereducer.

Its extent is governed by the box alone, with a knife-cut edge – measuring the blur-strength profile’s 0.9-to-0.1 transition band gives 7.2 px, exactly the criterion’s own floor (what an ideal step reads after the same 9-wide smoothing).

Correction: this used to say that a local filter needing feathering could only be run over the whole canvas and blended back by mask with numpy. That was a conclusion about apply(). doc.createFilterMask(name, f, sel) takes a Selection, where sel.feather(40) gives a 59.9 px transition band and feather(120) a 177.7 px one, and it is non-destructive. See ch. 15.

Erasing

The only thing that works is clearing alpha, s.erase(box=, mask=). All three ways of “erasing with a brush” do nothing (ch. 12).

Transforms

Node level, all of which change the bounds: scaleNode(QPointF(cx,cy), w, h, "Bicubic") (QPointF; a QPoint is a TypeError), rotateNode(rad), shearNode, cropNode and move.

Document level: scaleImage(w,h,xres,yres,strategy), rotateImage, shearImage, crop, resizeImage and flatten. The strategies from filterStrategies() are Bell, Bicubic, BSpline, Hermite, Mitchell, Bilinear, Lanczos3 and NearestNeighbor.

scaleImage’s strategy is not validated: pass "xyzzy" and the size changes anyway, by an unknown interpolation. Session.w and h do not follow automatically afterwards; read doc.width() back.

What node-level transforms measure against clipping inside a group, and their non-destructive counterpart the TransformMask, are in ch. 15.

Resources

Krita.instance().resources(type): preset 144, brush 84, gradient 19, pattern 112, palette 13, workspace 9. Any other string returns nothing. createFillLayer(name, "gradient"|"pattern", InfoObject(), sel) lays one as a layer; "simplenoise" segfaults.

Krita.instance().actions() has 688 entries, and any GUI menu item can be .trigger()-ed – the back door to anything the API does not cover, with no return value.

There is no “lay one” API for a gradient or a pattern on a Node; the only way to their rasterized result is Scratchpad.fillGradient and fillPattern (ch. 15).

Other things

  • Wrap around: view.canvas().setWrapAroundMode(True) measurably affects painting, with a stroke past the edge wrapping to the other side.
  • Animation: it can read and set timeline parameters and import a sequence of frames, but there is no API for creating a keyframe.
  • Channel order: ManagedColor.setComponents, Node.setPixelData and pixelData are all BGRA, the first in 0-to-1 floats. Anything the canvas exposes is RGB.