Week 5&6: Krita hackfest

March 7th, 2010

I’m writing this blogpost from Boud’s kitchen. After 10 days of the Krita hackfest I feel quite dizzy. What I was doing?

According the action plan, this two weeks could be spent on some unfinished business. So we decided to work futher on the Adobe Photoshop brush integration. I fixed the type of the brush internally. Photoshop brushes for Krita consist of the alpha-map and the presets of the Photoshop’s brush engine. I ported the GIMP plug-in which loads the bitmaps in the abr brush. But the presets were not parsed.

Krita team: Where is the vision?

Frob wrote the python script which I mentioned previously in my blogpost. Frob and Alexandre Prokoudine are working on reverse engineering of the Photoshop’s resources like brushes and gradients. And their work includes also parsing of the brush engines presets. So I ported the script from python to Qt/C++ for Krita. The last step is to integrate the script. That was not done yet.

Then I arrived to Deventer, the Netherlands. Dmitry Kazakov was waiting for me at the airport and we went together to Deventer from Amsterdam. The weekend was gone so fast. We discussed a lot of issues together with Peter Sikking, interaction designer. That was very very interesting for me. I also met other Krita hackers I haven’t met yet like Adam or Vera. It is nice to be together, because you can be very productive.Together with Dmitry we fixed a bug in few minutes. It would take much more time if we would do it like a Report Bug -> Assign -> Fix.

Week 6 was the hackfest for me, Sven, Cyrille and Boud here in Deventer. We decided to give a try to 1/4 computation of the brush mask to have faster painting. This time it was implemented correctly. Before I tried to copy the 1/4 of the mask to the other parts of the mask. This time I decided to compute the brush mask with bi-linear interpolation. I spent 2 days on it fixing some artefacts that started to occur. Final measurements showed that the 1/4 computation is more expensive then the function itself as this time the arctan2 was not involved. Also other benchmark with arctan2 involved showed that the code is equally fast as the version without the interpolation. Maybe some bigger brushes will be faster but I need to investigate. The code is in trunk, we just need to find it’s usage.

Another optimization was for flood fill tool. Write benchmark, valgrind, identify the bottlenecks, try to fix them, do it few times and I was done. Cyrille helped me a lot, he is very good developer and he had always some good advices how to get the speedup. Finally I managed to make flood fill run 3.5 times faster.
Here is table and you can see how time dropped:

Start of the optimization
1. 5,921 msec
2. 5,752 msec
3. 5,574 msec
4. 3,581 msec
5. 1,711 msec
End of the optimization

The flood fill is still quite slow in the Krita. I tested on 4096×4096 pixel image. The performance problem now is that there is difference function used in the flood fill algorithm and the function convert the pixels to LAB. I suppose that in GIMP it is probably done on RGB 8-bit colorspace. But in Krita there are many colorspaces and the best way to do the difference is on L channel in LAB as Cyrille told me.

Then we were in Amsterdam in the Blender studios. We met Ton Roosendaal and the Durian project team. It was exciting for us. I managed to talk with Angela, the Durian artist from Canada. I had nice chat with her, lovely person. I also managed to talk with Ben, the artist who tried Krita and he also produced some art with it. I was in Amsterdam for the first time. I managed to see arrogant Amsterdam bikers, nice architecture and the cannal. We had long but nice walk around the town.

At the hackfest we discovered more performance issues. So I spent some time on smudge brush. I started with simple fixes and I started to work on some complicated issues. I’m writing bitBlt function for our fixed device. Fixed device is used for brush masks and it is faster then using paint device with tiles as the brush masks are usually small and they does not require tiles and undo. We need more function for bitBlt when the selection is stored in fixed device. So far I  the smudge is 1.42x faster.

Krita headquarter

Krita guys also started to work on various stuff that Peter Sikking proposed, e.g. we have a new widget and scratch box so I had to fix paintops also. Also I rewrote the deform brush. I’m trying to unify the brush engines in Krita and I wanted to add some new features to old brush engines, so rewrite was needed. The code was almost one and a half year old. I did a lot of work on brush engines also. Usually many fixes etc, but that is for other blogpost maybe later.

