Archive for June, 2010

Week 25: Photoshop brush support II

Monday, June 28th, 2010

Last week I worked on spray brush to make some room for Photoshop presets. This week I focused on abr format again.

I started with inspecting the Krita preset format. We save our presets as embedded text in PNG file. We use Qt for it, class QImageWriter is responsible for it. The preset is saved as XML. It used to be a text file, but Cyrille made it png file for few reasons. First was that the preset contains binary data – image of the preview stroke used in UI. Second reason is the performance. PNG compress the file nicely, huge amount of presets are loaded much faster at the Krita start-up compared to presets saved as XML files with binary data. Bonus is that you can see preview of the brush preset in Dolphin as the preset is image. Editing or viewing the XML became a problem. You can’t open the PNG in editor and change the XML of the preset easily. I needed to see the structure of the XML so I wrote easy viewer in few lines thanks to Qt. Reading the structure from Krita source code would be kill :)

Then I looked back at the ABR parser, python script written by Valek Filippov a.k.a. frob. Frob and Alexander Prokoudine did some work on Photoshop resources. I’m interested only in ABR brushes as it is part of our plan to support those. I ported Frob’s abr parser before, but there were some changes in the script lately. I tried to port them, but I don’t know if they were useful. The abr parser is becoming more general and contain some code that is useful for parsing other resources like Photoshop gradients. The structures used for saving binary data for Adobe resources share some ideas. The commit message to git repositary with changes was not very helpful – I found out this in chat with Frob.The parser is quite a hacky tool to discover what is in abr file. There isn’t specification available which would allow you to implement the abr brush. The whole parser is output of reverse engineering.

I decided to move to work on translator of the ABR brushes. Thanks to Alexander Prokoudine’s abr description I was able to start. I worked between the parser and translator for the rest of the week. I created new class that takes into account attribute, type and value parsed from abr as QString and then it put those values into classes. Every class has toXML method. That method specify how is the abr translated to our preset. It can create preset for Spray brush or Paint brush.

Let me show you how the abr looks like:

"Objc" "brushPreset 20"
"Nm  " "TEXT" "Hard Round 1 1 - shape dyn - rotation - all off/zero"
"Brsh" "Objc" "computedBrush 8"
"Dmtr" "UntF" "#Pxl 1"
"Hrdn" "UntF" "#Prc 100"
"Angl" "UntF" "#Ang 0"
"Rndn" "UntF" "#Prc 100"
"Spcn" "UntF" "#Prc 25"
"Intr" "bool" "1"
"flipX" "bool" "0"
"flipY" "bool" "0"
"useTipDynamics" "bool" "1"
"flipX" "bool" "0"
"flipY" "bool" "0"
"minimumDiameter" "UntF" "#Prc 0"
"minimumRoundness" "UntF" "#Prc 25"
"tiltScale" "UntF" "#Prc 200"
"szVr" "Objc" "brVr 3"
"bVTy" "long" "8"
"fStp" "long" "25"
"jitter" "UntF" "#Prc 0"
"angleDynamics" "Objc" "brVr 3"
"bVTy" "long" "0"
"fStp" "long" "25"
"jitter" "UntF" "#Prc 0"
"roundnessDynamics" "Objc" "brVr 3"

It was quite a lot of work to find out what does this mean and put all the structures together according what they mean. So far I managed to create preset only for computed brushes in Photoshop (ellipse-based), so the result produce something like this so far:

<Preset paintopid="paintbrush">
<param name="brush_definition">
<![CDATA[<Brush type="auto_brush" randomness="0" spacing="0.25" angle="0">
<MaskGenerator radius="0.5" ratio="1" type="circle" vfade="1" spikes="2" hfade="1"/>
</Brush>
]]></param>
</Preset>

It is not integrated into Krita yet. I have just class that translate the first brush parameters, I will add option to convert abr into set of kpp (Krita paintop presets). I would like to work further on translating Photoshop attributes into ours. It will require still a lot of work. Some features are missing and they need to be implemented, some parameters will be harder to map. E.g. abr structure contains image data and they are not parsed by Frob’s script so I will need to find a way how to connect the image data with presets. I ported some other abr parser which parses only brush masks – images. That’s already integrated in Krita. These two parsers will have to be merged somehow in the future.

Week 24: Photoshop brush support in Krita

Monday, June 21st, 2010

