Last week we finished the part of the action plan regarding the performance. I started to work on usability improvements. The first usability improvement is canvas mirroring.
Canvas mirroring is useful in your painting work flow and Boudewijn explained that it is useful for artists to check errors in their paintings. In the classical painting you need some hardware for that — you need to find a real mirror and see if your painting looks creepy or not. In Krita you don’t have to buy a new mirror, you can use the canvas mirroring feature.
It is also useful when you paint something that supposed to be “almost” symmetrical. You paint ears of your hero or you paint head outlines. You can paint the first half, mirror the canvas and paint the second half and check back quickly. Other possibility is to use symmetrical feature I wrote for Softbrush lately.
In Krita you could already do this by transforming the image and it’s data but that can be slow if you are painting on big canvases. Krita aims to be professional tool, we want to support big canvases. So we need this also as projection feature. We will not transform the image data, we transform the projection of the image data.
I started to work on this and I had a feeling that this is not going to be about a lot of code but this task is going to be about orientate yourself in some complex part of the Krita called projection and about orientate in coordinate systems we have. You also have to find out and understand how the scrolling and zooming works.
I contacted mypaint maintainer maxy with some short mail asking how mirroring is done within mypaint. The answer was what I basically expected and it proved me that I might go in right direction.So first I started with mirroring the coordinates of the tools. We have few coordinate systems in canvas. First coordinate you get is the widget coordinate. That one is transformed according the scrolling offset. Then document origin, the top left coordinate of the image in canvas, also has to be taken into account. Next the zooming transformation follows.After this you are on document level coordinate system. On this level I mirror the coordinate. That means that the document is changed in mirrored manner. This works so far very nicely. For vertical mirroring you need to do transformation like scale(-1,1) and then translate(width,0) where width is the width of the document in my case. We mirror just vertically.
The next step is to mirror the projection of the image. I started to work in QPainter canvas as that one is the more complicated one. First I mirrored extra buffer QImage we have in canvas to be able to use RasterOp operations with Arthur. QImage::mirror() was just quick&dirty hack to see what will be broken. So tools outlines were broken as they don’t know about the mirroring and some features worked in mirrored way. I removed the dirty hack and I used QTransform for transforming the QPainter. I left the QPainter transformed this time also for tools so the outlines were fixed.
The OpenGL canvas was similar to QPainter canvas, I needed to do just the transformation and again setup the QPainter which is used even in OpenGL based canvas for painting the tool outlines.
Then I started to work on fixing some related, quite complicated, bugs. I spent a lot of time with them without solution. The issue does not seem to be complicated. You just need to mirror some coordinates. But it is hard to know which ones, if you did not write that projection code. The issues are that when you scroll and zoom-in in the part of the image, it became transparent. I suppose that projection thinks that part of the image is not visible so it does not update it or something like that. But I don’t know really if that is true and I can’t fix it either. Similar problem occurs in OpenGL canvas. I was not able to fix it either. I was trying but without lack. Try&error method did not bring any good results.
Then I spent time integrate the feature into Krita. You can mirror the canvas by View->Mirror Image (CTRL+I).To sum it up, the feature is in koffice-ko feature branch as trunk is frozen. It works with bugs we know about. We just need to fix them. The week I spent on it was nice start for this feature. Let’s hope the feature will be bug-free for Krita 2.3.
Setup brush softness with the curve
Stroke with custom curve to change brush mask
Dynamics of the soft brush in action
Softbrush density demo: Lukáš Tvrdý – House with charcoal
Softbrush mild jittering
Softbrush crazy jittering
Softbrush: Hue growing, saturation shrinking and value growing
Softbrush & spraybrush: n-pigeon – Watercolor


First version used 4 iterators over image pixels. One computation per pixel. And copy the values.
Improved version used two iteratiors and memcpy the second half of the brush mask.