I would like to thank Boudewijn and Irina for taking care of us. The home-made food was “best thing ever” as Vera would say. I had nice time with the Krita team at Rempt’s house. Thank you for inviting me!

Busy week, I’m really tired and I’m looking forward for some rest and my home.

Wacom tablet does not work in Qt

February 27th, 2010

I’m at Deventer, we are having Krita sprint. I’m trying to implement some new stuff in Krita and I can’t :’( Tablet stopped to work for me in Krita and basically in Qt. I don’t see tablet events (qt example in widgets/tablet does not show anything), so no pressure, no tilt, just mouse events.

I have Fedora 12, Qt 4.6.2. linuxwacom was replaced by xorg-x11-drv-wacom, so there are no utilities like wacdump or xidump now.I removed old configuration lines in xorg.conf. They were needed long time ago, I used to setup my tablet according wacom tablet. I depend on the evdev now. The tablet work in mypaint and in Gimp. I have pressure support there.

I don’t have tablet pressure in Qt example in qt4/examples/widgets/tablet nor in Krita.

Cyrille proposed to check this command:

xlsatoms | grep -i wacom
303     Wacom Tablet Area
304     Wacom Rotation
305     Wacom Pressurecurve
306     Wacom Serial IDs
307     Wacom Strip Buttons
308     Wacom Wheel Buttons
309     Wacom TwinView Resolution
310     Wacom Display Options
311     Wacom Screen Area
312     Wacom Proximity Threshold
313     Wacom Capacity
314     Wacom Pressure Threshold
315     Wacom Sample and Suppress
316     Wacom Enable Touch
317     Wacom Hover Click
318     Wacom Tool Type
319     Wacom Button Actions
430     Wacom Stylus
431     Wacom Cursor
432     Wacom Eraser

So it looks ok. Have you got idea how to fix it? It seems that it is Fedora issue, other Krita developers
have working tablet support out of the box in the OpenSuse. I checked if the tablet support is compiled in Fedora, it is.

Krita hackers are offering me CD of OpenSuse. I like my Fedora, I don’t give up so far…Please, help if you can ;)

Sven Langkamp has also this same problem as I do, he is also on Fedora 12 these days.

Update 28.2.2010:
I filled bugreport for Fedora https://bugzilla.redhat.com/show_bug.cgi?id=569132

Also for Qt http://bugreports.qt.nokia.com/browse/QTBUG-8599

UPDATE: It works now with some patch. Fedora will ship some update soon. Thanks to Thomas Zander for the patch and Fedora guys for providing me test build!

Week 4: Optimizing iterators

February 22nd, 2010

So what happened last week? Except that Slovakia upset Russia in Hockey at Vancouver, Slovakia is also fixing Krita performance thanks to the donors, from all around the world, who made that possible. Enough about nationality, let’s talk about what happened.

The plan for the last week was to optimize iterators. We use tiled buffers for our memory management. You usually need undo function in the image processing application and storing the whole image is not a good idea. You rather break the image into tiled parts, rectangles and you store and restore them. But affects the whole application, you have to iterate pixels in filter, you have paint with the brush and that means to composite one image over another image. So basically iterators are very important for Krita. Its speed is priority of course.

We knew, from the measures  I did first week, that fetching those tiles is a slow process. That’s why we have a rectangle iterator which iterates the image tile by tile. But sometimes you need to iterate the image in lines. E.g. in the filters or under some special conditions when you need the access to the pixel before and after in the same line.

That’s why we have a line iterators, we have a vertical and a horizontal iterator. I was optimizing the line iterators. Instead of fetching the tiles every width/height of the tile, we now pre-fetch the tiles to some buffer, lock them and work with them, til we can skip to the next row of tiles. The tiles are 64×64 big by the way. Another important thing is that Krita is threaded and one thread is doing a projection updates (the final image you see in Krita) and other can work on some other stuff like painting or filtering. So we have to lock&unlock the tiles. I patched the vertical and the horizontal iterator.

Ben Dansie: Monkey

We managed to get speedup like 1.28x til 6.21x faster iterating. Cyrille Berger then suggested that we have quite complicated structure for iterators with many function calls, so let’s try a new API for iterator with less function calls. So my task was to code or better said port the horizontal iterator to the new API. The iterator is ready for testing. According the benchmarks, the new iterator is 1.5x faster then old API. Also Cyrille added a lot of custom magic to it so that it is faster. We are closer to the data manager speed, which limits the speed of iterators.

