Saturday, August 2, 2014

Krita: illustrated beginners guide in Russian

Some time ago our user Tyson Tan (creator of Krita's mascot Kiki) published his beginners guide for Krita. Now this tutorial is also available in Russian language!

If you happen to know Russian, please follow the link :)


слайд

Krita: иллюстрированное руководство начинающего художника на русском



Совсем недавно наш пользователь Тайсон Тан создал замечательное руководство для начинающих пользователей Криты. А благодаря переводу  Георгия Сыпченко теперь это руководство доступно и на русском. Щелкаем на картинку и изучаем!



Monday, July 14, 2014

Notes from Calligra Sprint. Part 2: Memory fragmentation in Krita fixed

During the second day of Calligra sprint in Deventer we split into two small groups. Friedrich, Thorsten, Jigar and Jaroslaw were discussing global Calligra issues, while Boud and me concentrated on the performance of Krita and its memory consumption.

We tried to find out why Krita is not fast enough for painting with big brushes on huge images. For our tests we created a two-layer image 8k by 8k pixels (which is 3x256 MiB (2 layers + projection)) and started to paint with 1k by 1k pixels brush. Just to compare, SAI Painting Tool simply forbids creating images more than 5k by 5k pixels and brushes more than 500 pixels wide. And during these tests we found out a really interesting thing...

I guess everyone has at least once read about custom memory management in C++. All these custom new/delete operators, pool allocators usually seem so "geekish" and for "really special purposes only". To tell you the truth, I though I would never need to use them in my life, because standard library allocators "should be enough for everyone". Well, until curious things started to happen...

Well, the first sign of the problems appeared quite long ago. People started to complain that according to system monitor tools (like 'top') Krita ate quite much memory. We could never reproduce it. And what's more 'massif' and internal tile counters always showed we have no memory leaks. We used exactly the number of tiles we needed to store the image of a particular size.

But while making these 8k-image tests, we started to notice that although the number of tiles doesn't grow, the memory reported by 'top' grows quite significantly. Instead of occupying usual 1.3 GiB, which such image would need (layers data + about 400MiB for brushes and textures) reported memory grew up to 3 GiB and higher until OOM Killer woke up and killed Krita. This gave us a clear evidence that we have some problems with fragmentation.

Indeed, during every stoke we have to create about 15000(!) 16KiB objects (tiles). It is quite probable that after a couple of strokes the memory becomes rather fragmented. So we decided to try boost::pool for allocation of these chunks... and it worked! Instead of growing the memory footprint stabilized on 1.3GiB. And that is not counting the fact that boost::pool doesn't free the free'd memory until destruction or explicit purging [0]

Now this new memory management code is already in master! According to some synthetic tests, the painting should become a bit fasted. Not speaking about the much smaller memory usage.

Conclusion:

If you see unusually high memory consumption in your application, and the results measured by massif significantly differ from what you see in 'top', you probably have some fragmentation problem. To proof it, try not to return the memory back to the system, but reuse it. The consumption might fall significantly, especially is you allocate memory in different threads.



[0] - You can release unused memory by explicitly calling release_memory(), but 1) the pool must be ordered, which is worse performance; 2) the release_memory() operation takes about 20-30 seconds(!), so there is no use of it for us.



Sunday, July 13, 2014

Notes from Calligra Sprint in Deventer. Part 1: Translation-friendly code

Last weekend we had a really nice sprint Deventer, which was hosted by Irina and Boudewijn (thank you very much!). We spent two days on discussions, planning, coding and profiling our software, which had many fruitful results.

