Week 3: Photoshop brushes

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

Posted in Krita | 6 Comments

Week 2: Optimized Autobrush. Faster painting.

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.

Posted in Krita | 10 Comments

First week of Krita full-time hacking

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.

Posted in Krita | 8 Comments

Cross-compile Qt4 app for Windows on Fedora 11

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

Posted in Fedora, Qt | 6 Comments

Spray improvements

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 !

Posted in Krita | 1 Comment

Let’s spray everything

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?

Posted in Krita | 7 Comments

Krita: Everybody can make a painting

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! 😉

Posted in Computer graphics, Krita | 1 Comment

New brush in Krita: Grid brush

I created new funny brush call grid brush. It was inspired by this flash game and I added idea that needed to be implemented long time ago – sample colors from under your brush. Paul Haeberli talks about it in Paint By Numbers article.

What can you do with it?

1. Make art from your photos. Easy. Just check in color dialog that you want to sample input color. Select some various divisions in brush option and ride with your cursor on image.

Grid preview

2. Somehow create the mentioned game pictures. Just play with grid size, color options and division level in options.

Grid game

3. Pixel-art. Various options allows you to generate funny things. I hope some Krita users will make something more representative in the gallery.

Pixel art with grid brush

Grid brush has also some tablet support, e.g. for mixing the background color with input or foreground color and the division level can be changed by pressure. This brush is still work-in-progress, but you can already play with it as the trunk for KOffice is open again. Except this in Krita 2.2 😉 I have fun with gridbrush. I hope you will have too :)

Posted in Krita | Leave a comment

Krita forum: Communicate

We need the place where our users can meet. The place where the artists can share their artworks and tips&trick for Krita usage. Gimpers have their GimpTalk. Blender users have their blenderartists. Krita has it’s new Krita forum! Mailing-lists are cool, but not so much among users. Krita has it’s hidden mailing list here but the topic is usually development. Krita used to be called kimageshop.

Krita

We thought we will start the separate forum on krita2d.org (old not-up-to-date website) or we would go for KDE Forum and do what amaro(c)kers did with with their forum. We decided to go with KDE Forum for two main reasons:

  • it is a cool team, the KDE forum..and working with them was pleasure for me
  • we don’t have enough people to handle forum (it requires to code features, moderate, fight spam, etc. ) and Krita developers want to focus on developing Krita

Thank you, KDE Forum team!

Our forum is small and we hope it will grow and we will add more interesting subforums like those on the mentioned forums.

So now go and enjoy the new Krita forum. Post your artworks, ask how to use Krita, share and get Krita related news!

Posted in KDE, Krita | 4 Comments

How to render outlines in Qt?

I have seen some approaches how to paint tool outlines in KDE/Qt apps. We draw two types of outline in Krita:

* When you want to draw a line with line tool, you want to see the preview of the line. If you want to draw rectangle or ellipse or any shape in Krita, you also get the preview. Call this tool outline.

* When you paint with some brush in Krita, you need to see the position of the brush. You can have a cursor or the shape of the brush. That way you can see the preview of the brush borders. These shapes can be complicated. You can have brush shapes like big vector flower or something.

RasterOP_XOR

So far we used black lines for outlines in Krita2. It has big problem. You can’t see black line in black background, can you? So I wanted to resurrect XOR from Qt3 times in Krita. It has been also older regression. XOR has been removed, but it is somehow back. You can set QPainter to composite mode RasterOp_XOR. The disadvantage is that you can’t have anti-aliased lines with it. I solved this with CompositionMode_Exclusion. That one is similar to XOR. But that one does not work if you render on X11. You have to use QImage as buffer for your widget. So I added the QImage as buffer to our Arthur canvas (we also have OpenGL canvas, but we support both of them of course) and that way it worked.

Then thanks to C. Boemann showed me that it is not the solution. There are colors which make the outline invisible. When you use some colors as outline color(e.g. 128,255,128) and you have background RGB(127,127,127), the outline is invisible. This hidden problem is CompositeMode_Exclusion. But not in the RasterOp_XOR. That outline color (128,255,128) is not selected by random but by old bug report from Gimp. The selected color XORed to image is always contrast enough so it does not hide itself. So CompositeMode_Exclusion does not solve our problem, it just moves it away. We decided to use RasterOp_XOR so far. Outlines are not anti-aliased, but at least it does not hide itself. If you use OpenGL canvas in Krita, also XOR mode is used but lines are anti-aliased — we use OpenGL code for that. I wrote that piece of code through GSoC as you may remember..

We tried to paint outline 3px wide: semi-transparent black line 3px wide and white line 1px in between. That one may work but it looses some pixel precision in same use-cases. In a perfect world outline should be 1px wide — at least in pixel&image editing or painting app like Krita, Gimp..

What do you use to paint tool outline when you want pixel precision? And how do you paint outlines when the pixel precision is not important?Altering two colors looks usually too ugly :( At least for me..

The most nicer result I found is Inkscape. Inkscape uses some composition which makes it work on every color too. This was found in discussion what is Photoshop doing. When underlying pixel is bright enough, use dark color. If the underlying pixel is dark too much, use bright color? Maybe Inkscape uses also XOR with some color…I did not find out.
Write custom composite operation for Qt would be solution?

Zoom tool in Inkscape

Posted in Design, KDE, Krita | 2 Comments