On Monday I also fixed the abr brush so that we can paint with abr brushes, but the work is not finished yet. This week I will work on it and also I will try to use the new iterator in KisPainter for compositing and explore the time results. Then at the end of the week I fly to Netherlands, where we are having our Krita sprint in Deventer, in Boudewijn’s home. I will spent 11 days there with other Krita hackers. So a lot of coding in front of us. We will be visiting the Blender team also. I’m looking forward to it!

So far we make progress, Sven Langkamp made me happy saying that the speedup for painting even with some filters is amazing now compared to what it was before. Also the artist, Ben Dansie,  from the project Durian, the Blender project of the open movie, used Krita for making some art. Cool, isn’t it? Now back to rediscover your Krita code ™.

Week 3: Photoshop brushes

February 15th, 2010

Last week was devoted to add support for abr and vbr brushes. The abr file format comes from Adobe Photoshop, the later comes from Gimp. The motivation for this were the big collections on the web. Sites like deviantart.com are full of the artist’s collection of the abr brushes. The motivation is also interoperability with GIMP and with proprietary Adobe Photoshop. vbr brush support was postponed because it was too much work just to support abr brushes.

First day I started with exploring the abr format, so that we know each other a bit. I started to write simple code to parse it, but I found out that the issue is so complicated. Valek Filippov is working on the python script which parses abr brush, so I started with that one. Important note: We support only brush format v1, v2 and v6.2 (Photoshop CS2). The newest format is not documented at all and there is not open-source implementation around. It would require a lot of reverse engineering and that takes so much time, that we would need much more time then one week for it.

Next day I realized that it would go too slow to just work with the script and I felt that we need to draw soon. So me and Boudewijn, we googled for other sources and we found GIMP plug-in which is maintained version of the work based on this code. It parses just the bitmaps from the abr file format. That’s the basic thing you need to parse out of the brush file format. There are many other options saved in abr brushes, like the setting of the brush engine (attributes like diameter, spacing, angle…) but we don’t parse them yet. Valek Filippov’s script does. We have chance to have better support for the brushes, the settings look like our brush engine presets.

I was porting the ANSI C code which used the glib to Qt. It took two days to port it correctly. Next two days has been devoted to integration into Krita. The architecture for the brushes is powerful, but it is not easy, so I spent time investigating how it works and what do you need to do so that your brushes are correctly displayed and painted.We load all the brushes in the memory when Krita starts. Krita uses nice resource architecture, but it did not have support for importing one file as many resources. Abr brush consists of many bitmaps, which we use as brush masks so far. Sven Langkamp helped with that. Boudewijn Rempt helped  a lot by doing preliminary integration code and then I was fixing it so that it works. We decided to  reuse the brush chooser dialog we use for gbr brushes (other Gimp brush format). For the future it would be cool to have more features in the brush chooser dialog, or maybe we will need to write different widget for abr brushes. Some categories would be useful.

The painting with abr brushes does not work yet. I will work on the bugs. We get the correct image in the brush generation code, but we paint plain colored rectangle instead. There are some minor bugs that needs to be fixed too.

For the future it would be useful to support the attributes of the brush engine saved in the format. Our brush engine should support most of them, maybe some features will have to be coded and some are hard to implement as there is no specification for them.

Here is screenshot showing loaded abr brush into our brush chooser. The code is already in trunk, so you can at least see your brushes in the chooser. I hope we will be able to paint tonight!

13:57 update: The problem is fixed and now I paint with the abr brushes!

Brush chooser with Abr brush masks

Week 2: Optimized Autobrush. Faster painting.

February 8th, 2010

The second week of our action plan for optimizing Krita was devoted to optimizing painting in Krita. Although there are many great paintops in Krita, digital painters tend to use most of the time the simple default brush engine which we call Pixel Brush. Painters can use GIMP brushes here, the text brush, but the most used brush tip is called Autobrush. You can setup the brush attributes like shape (circle, rectangle) and you can change the ratio to get an ellipse. Then you can change softness by vertical and horizontal fading. If you play with spikes and ratio, you get stars and other funny shapes. The brush has many dynamic attributes thanks Cyrille Berger’s work on concept called sensors. E.g. tablet can control the size by pressure, by tilt or anything you want (e.g. interesting is drawing angle) and it can be tuned by curve.