Thanks to the pledge we did long time ago and thanks to the community member, Silvio Grosso, who made major donation, I’m working on Krita for next ~12 weeks full-time.  The Krita community and me prepared Action Plan II. It’s something like Google Summer Of Code proposal but with much more targets. I have tasks per week, not one big target like Summer Of Code projects.

First two weeks of the plan are devoted to the support of the Photoshop brushes. I worked on it already in Action Plan I, I added support of the brush masks (bitmaps) from the file format, but there are still presets saved in the ABR format and we want to support them. The presets are for defining the brush rotation, roundness,  it’s dynamics like spreading in some area or some color stuff like HSV changes. I’m working on it right now.

First I thought that let’s create new brush engine that mimics the Photoshop one and then load the presets into this one. But that would be waste of time. We already have brush engines that have features like the Photoshop one, but they are scattered in our brushes engines – especially in Pixel Brush and in Spray brush. Cyrille pointed me to this fact.And other problem is that we need to unify the brush engines. Those I created are little divergent to the other brush engines, so I’m unifying.

First thing I had to do was to add support of our standard brush dialog to the spray. That way you can spray abr bitmaps because of preddefined brush dialog shows them and you can spray Auto Brush masks and even Text. Great, isn’t it? I spent few days with that. I fixed some bugs and now the standard dialog brushes are sprayed in the same way as the old limited shapes which were there before (pixel, anti-aliased pixel, ellipse, rectangle, brush bitmap – texture). This step is needed to support the abr presets.

New clouds with Krita are even better then the real things (U2)!

Made with Krita now: More realistic clouds

We also started to work on backward compatibility with our presets so I just could  not dropped old shapes and pixels because your presets would be broken.Working on backward compatibility is not very funny – but it’s important. It builds character as Boudewijn said.The backward compatibility works for spray presets, if you find bugs, contact me on IRC or fill a bug report.

Old clouds with sprayMade with Krita before: Comic clouds before

The old shapes are useful so you can still spray old not-softness-aware circles, ellipses etc. I wanted to merge those stuff into our standard brush dialog, but it turned out to be complicated. We have KisBrush class that units all the brush masks under one class. I was trying to turn my shapes into that one, but I would need more time to design it and implement it wisely. The outcome of this is some interesting discussion in the Krita mailing list about my idea of random shapes based on QPainterPath.

At the end of the week I spent some hours on something different than ABR brush for a while to rest from ABR. It’s basically UI thing for airbrushing.
We had Airbrush brush engine in Krita, but it was basically only copy of Pixel Brush with hardcoded option for incremental deliver. We dropped it due to spray brush which simulates the Airbrush much more better and then we want to have less brush engines with overlapping features, so it was wise decision to drop the Airbrush brush engine.

Airbrush as optionTurn your brush engine into airbrush mode

Every brush engine can act like “airbrush”, by delivering the brush mask when you do not move with your input device in the actual position. It’s done on the tool level – the free hand tool incrementally call paintAt at the same position in time interval specified by rate. So I moved the rate option from the tool to the brush engines GUI and now it is part of the UI and you can turn on/off airbrush option in the UI for brush engines which want to support “airbrush” mode. And even it can be part of the brush engine settings you can save, that was not possible before.

On the different topic, I spent nice weekend shortly before my final state exam in Brussels at the Libre Graphics Meeting. Thanks to the KDE e.V. for the sponsorship! You can watch my talk in some funny language slovakish-english about some brush engines I wrote for Krita . It was great event.  I met some cool guys like GIMP developers for the first time. I also teamed up with Martin maxy Reynolds, mypaint maintainer and core developer. Great event, nice place to talk about Krita and meet people in real-life.

What I realized at LGM:
1. Krita does not have many users. Most probably due to not releasing stable release for a long time. Distributions ships the stable ugly Krita 1.6.x. Let’s hope in change with Krita 2.3 which should be the first user-ready,  stable, awesome, great, unbelieveable release.
2. I don’t like the vegetarian food at all. Brussels chips fries FTW!

In my real life I graduated two weeks ago! I’m Ing. Lukáš Tvrdý now. I finished 5 years of university, it can be translated to Master Of Science. Weeeee. I’m now going to job interviews and writing cover letters. So far it’s fun.

I'm going to Akademy

I’m giving a talk at Akademy 2010 about Krita: what it was like to be GSoC student, community sponsored developer, talk about how we are doing in Krita community and I will show some results of my work in Krita. Be there ;)