On Saturday we were mostly talking and discussing our current problems, like porting Calligra to Qt5 and splitting libraries more sanely (e.g. we shouldn't demand mobile applications compile and link QWidget-based libraries). Although these problems are quite important, I will not describe them now (the other people will blog about it very soon). Instead I'm going to tell you about a different problem we also discussed — translations.

The point is, when using i18n() macro, it is quite easy to make mistakes which will make translator's life a disaster, so we decided to make a set of rules of thumb which developers should follow for not creating such issues. Here are these five short rules:

  1. Avoid passing a localized string into a i18n macro
  2. Add context to your strings
  3. Undo commands must have (qtundo-format) context
  4. Use capitalization properly
  5. Beware of sticky strings
Next we will talk about each of the rules in details:

1. Avoid passing a localized string into a i18n macro

They might be not compatible in case, gender or anything else you have no idea about

// Such code is incorrect in 99% of the cases
QString str = i18n(“foo bar”);
i18n(“Some nice string %1”, str);


Example 1

// WRONG:
wrongString = i18n(“Delete %1”, XXX ? i18n(“Layer”) : i18n(“Mask”))

// CORRECT:

correctString = XXX ? i18n(“Delete Layer”) : i18n(“Delete Mask”)
 

Such string concatenation is correct in English, but it is completely inappropriate in many languages in which a noun can change its form depending on the case. The problem is that in macro i18n(“Mask”) the word "Mask" is used in nominative case (is a subject), but in expression "Delete Mask” it is in accusative case (is an object). For example is Russan the two strings will be different and the translator will not be able to solve the issue easily.

Example 2

// WRONG:
wrongString = i18n(“Last %1”, XXX ? i18n(“Monday”) : i18n(“Friday”))

// CORRECT:
correctString = XXX ? i18n(“Last Monday”) : i18n(“Last Friday”)

This case is more complicated. Both words "Monday" and "Friday" are used in the nominative case, so they will not change their form. But "Monday" and "Friday" have different gender in Russian, so the adjective "Last" must change its form depending on the second word used. Therefore we need to separate strings for the two terms.

The tricky thing here is that we have 7 days in a week, so ideally we should have 7 separate strings for "Last ...", 7 more strings for "Next ..." and so on.

Example 3 — Using registry values

// WRONG:
KisFilter *filter = filterRegistry->getFilter(id);
i18n(“Apply %1”, filter->name())

// CORRECT: is there a correct way at all?
KisFilter *filter = filterRegistry->getFilter(id);
i18n(“Apply: \”%1\””, filter->name())

Just imagine how many objects can be stored inside the registry. It can be a dozen, a hundred or a thousand of objects. We cannot control the case, gender and form of each object in the list (can we?). The easiest approach here is to put the object name in quotes and "cite" that literally. This will hide the problem in most of the languages.

2. Add context to your strings

Prefer adding context to your strings rather than expecting translators reading your thoughts

Here is an example of three strings for blur filter. They illustrate the three most important translation contexts

i18nc(“@title:window”, “Blur Filter”)

Window titles are usually nouns (and translated as nouns). There is no limit on the size of the string.

i18nc(“@action:button”, “Apply Blur Filter”)

Button actions are usually verbs. The length of the string is also not very important.

i18nc(“@action:inmenu”, “Blur”)

Menu actions are also verbs, but the length of the string should be as short as possible.

3. Undo commands must have (qtundo-format) context

Adding this context tells the translators to use “Magic String” functionality. Such strings are special and are not reusable anywhere else.

In Krita and Calligra this context is now added automatically, because we use C++ type-checking mechanism to limit the strings passed to an undo command:

KUndo2Command(const KUndo2MagicString &text, KUndo2Command *parent);

4. Use capitalization properly

See KDE policy for details.

5. Beware of sticky strings

When the same string without a context is reused in different places (and especially in different files), doublecheck whether it is appropriate.

E.g. i18n("Duplicate") can be either a brush engine name (noun) or a menu action for cloning a layer (verb). Obviously enough not all the languages have the same form of a word for both verb and noun meanings. Such strings must be split by assigning them different contexts.

Alexander Potashev has created a special python script that can iterate through all the strings in a .po file and report all the sticky strings in a convenient format.

Conclusion

Of course all these rules are only recommendation. They all have exceptions and limitations, but following them in the most trivial cases will make the life of translators much easier.

In the next part of my notes from the sprint I will write how Boud and me were hunting down memory fragmentation problems in Krita on Sunday... :)