The algorithm, which computes the brush mask, stamped on the canvas regular as you stroke, is computed by the KisCircleMask::valueAt(). It is a computationally expensive function according valgrind logs we did week ago and many times before. David Revoy, team member of the Durian project, said that using 70px brush on 2500×2500 image was very slow in Krita. So we needed to optimize that.

I started with exploration of the code. I’m not the author of the autobrush, though I did most of the paintops in Krita (10 paintops are mine out of 19, many are experimental). First catch was the interpolation in the brush mask computation. We called valueAt() 4 times per pixel of the brush mask. We found out with Cyrille that the valueAt function used to take integer parameters a long long time ago and double values of the brush mask pixel positions were computed with interpolation. So I decided to remove the interpolation as the function has been capable to take double input long time ago. And the results of the valueAt() are more precise then interpolation. The benefit was great. Painting was 4x faster. Benchmark for random lines with changing size according pressure dropped from 18 seconds to 4 seconds on 4096×4096 image. Check it in the wiki, related table is called Just with performance fix.

From the valgrind logs we noticed that the atan2 function is called too often. “Chickenpumpsuggested some cool old school tricks in comments. And so we gave that a try. I used double hashing with QHash in QHash for the 2D function atan2, but that was very slow due to low cache hit ratio and expensive hashing. Then Cyrille posted some links with free code which implemented a fast atan2 with an internal lookup table. So I ported that code to Krita. Cyrille did some magic stuff like computation with fixed precision on library loading time and some little tune ups to speed the fast atan2 computation and we managed to get more speed up around 1.3x faster then without fast atan2 function. There is probably some more room for optimizations as the fast atan2 implementation uses a quite small lookup table. Also I tested some other implementations, but it had problem with precision. It had 3 degrees error. That is too much for us, so I dropped that.

I remembered a quite interesting magic function for fast inverse square root used in Quake III. So I gave it a try as we use inverse square root in valueAt() too. I found out by benchmark that fast inverse square root is slower then directly computing the inverse square root (1/sqrt(x)). It used to be 4 times faster a long time ago. Probably Intel implemented that in processors already. Or the optimization done by compiler was not so effective in case of fast version. Again we dropped that.

Most of the use cases for painting include brush masks which are symmetrical. The algorithm could compute just 1/4 of the mask. Next step was implementing this.

First version used 4 pointers to the memory and compute 1 pixel and copy 3 pixels to the right region. I managed to get another 1.7x speed up (from 3.555 ms to 1.9 ms).

Memory access is very important and can slow down computation. It is like when you use setPixel/pixel method to access pixels in pixel buffer – you supposed to use scanlines, that is faster. Here is some interesting article about it. If you don’t have something to read, here is also nice CPU memory bible.

4 iteratorsFirst version used 4 iterators over image pixels. One computation per pixel. And copy the values.

So I decided to make it little faster just by using two pointers. I compute 1/4 of the mask and copy this part to the NW region. And then I copy the rows in the lower part of the mask in correct order – I mirror it.

2 iterators version Improved version used two iteratiors and memcpy the second half of the brush mask.

I found out on friday evening that it does not work though. Circle masks seems symmetrical from user point of view, but they are not. The brush mask respects sub-pixel precision in Krita, so the edge pixels of the circle are not symmetrical. The sub-pixel precision is visible when you work with big zoom level. I have an idea for computation 1/4 of the brush mask, but I decided to post-pone it.