Saturday, July 5, 2014

Calligra Sprint 2014 has started!

Calligra Sprint 2014 has started! Today you have a unique chance to ask developers any questions about Calligra, Krita and Kexi on Twitter on a hash tag #AskCalligraDevs

Wednesday, June 18, 2014

Krita: "Edit Global Selection" feature

Our Kickstarter project is over 50% of the goal now! To say "Thank you!" to our supporters we decided to implement another small feature in Krita: editing of the global selection. Now you can view, transform, paint and do whatever you like on any global selection!

To activate the feature, just go to main menu and activate Selection->Show Global Selection Mask check box. Now you will see your global selection as a usual mask in the list of layers in the docker. Activate it and do whatever you want with it. You can use any Krita tool to achieve your goal: from trivial Brush tool to complex Transformation or Warp tool. When you are done, just deactivate the check box to save precious space of the Layers docker.

Add usual global selection

Deform with Warp Tool and paint with Brush Tool

This feature (as well as the Isolated Mode one) was a really low hanging fruit for us. It was possible to implement due to a huge refactoring we did in the selections area about two years ago, so adding it was only extending existing functionality. It is really a pity that the other features from the Kickstarter list cannot be implemented so easily :) Now I'm going to dig deep into the Vanishing Points and Transformations problem. Since Saturday I've been trying to struggle through the maths of it, but with limited success...

Next Windows and Krita Lime will have this feature included!

And don't forget to your friends about our Kickstarter!

https://www.kickstarter.com/projects/krita/krita-open-source-digital-painting-accelerate-deve




Monday, June 16, 2014

Krita team starts implementing features declared for the Kickstarter!

During the first week of our Kickstarter campaign we collected more than 6500 eur, which is about 43% of the goal. That is quite a good result, so we decided to start implementing the features right now, even though the campaign is not finished yet :)

I started to work on three low-hanging fruits in parallel: perspective transformation of the image basing on vanishing points, editing of the global selection and enhanced isolate layer mode.

It turned out that the vanishing point problem is not so "low-hanging" as I thought in the beginning, so right now I'm in the middle of my way of searching the math solution for it: to provide this functionality to the user the developer must find right perspective transformation matrix basing only on points in the two coordinate systems. This problem is inverse to what everyone is accustomed to solve at school :) This is quite interesting ans challenging task and I'm sure we will solve it soon!

Until I found the solution for maths task, I decided to work on small enhancements of our Isolate Layer mode. We have this feature already for a long time, but it was too complicated to use because the only way to activate it was to select "Isolate Layer" item in the right-click menu. Now this problem is gone! You can just press Alt key and click of the layer or mask in the Layers docker. This enables many great use cases for artists, which now can be done with a single Alt-click:
  • Show/Edit the contents of a single layer, without other layers interferring
  • Show/Edit the masks. This includes Selection Masks, so you can edit non-global selections very easily (modifying global selections will be simplified later)
  • Inspect all the layers you have by simply switching between them and looking into their contents in isolated environment

A comic page by Timothée Giet

There are several more things we are planning to do with the Isolated Mode like adding a bit of optimizations, but that is not for today :) 

The next packages in Krita Lime will include this new feature. They are now building at Launchpad and will be available tonight!

And don't forget to spread the word about our Kickstarter!

https://www.kickstarter.com/projects/krita/krita-open-source-digital-painting-accelerate-deve

Tuesday, June 10, 2014

Krita Lime is updated again!

It was about a month when we last updated Krita Lime. And it is not because we had leisure time and did nothing here ;) In reverse, we got so many features merged into master so it became a bit unstable for a short period of time. And now we fixed all the new problems so you can see a nice build of Krita with lots of shiny features!