Other possibilities are still around:

  1. mip-mapping : pre-compute various levels of brush mask to buffer and interpolate the masks. We do this for Gimp brush. We would interpolate two computed brush masks instead of computate the single mask. Maybe it could be faster, maybe not. The reason for mipmap in GIMP brush painting we have, was to increase the quality of the scaled brushes as Adrian Page, hacker in the Krita team, wrote me in an email. Mip-mapping would require to split rotation from the mask computation. This can lead to different results regarding of the brush mask. Now we consider the rotation in the mask computation. Then we would rotate un-rotated mask by image processing – rotate image. Some conformation rendering test would be needed. The advantage would be support for rotation of the gimp brushes in Krita.
  2. cache the brush mask for mouse users: cache the dab as the mask doesn’t change. This would be nice if we did not compute sub-pixel precision. But we do that, so the cache hits ratio would be very small. It would be usable for 100% zoom, when sub-pixel position is zero. And of course big condition for checking of the parameter changes would be required.
  3. Compute the mask with graphics card – use shaders: that would be cool, I have some initial experience with shaders but integration would be harder and probably too experimental for our plan. I’m mentioning this as we discussed this with Sven Langkamp in Oslo and so that it is not forgotten.
  4. We will probably do some garbage recycling – memory allocation is slow, we can benefit from recycling memory. It is a matter of discussion on IRC at #krita on freenode. You are welcome to join.

Final time of the computation in benchmark for random lines is 1,449.2 ms. It dropped from 18,576 ms. So the painting was 16xtimes faster.But I revert the 1/4 of the brush mask speed up, so the current speed is 3.555 ms. Painting will be 6xtimes faster. The speed is considered to be usable for big brushes now. I invite you to do check-out of the trunk and try to play with big brushes. 200 px is now very usable on my laptop. What about yours?

I updated my WordPress blog. I dropped the previous classic WordPress theme and selected the default one – lazy developer. I did not like the font in the previous one. I don’t have much time to play with web-designing these days. But at least I customized the default Kubrick theme. I changed the fixed width of the theme to wider values. I did also simple custom header with some random strokes with my paintops in Krita. I hope you will like it. Every image in the blogpost is made in Krita.

First week of Krita full-time hacking

February 1st, 2010

I finished all my exams on time, so last Monday I could starting working full-time on Krita. I’ve now been at it for a full week! How does it go?

First week according the plan was aimed at measuring the speed of Krita. We talked about our bottlenecks on IRC regulary. We also talked about them in Oslo. But we didn’t have any numbers. Sven Langkamp did some benchmarks using QTime on iterators, there were some performence tests scattered in unit tests etc. Boudewijn has decided to use new benchmark features from Qt4.6. So I wrote 10 benchmark classes where we benchmarked stuff like internal data memory management for images – our tile engine. Some access classes which access pixels for use called iterators. They allow to iterate over pixels in various ways. Vertically, horizontally , in small rectangles, randomly etc.

Another important thing is compositing. That is the work of class called KisPainter (something like QPainter in Qt but with different complicated features not available in QPainter). We benchmarked the speed of bitBlt operation with two types of memory storage. First is KisPaintDevice and second one is called KisFixedPaintDevice. The later one is lightweight version of the first one. It is similar to QPaintDevice in Qt but again with more complicated features.

Øyvind Kolås a.k.a. pippin, Gegl developer is around. Pippin shared his knowledge about benchmarking with us on irc (btw come and visit as at #krita on irc.freenode.net) We decided to make tests for blur and brightness/contrast filter. The first one is convolution filter, the second one is here because we wanted to be able to compare to GIMP.

We also made a benchmark for the image projection. The projection benchmark loads an image in Krita’s native format, computes the whole image constructed from various types of layers like group, filter, adjustment layer etc. and in the end we again save the file into native Krita format. Our focus through this plan is to speed up painting. So we can’t avoid stroke benchmarks.

Result image from the benchmark of the strokes

Thanks go to Sven Langkamp for his work on presets saving/loading. Using paintop presets, we can use the benchmark code I did, for any paintop. We benchmarked our autobrush default paintop. It is most used paintop for digital painters. I’m very happy about this benchmark as I can test my other paintops easily, all I need to do is create a preset for any paintop, save it in Krita and run the benchmark with the preset.

There results of the benchmars are on our wiki.

So it looks: The data manager, which is responsible undo/redo and basically for storing and retrieving data is fast. It allows us to read/write data at very high speeds.  From 1333.3 Mb/s to 1628.4 Mb/s, according to the benchmark results. We benchmarked on 4096×4094 RGBA image (64 Mb) which was read/wrote 100 times. For comparison memcpy for two buffers of the same size as the image we used is almost the same speed. There is benchmark code for memcpy in KisDatamanagerBenchmark, you can try it yourself if you want :)

Horizontal and vertical iterators are 11 times slower then Rectangular iterator. The reason is that there is no caching. From valgrind logs we see that fetching and switching tiles is very slow, so we need to implement caching there. Every 64 pixels a new tile is fetched and switched to. Why? Our tile is size of 64 pixels. This slow downs the iteration. We will cache the both iterators to avoid switching and fetching. We will cache tiles, we don’t do that now. The rectangular iterator is quite fast, does not offer so many opportunities to improve. The random iterator on the other hand is the slowest one. Again fetching and switching to tiles is expensive. Some caching strategy would be handy for moving around the image. But the use case for using the random accessor is different so the cache strategy should be somehow adaptive. The random accessor is 13-times slower than rectangular one.

The compositing operation also known as BitBlt of KisPainter is used very often. There is room for improvements, because currently it uses a slow iterator – random iterator. The speed is very decent, but we will try to make a lot faster.

Filters are very slow compared to GIMP. At least according the numbers pippin provided. But first we need to improve underlying issues like the aforementioned iterators to improve their performance. We blur the image with speed of 0.8 Mb/s. Here we need to optimize the convolution painter. Also the speed could be better when we optimize the horizontal iterator.

Strokes are slow because of the recomputation of the brush mask is needed  every dab – every time brush touches the canvas in certain point. That’s slow. You can see from the valgrind log, that the math function atan2 is slow. We have to cache the result to avoid this.

The conclusion at the end of the first week is that we need to cache iterators and cache the brush mask. Some parts of Krita have very nice speed like the tile engine. Then we have slow parts like iterators. I think we can gather a good performance boost with our plan.

Cross-compile Qt4 app for Windows on Fedora 11

December 29th, 2009

I made school project in Qt4.5.3 and my teacher does not use Linux so I decided to try to cross-compile the project for her from Fedora 11. Here are the steps. Let’s hope it is useful for you too.

First you have to install mingw compiler, so I did something crazy like:

yum install mingw32*

That grabs everything related to mingw (installs Qt4 libs, compiler, qt-qmake specs files) on Fedora 11. Many unrelated libs are installed too (Gtk, …) – you have been warned.

Then you create Qt4 project file if you don’t have one already

qmake-qt4 -project

Pass the qmake specification:

qmake-qt4 -spec fedora-win32-cross

Run this so that QtGui is found

QMAKESPEC=fedora-win32-cross qmake-qt4 QT_LIBINFIX=4

Compile!

make

Then I found exe file in release/ directory. I wanted to distribute it so I needed to distribute some dlls too. To find out I run

i686-pc-mingw32-objdump -p prog.exe | grep dll

It lists all used dlls.I copied them from Fedora box to the same folder as the binary and I was done!

I used locate to find them (found in /usr/i686-pc-mingw32/sys-root/mingw/bin/). QtCore4.dll, QtGui4.dll and libgcc_s_sjlj-1.dll was needed for me.
I did not copied KERNEL32.dll, msvcrt.dll etc. Windows users usually have those files.

Then it worked for me. The app looked bad but worked as supposed to. In Wine it had some bug, but it worked on Windows XP.

Thanks for help to the fedora-mingw team at #fedora-mingw on freenode IRC ;)
https://fedoraproject.org/wiki/MinGW/Tips – related wiki page

Spray improvements

December 21st, 2009

I spent a lot of time working on spray brush because it is really fun to improve it. After some time developing it I heard from enki, our great artist who is available for feedback, that he was able to do something with spray in a few seconds in a comparison doing the same thing with image hoses in GIMP. Great, I’m reaching my goal.

Last time I blogged about spray, it wrote about adding support for spraying bitmaps. Since then I have added more control to rotation of the particles which are sprayed from spray. The particle’s rotation follows the mouse position, can be rotated by random or by constant angle. And even you can mix it, so you can rotate partially random and partially constant and partially by following the mouse position. Almost every particle type (ellipse, rectangle, image) supports this expect pixel particles. It will be fixed by moving the pixel particle type to a different user interface so that the user is not confused.

Control of the particles