Wacom Artpen rotation sensor improved

If you are a happy owner of a Wacom Artpen stylus, now you can use its rotation sensor efficiently: now it works on both Linux and Windows, and more, it works exactly the same way on both operating systems! For those who are not accustomed to work with drivers directly it might come as surprise, but the direction of rotation reported by the Windows and Linux drivers are opposite, not speaking about an offset by 180°. The good news: now it is gone! Just use it!

Avoid stains on the image when using touch-enabled Wacom device

The most popular advice you get from an experienced artist concerning Wacom touch-enabled usually sounds like: "disable touch right after connecting it". Well, it has some grounds... The problem is that the artist while painting with the stylus can easily tap on a tablet with a finger and soil the image with stains of paint. Yes, most of the taps will be filtered by the Wacom driver (it disables touch while stylus is in proximity), but sometimes it doesn't work. Anyway, now the problem is solved, though only on Linux.

Now Linux version of Krita has a special "hidden" configuration option called disableTouchOnCanvas. If you add line

disableTouchOnCanvas=true

to the beginning of your kritarc file, the touch will not disturb you with extra points on the canvas anymore! Though it will continue to work with UI elements as usual!

OpenColorIO-enabled color selectors for HDR images

This is a very huge and really nice feature, on which we were working hard. There will be a separate article about it soon! Just subscribe to us and wait a bit! ;)

Many small nice enhancements

  •  '[' and ']' shortcuts for changing image size now don't have hysteresis, and scale smoothly with the brush size
  • Zooming, Rotation and Mirroring now have a floating window showing the current state of the operation. This is highly necessary when working in full-screen mode or without the status bar shown.
  • Pseudo Infinite Canvas will not make your canvas too huge. It will grow the image by 100% and no more. Now you can use this feature for doubling any dimension of the canvas with a single click.
  • Added "Scalable Smoothing Distance" feature. When using Weighted Smoothing, the distance will be automatically corrected according to your zoom level, so the behavior of the stylus will not alter with changing the canvas zoom.
  • Made the handles of the Transform Tool easier to click on. Now clickable area is twice wider! Just click!

Kickstarter campaign

And yes, today we started our first donation campaign on Kickstarter! It will last for 30 days only, during which we are going to raise money for 2.9
release!

Direct link: http://www.krita.org/kickstarter.php

Help us, and together we will make Krita awesome!

Monday, June 2, 2014

Some notes from Krita Sprint 2014

Krita people in Deventer:
Sven, Lukas, Timothee and Steven
Almost two weeks have passed since we returned from the sprint, but we are now only beginning to sort out and formalize all the data and notes we did during the meeting. The point is, this time (as well as during the last sprint in 2011) we had three painters with us who gave us immeasurable amount of input about how they use Krita and what can be improved. This is the case when criticizing and complaining was exactly what we needed :)

So after having general discussions about Krita's roadmap on Saturday [0], we devoted Sunday on listening to painters. Wolthera, Steven and Timothée gave us short sessions during which they were painting their favorite characters and we could look at it and notice all the usecases and small inconveniences they face when working with Krita. The final list of our findings became rather long :), but it will surely have immense impact on our future. We saw not only wishes and bugs, we also had several revelations, the things which we could not even imagine before. Here is a brief list of them.

Tablet-only workflow

Yeah, not all the painters have a keyboard! ;) Sometimes a painter can use a tablet with built-in digitizer for painting. In such a case the workflow completely changes!
Two tool bars is too few! More floating toolbars!
  1. The painter may decide to reassigns the two stylus buttons to pan and zoom gestures since he has no access to a usual Spacebar shortcut.
  2. The toolbars! Yes, the toolbars are the precious space where the painter will put all the actions he needs. And there should be many configurable toolbars. The problem we have now is that there can be only one toolbar of a specific type and every action belongs to its own toolbar. The user should be able to create many general-case toolbars and put/group actions however he likes. I'm not sure this is possible to implement within current KDE framework, but we must investigate into it!
  3. Even when using a tablet some painters cheat a bit and use gaming keypads to access most needed actions, like pop-up palette, color picker and others. Steven came to Deventer with his Razer Nostromo device, and it seems he is quite convenient with it.