From the UI point of view there is a “keep aspect” button in the particle type setting dialog. When you change the width of the brush, the height is locked and changed according the aspect. Also the proportional setting has been merged into less UI components to make the dialog nicer.

The spraying area of spray has been improved. So far you were able to spray particles in circle and you were allowed to change the distribution of the particles to gauss distribution. Gauss distribution is nice, because it behaves somehow “naturally”. In spray more particles are randomly distributed around the center of the spraying area with this distribution. Common ANSI C command rand() distributes the numbers uniformly so every particle position should be distributed with the same probability. This is used when you don’t check gauss distribution in the spray UI.

Now I made it possible to spray in ellipsoid shape. And this brings new opportunities — I can rotate the area. On this picture you can see that I rotated the ellipsoid distribution of circle particles  in the “sun”. I used the circle tool, dabs of spray has been rotated. Then on the cloud you can see that particles are distributed in ellipse too. Rotation can be controlled manually by constant angle.

I added also few sensors called “Size”, “Opacity” and “Rotation”.The rotation sensor allows you to rotate the distribution by tablet’s tilt, pressure and by some funny attributes like time or drawing angle. The size sensor controls the size of the distribution area. Opacity controls the overall opacity of the single spray dab. The sensors are Cyrille’s idea and I’m trying to use it in my paintops, so that we have consistent UI and we share more code.

Another thing was exponential slider in kdelibs4.3. Now you can reuse bigger area of the slider for setting your preffered size of the brush.So far the slider has been linear. You move a little and you would end up with a size of 200px. Now if you move a little from e.g. 50px size, you get 70px and not 200px. You usually use smaller values often and only sometimes you want big brush with 1000 px width. Again Cyrille’s patch for kdelibs and implemented by me in Krita :) Spray has exponential sliders in UI for particle count and diameter. It is very nice and I consider it very usable.

I added many sliders to spray because David Revoy wrote me longer time ago that he prefers them with tablet. I added so many sliders that the UI is becoming very ugly, but useful!  My brush engines are becoming something like motor engines :) Just few folks around knows how to tune them because they understand them.. This is wrong of course. One solution is that you as user should get nice presets so that you don’t have to touch engine too much. You just fine tune size or rotation a little. That’s where it is heading now somehow. We will have a lot of presets for you when we implement presets saving/loading I hope.

Ellipses

There are some bugfixes also in UI here and there, chalk has been improved a little – ink depletion can be turned off. Opacity sensor has been added to chalk so you can control overall opacity with tablet and some minor fixes. So far so good. I plan to constantly improve digital painting in Krita.

More information can be found at our “commit-digests” Week in Krita at krita.org. See week 46, 47, 48, 49, 50 and soon 51. Nice read when you want to watch Krita development.

Life

I have been in Oslo for KOffice sprint and it was wonderful. I had a lot of fun, meet other Krita hackers and we had nice discussions about Krita.I had a lot of fun with Jarek Staniek, the Kexi guy. Very nice man! He helped me to setup Windows development environment for Krita, but I failed somewhere and I did not find time to fix it and continue.I learned something about building API too. Oslo is nice place, but quite dark for me and quite expensive. I would like to thank Thomas Zander and Alexandra Leisse for the organization.

We started a campaign to gather money so that a member of Krita team can work full-time on Krita. I’m that team member :) I would like to thank every donor that you make this possible. Thank you! As you can see we are over goal, but you can still donate if you want.

I remember days when people put some money together to allow Blender being a open-source application and look where Blender is now – it is used by professionals. Now something similar can happen with Krita. We have a plan to implement and we think that it can make Krita very usable for digital painters . I’m looking forward to work on Krita full-time. Just few last exams in university in January and I’m ready to start to work.Keep the fingers crossed! I will keep you informed about the progress regularly.

Click here to lend your support to: Help raise Krita to the next level and make a donation at www.pledgie.com !

Let’s spray everything

November 13th, 2009

I added new feature to spray -  spraying bitmap images (textures). Thanks to the KDE you can load plenty of image formats. It starts with Qt QImage supported file formats and continue with KDE supported file formats (psd, xcf to choose the most used ones). Let’s be the mentor for you for a while and teach you how can you do nice things. Let’s start with autumn wallpaper.

Tutorial

You need svn copy of Krita (how to build koffice ) and  some leafs textures (e.g. I used this one , found in wikipedia by Kubuntiac ). The texture has alpha channel, it is png file. That is important so that it looks cool. I scaled that texture to 192×118 px and named it leaf2.png.

Spraying bitmaps works nicely with objects that are cut from some pictures, e.g. some kde hackers on planet have their faces properly cut from photos. It is good example object for spraying.

Some random KDE hackers from planet

In Krita you select spray brush and go to options. In Particle Type you select Spray object to image. Then you select the image within the dialog (Open The File, locate leaf2.png on disk and click ok). In brush size you can specify with particle number — how many images will be sprayed per dab (something like per mouse move event:) ) but what I changed there is spacing to 1.0, so that the brush reacts quicker and with less density. In Color dialog check random HSV and move hue to value 40, saturation to -40 and value leave intact. Here you can experiment. Experiment with scale and brush size too. Brush size can be changed by pressing shift and moving with mouse left and right on the canvas. It was added lately and it is quite handy.

Let’s look at some pictures. This autumn image was made with the leaf texture I mentioned above and one other leaf texture. HSV trasformation nicely changes the texture so you get rich colorful image with just one or two textures.

Spraying leafs - HSV transformation useful

Filters can be useful when painting, here is post-processed version (I used auto-contrast filter). It has different mood, more like some cartoon, illustration style :)

And one for upcoming winter. I did this one with snow flakes. Those are used as textures. Clouds done with feature I wrote about last time.

Snowing [done with spray]

This feature is present in other apps in some ways too. I don’t have Photoshop or Corel Painter, I never used them before but Boud told me that similar feature is called image hose in Corel’s Painter. In GIMP similar feature is called brush pipe.

Developing future

I have to polish the GUI, optimize the algorithm so that more and big images can be sprayed more faster. I plan to improve the particle settings, add more control to rotation to the user’s hands (tablet support, etc. )

Questions

How do you see it? Do you like it? What would you add to the spraying of bitmaps?

Krita: Everybody can make a painting

November 1st, 2009

I decided to share some GUI between our brush engines (paintops in Krita jargon). I started with color dialog. The color dialog is work-in-process. I co-operate with Cyrille Berger so that more paintops can benefit from color trasformations and also I want to add features that Cyrille coded. First implementers of the color dialog are spray and grid brush.

Color dialog

So I implement some features that are available with grid brush to spray. And now you can do fun stuff. You can be artist with just few clicks. Everybody can make a painting :)

There is painting style called pointillism. If you want to know what is that, wikipedia has nice article and nice picture in neo-impressionism article. Inspiration came also from Paul Haeberli, who did really great job in area of non-photorealistic rendering (Paint By Numbers article). There is Paul’s applet where you can be impressionist (pointillism style also possible with proper settings).

Now in spray brush in Krita you select particle type circle, you check in color dialog, that you want color per particle and sample input color. Then you just go through image and paint where you want. You can get the same result as in picture I did. Don’t forget to load some cool photo which colors will be sampled.

Pointillism

Pointillism with spray brush in Krita

You can select different particle type to get different style. E.g. I selected rectangle with 1px width and 60px height size (lines ;)   and checked random size and same options in the color dialog. I also checked random opacity and random HSV and used sliders to post-process sampled colors as I paint.

ImpressionistKrita-impressionism with spray

So far it is destructive editing, so you paint on photo in the layer. For future you will be able to select layer in which your photo is loaded so that it is not destroyed.

I love to paint clouds :) I always wanted to be able to paint clouds with my brush engines and now I’m closer to that aim. Here is what I get with spray and color dialog:

Clouds

Let’s describe random HSV and opacity a little. Random opacity select random opacity of the color. Easy. Random HSV turn on hue, saturation and value transformation of the color. The sliders in the color dialog sets how much and how far the color can be transformated. If you select from HSV e.g. value to zero, color’s value will not be changed. If you select value 100, then color’s value will be randomly adjusted to interval 0..100. Applies for the hue and saturation in the same manner. You have to understand the HSV model for this usage.

For the clouds I selected white color and checked random opacity and HSV and dragged the value slider to negative values to get darker colors. And I played with gray colors and saturation. Working on thesis is fun! ;)