Razer Nostromo. Not for gaming :)

Revelations

Though it might sound funny, but some of Krita features really surprised me! I never knew we could use old-good tools this way.
  1. Experiment Brush. Have you ever thought that this brush might be an ideal tool for creation of shadows on a comic-look pictures? Well, it is ;)
  2. Group Layers + Inherit Alpha layer option. I could never imagine that Inherit Alpha feature can be combined with the Group Layers! If you use Inherit Alpha withing a group, then it'll use only the colors of this group! This can be used for filling/inking the parts of the final image. Just move it into a separate group, activate Inherit Alpha and you can easily fill/outline your part of the image!
  3. Color Picker. This is a trivial tool of course. But if you assign it to the second stylus' button, it becomes an efficient tool for mixing color right on the canvas! Paint, pick and mix colors as if you use a real-world brush.
Well, there were many other issues we found during the sessions. There were also some bugs, but the severity of those was really minor. Especially in comparison to the sessions we did in 2011, when David Revoy had to restart Krita several times due to crashes and problems... We did really much progress since Krita 2.4!

Yeah, it was a really nice and efficient sprint! Thanks Boudewijn and Irina for hosting the whole team in their house and KDE e.V. for making all this possible!


[0] - see Boud's report about it

Wednesday, April 9, 2014

Krita: Russian Translations Updated!

A picture by Georgiy Syptchenko
after a well-known series by David Revoy :)


Thanks to Georgiy Syptchenko from Krita Russian Community [0] Krita's translations into Russian got significantly improved recently!

We have already done three translation updates in Krita Lime repository and there are new changes yet to come!

So if you happen to speak Russian and want to help us with testing our translations, please follow this manual [1] and install updated translation packages!



[0] - http://vk.com/ilovefreeart
[1] - http://dimula73.blogspot.ru/2014/03/krita-lime-localization-support.html

Friday, March 28, 2014

Krita 2.9 (pre-alpha): Updated Fill Tool!


Preface

The Fill Tool was present in Krita since the ancient days. Its was first implemented back in 2004, and since then there were only minor changes to the algorithm it used. Now we are glad to announce a major update of it!

The old implementation used a, though a bit optimized, but still conventional, flood-fill algorithm that iterated through all the pixels recursively using a huge array as a map to store which pixels were visited and which not. It had two obvious drawbacks: it ate your memory (~100MiB for a map for an 10k x 10k image) and it was rather slow. The new algorithm is free from these disadvantages!

Scanline Flood Fill Algorithm

The new algorithm uses larger entities than just a single pixel. It uses "scanlines", which is effectively a chunk of a row of the image. The process of filling looks like a game. Several scanlines traveling throughout the image and checking or filling the pixel data. Each scanline can travel in either upward or downward direction. When two scanlines of opposite directions meet, they eat each other and both disappear! The process continues while there is at least one scanline alive :)

The rules for breeding and eating scanlines are a bit complicated, but they guarantee that not a single pixel will ever be visited twice! And that is without keeping any map of visited pixels, and therefore without oppressing your RAM! The experiments we conducted showed that to flood-fill an image of 10k by 10k pixels one would need only about 1MiB of memory! Just compare that to the 100MiB demanded by the conventional algo!

Real Performance Tests

The tests showed that the performance of the new Fill Tool greatly depends on whether the user needs some complex compositioning or not. That is why we introduced two new modes for the Fill Tool:
  • Advanced Mode — the mode supporting all the features of the tool, such as applying a selection, rendering the result with a user-supplied composite op, growing or feathering the selection area. This mode works about 1.4 times faster than the old implementation;

  • Fast Mode — just fill the area with color! No compositioning or selections are supported, but thanks to these limitations it is capable of up to 2 times better performance than the Advanced Mode. Which is almost 3 times faster that the old conventional algorithm!
And, of course, these speed benefits are nothing in comparison to the economy of memory we achieve!

Conclusion

The new Flood Fill algorithm is already present in Krita master and is available for all the users having Krita Lime [0] installed! Just update and have fun with your painting!

And yes, this work would be impossible without the support from Krita Foundation! Become a sponsor of the Krita Project and help us move the painting world further!

Monthly Donation through Paypal

Krita Development Funding

One-time donation through Paypal

 
[0] -  http://dimula73.blogspot.ru/2013/05/krita-lime-ppa-always-fresh-versions.html

PS:
Thanks Timothée Giet for a nice title image!

Thursday, March 27, 2014

Krita: new extended tablet support!

Traditionally Krita supported various types of tablets on Linux, but this support was limited to the tablets handled by wacom driver. The list of the supported hardware included (obviously) all the Wacom-branded tablets and some rare species that were trying to resemble the branded devices. It was the best that one could get form the Qt's tablet code. From now on Krita can also work with all the devices which are handled by the evdev X11 driver!



The list of the devices supported by evdev is really vast. It includes such not-very-expensive brands like Monoprice, Bosto, Huion and Genius. By the moment we tested Krita on two devices: Bosto 19MA [0] and Genius G-Pen 560. Both work fine with Krita and have really nice pressure support! Right now we are also working on support for the Huion tablet supplied by huiontablet.com to the Krita project as well!

Bosto kingtee 19MA now works with Krita!
So if you have a tablet device which used to refuse to work with Krita on Linux, test it now!

I also did a small cross-test of my old Wacom Graphire2 device and Genius G-Pen 560. What I noticed is that the lines generated by the Wacom tablet are more stable and smooth, whereas the lines by the Genius tablet are a bit dizzy. I don't know what is the exact reason for it, but I have a feeling that Wacom does some internal filtering of the coordinates generated by the hardware, which gives us better lines. Anyway, even if you own this Genius device, Krita allows you to workaround the issue. Just enable Weighted Smoothing painting algorithm and it will produce the results just like Wacom does!

And if you would like to know the technical details about why Qt's tablet code supports wacom-driver-based tablets only...

Qt's code doesn't fully support the interface of the XDeviceMotionEvent. Qt expects that the values of all six axes of the tablet will be sent to the client in each event. This is true for wacom driver, but it is not guaranteed to be true for other XInput devices. The motion event can also send the values that changed since the last event only. It even has special fields for that:

typedef struct
    {
    /* ... skipped ... */
    unsigned char axes_count;
    unsigned char first_axis;
    int           axis_data[6];
    } XDeviceMotionEvent;

axes_count field tells us how many axes are really delivered to the client and first_axis tells to what absolute axis the first element of axis_data corresponds to.

Now Krita can handle that effectively, as well as recognize to what sensor each axis is assigned to! [1]


[0] - https://groups.google.com/forum/#!topic/bosto-user-group/sL_O4VoopVk
[1] - unlike Gimp's way, where the user must manually investigate to which sensor each axis is connected to ;P

Monday, March 10, 2014

Krita Lime: Localization Support

After some time of really hard work we are happy to announce that our Krita Lime packages now support localization!

If you want to see Krita in your own language, just install a corresponding package...

apt-get install krita-testing-l10n-[your_language_id]

... and run Krita!

If you want to see Krita is a language that differs from your system one, type

KDE_LANG=[your_language_id] krita


Happy painting with Krita! :)

PS:
And for some languages the help of translators is really needed! Join our KDE translators team on l10n.kde.org and we will move KDE forward together! :)


Followers