GSoC/2019/StatusReports/Albertoefg: Difference between revisions
Albertoefg (talk | contribs) No edit summary |
Albertoefg (talk | contribs) No edit summary |
||
(9 intermediate revisions by the same user not shown) | |||
Line 2: | Line 2: | ||
=== Summary === | === Summary === | ||
* Project Name: Animated Vector Brush for Krita | * '''Project Name''': Animated Vector Brush for Krita | ||
* Proposal: Google Docs Proposal | * '''Proposal''': [https://docs.google.com/document/d/1SwIBNFthJ5Qg3N7DBgzMKMrW-rn5hB_NPxuf8EuMr2w/edit#heading=h.banhzxz4dibc Google Docs Proposal] | ||
* Abstract: This projects aims to implement an Animated Vector Brush for Krita, which uses SVG as a source file for the brush tips. The purpose of an animated brush is to change the brush tips automatically with every dab on the canvas. This allows for a quick way to paint different images, create random and fun designs, and explore new ways to paint that are not easy in physical world. In the other hand, using SVG as a source makes it easy to share the brush tips as they are saved as plain text, as opposed to raster image brushes. | * '''Related blog''': [https://albertoefg.info/blog/kde.html albertoefg.info] | ||
* '''Abstract''': This projects aims to implement an Animated Vector Brush for Krita, which uses SVG as a source file for the brush tips. The purpose of an animated brush is to change the brush tips automatically with every dab on the canvas. This allows for a quick way to paint different images, create random and fun designs, and explore new ways to paint that are not easy in physical world. In the other hand, using SVG as a source makes it easy to share the brush tips as they are saved as plain text, as opposed to raster image brushes. | |||
=== Project Goals === | === Project Goals === | ||
Line 17: | Line 18: | ||
* Write a helper class to populate the VectorAnimatedBrush class | * Write a helper class to populate the VectorAnimatedBrush class | ||
* Change brush tip with every dab | * Change brush tip with every dab | ||
=== Project related links === | === Project related links === | ||
Line 37: | Line 37: | ||
=== Load AVB === | === Load AVB === | ||
* '''Goal''': The Animated Vector Brush file should be loaded and call the proper | * '''Goal''': The Animated Vector Brush file should be loaded and call the proper class, in this case <code>KisVectorAnimatedBrush</code>. | ||
* '''Status''': The implementation is done, the loading of the AVB by the user is using the +import tab. | * '''Status''': The implementation is done, the loading of the AVB by the user is using the <code>+import</code> tab. | ||
* '''Related blog post''': [https://albertoefg.info/blog/2019/06/2019-06-09-my_first_two_weeks.html#org54db47c My first two weeks on Google Summer of Code] | * '''Related blog post''': [https://albertoefg.info/blog/2019/06/2019-06-09-my_first_two_weeks.html#org54db47c My first two weeks on Google Summer of Code] | ||
==== Commits and Differentials ==== | ==== Commits and Differentials ==== | ||
Line 44: | Line 44: | ||
** [https://invent.kde.org/albertofl/krita/commit/bd654077f29b2f50cdb0ea9c93766a57295bbdb1 bd654077: Added vectorAnimatedBrush to brush server] | ** [https://invent.kde.org/albertofl/krita/commit/bd654077f29b2f50cdb0ea9c93766a57295bbdb1 bd654077: Added vectorAnimatedBrush to brush server] | ||
** [https://invent.kde.org/albertofl/krita/commit/ddee5b98b3aacf2cbed764f3c650167243e17a29 ddee5b98: Load Vector Animated Brush] | ** [https://invent.kde.org/albertofl/krita/commit/ddee5b98b3aacf2cbed764f3c650167243e17a29 ddee5b98: Load Vector Animated Brush] | ||
** [https://invent.kde.org/albertofl/krita/commit/d1afdb4053d237b123424db07bc837951d008bbe d1afdb40: Return false for empty SVG] | |||
=== Parse SVG === | === Parse SVG === | ||
* '''Goal''': The SVG should be parsed and transformed to KoShape as necessary, so Krita can use them to set | * '''Goal''': The SVG should be parsed and transformed to <code>KoShape</code> as necessary, so Krita can use them to set <code>brushTipImage</code>, paint dabs or change the size of the brush tip. | ||
* '''Status''': Done. | * '''Status''': Done. | ||
* '''Related blog post''': [https://albertoefg.info/blog/2019/06/2019-06-23-the_last_two_weeks_on_krita.html Basic functionality almost ready] | * '''Related blog post''': [https://albertoefg.info/blog/2019/06/2019-06-23-the_last_two_weeks_on_krita.html Basic functionality almost ready] | ||
Line 55: | Line 57: | ||
=== Render brush tips as images === | === Render brush tips as images === | ||
* '''Goal''': The KoShapes should be transformed to QImage as necessary, so Krita can use them to set | * '''Goal''': The <code>KoShapes</code> should be transformed to <code>QImage</code> as necessary, so Krita can use them to set <code>brushTipImage</code>, paint dabs or change the size of the brush tip. | ||
* '''Status''': Done. | * '''Status''': Done. | ||
* '''Related blog post''': [https://albertoefg.info/blog/2019/06/2019-06-23-the_last_two_weeks_on_krita.html Basic functionality almost ready] | * '''Related blog post''': [https://albertoefg.info/blog/2019/06/2019-06-23-the_last_two_weeks_on_krita.html Basic functionality almost ready] | ||
Line 65: | Line 67: | ||
=== Write a parasite class to hold the index === | === Write a parasite class to hold the index === | ||
* '''Goal''': Write a parasite class that will aid | * '''Goal''': Write a parasite class that will aid <code>KisVectorAnimatedBrush</code> class, holding the values of the Index and related data. | ||
* '''Status''': In Progress. Although the majority of the class works now, there is a need for comments and cleaning. It can also be extended to add more functionality like different types of sequences: tilt, velocity, etc. | * '''Status''': In Progress. Although the majority of the class works now, there is a need for comments and cleaning. It can also be extended to add more functionality like different types of sequences: tilt, velocity, etc. | ||
* Related blog post: [https://albertoefg.info/blog/2019/07/implementing_a_derivated_class_of_kis_brushes_pipe.html Implementing a derivated class of kis_brushes_pipe] | * Related blog post: [https://albertoefg.info/blog/2019/07/implementing_a_derivated_class_of_kis_brushes_pipe.html Implementing a derivated class of kis_brushes_pipe] | ||
Line 72: | Line 74: | ||
** [https://invent.kde.org/albertofl/krita/commit/065ac9ba9ce8c037f8ffeedb0ce4081bf4716bcf 065ac9ba: Added a parasite helper class] | ** [https://invent.kde.org/albertofl/krita/commit/065ac9ba9ce8c037f8ffeedb0ce4081bf4716bcf 065ac9ba: Added a parasite helper class] | ||
** [https://invent.kde.org/albertofl/krita/commit/4d3fbd9b40260b21f138e6df30495fe0c6b3c4f3 4d3fbd9b: Fix the segmentation fault] | ** [https://invent.kde.org/albertofl/krita/commit/4d3fbd9b40260b21f138e6df30495fe0c6b3c4f3 4d3fbd9b: Fix the segmentation fault] | ||
=== Write a KisVectorAnimatedBrush class === | === Write a KisVectorAnimatedBrush class === | ||
* '''Goal''': Write a the class | * '''Goal''': Write a the class <code>KisVectorAnimatedBrush</code> that will inherit from <code>KisBrushesPipe</code> to work as a brush pipe of <code>VectorShapeObject</code> brushes, it will also have a <code>Private</code> struct to hold a <code>KisVectorHelperPipe</code> object. | ||
* '''Status''': In Progress. The class is mostly done, however it can be extended to get more functionality. | * '''Status''': In Progress. The class is mostly done, however it can be extended to get more functionality. | ||
* '''Related blog post''': | * '''Related blog post''': | ||
** [https://albertoefg.info/blog/2019/07/implementing_a_derivated_class_of_kis_brushes_pipe.html Implementing a derivated class of kis_brushes_pipe] | |||
** [https://albertoefg.info/blog/2019/08/krita_sprint_news.html Krita Sprint News] | |||
** [https://albertoefg.info/blog/2019/08/building-a-vector-animated-brush.html Building a Vector Animated Brush] | |||
==== Commits and Differentials ==== | ==== Commits and Differentials ==== | ||
* [https://phabricator.kde.org/T10930 Phabricator T10930] | * [https://phabricator.kde.org/T10930 Phabricator T10930] | ||
** [https://invent.kde.org/albertofl/krita/commit/ddee5b98b3aacf2cbed764f3c650167243e17a29 ddee5b98: Load Vector Animated Brush] | ** [https://invent.kde.org/albertofl/krita/commit/ddee5b98b3aacf2cbed764f3c650167243e17a29 ddee5b98: Load Vector Animated Brush] | ||
** [https://invent.kde.org/albertofl/krita/commit/058756d2f898127d4751bbda1b40a758e7233e3e 058756d2: Intitalize Private struct to hold KisVectorHelperPipe object] | ** [https://invent.kde.org/albertofl/krita/commit/058756d2f898127d4751bbda1b40a758e7233e3e 058756d2: Intitalize Private struct to hold KisVectorHelperPipe object] | ||
** [https://invent.kde.org/albertofl/krita/commit/7536541236ed90d376252d77c9ea5058f7aa1992 75365412: Use paintDevice to render brush ] | |||
** [https://invent.kde.org/albertofl/krita/commit/bbd5667e219e055ddf4a80803c16a845888045d2 bbd5667e: Add destructor for Private object] | |||
=== Write a VectorShapeObject class === | === Write a VectorShapeObject class === | ||
* '''Goal''': Write a class that will work as a single brush that will hold a single | * '''Goal''': Write a class that will work as a single brush that will hold a single <code>KoShape</code> and a single <code>QImage</code>. A series of objects of this class will populate the <code>VectorAnimatedBrush</code> class, using the <code>KisVectorHelperPipe</code> class. | ||
* '''Status''': Done. | * '''Status''': Done. | ||
* '''Related blog post''': | * '''Related blog post''': [https://albertoefg.info/blog/2019/08/krita_sprint_news.html Krita Sprint News] | ||
==== Commits and Differentials ==== | ==== Commits and Differentials ==== | ||
* [https://phabricator.kde.org/T10930 Phabricator T10930] | * [https://phabricator.kde.org/T10930 Phabricator T10930] | ||
** [https://invent.kde.org/albertofl/krita/commit/eae68aa720867cc0c94a54caca7abf2b474a2d67 eae68aa7: Add KisVectorHelperPipe Class] | ** [https://invent.kde.org/albertofl/krita/commit/eae68aa720867cc0c94a54caca7abf2b474a2d67 eae68aa7: Add KisVectorHelperPipe Class] ''Note: This class was added in the same commit as the helper pipe class.'' | ||
** [https://invent.kde.org/albertofl/krita/commit/0b2ef645ce666c0173a0805ca31cb6034ef74620 0b2ef645: Inherit from KisScalingsizebrush in KisVectorShapeObject] | |||
** [https://invent.kde.org/albertofl/krita/commit/ebdd8f8c384b1c6a30fa9d0eee1037a5da93e80e ebdd8f8c: Convert brushTip to MaskImage] | |||
** [https://invent.kde.org/albertofl/krita/commit/9e6ee54775c2e06d723f43b1d37e3741b9ce72bd 9e6ee547: Add appropriate brushType] | |||
** [https://invent.kde.org/albertofl/krita/commit/058756d2f898127d4751bbda1b40a758e7233e3e 058756d2: Intitalize Private struct to hold KisVectorHelperPipe object ] | |||
=== Write a Helper Pipe class to populate the KisVectorAnimatedBrush === | === Write a Helper Pipe class to populate the KisVectorAnimatedBrush === | ||
* '''Goal''': Write a helper class for | * '''Goal''': Write a helper class for <code>KisVectorAnimatedBrush</code> that will aid holding a parasite object of the class written earlier, and populate the pipe brush with <code>VectorShapeObject</code> brushes. | ||
* '''Status''': Done. | * '''Status''': Done. | ||
* '''Related blog post''': | * '''Related blog post''': [https://albertoefg.info/blog/2019/08/krita_sprint_news.html Krita Sprint News] | ||
==== Commits and Differentials ==== | ==== Commits and Differentials ==== | ||
* [https://phabricator.kde.org/T10930 Phabricator T10930] | * [https://phabricator.kde.org/T10930 Phabricator T10930] | ||
** [https://invent.kde.org/albertofl/krita/commit/eae68aa720867cc0c94a54caca7abf2b474a2d67 eae68aa7: Add KisVectorHelperPipe Class] | ** [https://invent.kde.org/albertofl/krita/commit/eae68aa720867cc0c94a54caca7abf2b474a2d67 eae68aa7: Add KisVectorHelperPipe Class] | ||
** [https://invent.kde.org/albertofl/krita/commit/30c2f3c9f2c2b11c27cb296a3e7b093f3670e7bc 30c2f3c9: Populate brushesPipe with VectorShapeObjects] | |||
=== Change brush tip with every dab === | === Change brush tip with every dab === | ||
* '''Goal''': Change the | * '''Goal''': Change the <code>brushTipimage</code> with every dab | ||
* '''Status''': | * '''Status''': Done. | ||
* '''Related blog post''': | * '''Related blog post''': [https://albertoefg.info/blog/2019/08/building-a-vector-animated-brush.html Building a Vector Animated Brush] | ||
==== Commits and Differentials ==== | ==== Commits and Differentials ==== | ||
* [https://phabricator.kde.org/T10930 Phabricator T10930] | * [https://phabricator.kde.org/T10930 Phabricator T10930] | ||
** [https://invent.kde.org/albertofl/krita/commit/2ed1c1d5acd7e5098a85f4948893ff52cfd52ac9 2ed1c1d5: Fix iteration of shapesToimages] | ** [https://invent.kde.org/albertofl/krita/commit/2ed1c1d5acd7e5098a85f4948893ff52cfd52ac9 2ed1c1d5: Fix iteration of shapesToimages] | ||
** [https://invent.kde.org/albertofl/krita/commit/cda1fd56f6c6d4cb2b05fcd98b1e4d084a9561eb cda1fd56: Use chooseNextBrush to update the Index] | |||
** [https://invent.kde.org/albertofl/krita/commit/e8248790db65b8f1280f30242041b035822182a3 e8248790: Use KisVectorHelperPipe for the Index] | |||
== All Commits == | |||
** [https://invent.kde.org/albertofl/docs-krita-org/commit/e9dbd91fff1754ad6fc9e215d9bd16ee5a43116f e9dbd91f: Added Tutorial for Animated Vector Brushes.] | |||
** [https://invent.kde.org/albertofl/docs-krita-org/commit/378b759a4c849f3c3feb50c2000920f9a7e63a3a 378b759a: Added small description for AVB] | |||
** [https://invent.kde.org/albertofl/docs-krita-org/commit/1aa98e85589b0786b2b8e67d64513272663d99bb 1aa98e85: Created documentation for avb] | |||
** [https://invent.kde.org/albertofl/krita/commit/bd654077f29b2f50cdb0ea9c93766a57295bbdb1 bd654077: Added vectorAnimatedBrush to brush server] | |||
** [https://invent.kde.org/albertofl/krita/commit/ddee5b98b3aacf2cbed764f3c650167243e17a29 ddee5b98: Load Vector Animated Brush] | |||
** [https://invent.kde.org/albertofl/krita/commit/d1afdb4053d237b123424db07bc837951d008bbe d1afdb40: Return false for empty SVG] | |||
** [https://invent.kde.org/albertofl/krita/commit/7ed4b9c13c86c4b1b3347528c739cd733c163354 7ed4b9c1: Use SvgParser to loadFromDevice] | |||
** [https://invent.kde.org/albertofl/krita/commit/cffe647e8064117fb7ab70c9147ec0ad67c48120 cffe647e: Set brushTipImage from the KoShapePainter] | |||
** [https://invent.kde.org/albertofl/krita/commit/b024e4fb08ce78d438a0f9b081ad1a1dc3d0c548 b024e4fb: Render QImages only once] | |||
** [https://invent.kde.org/albertofl/krita/commit/065ac9ba9ce8c037f8ffeedb0ce4081bf4716bcf 065ac9ba: Added a parasite helper class] | |||
** [https://invent.kde.org/albertofl/krita/commit/4d3fbd9b40260b21f138e6df30495fe0c6b3c4f3 4d3fbd9b: Fix the segmentation fault] | |||
** [https://invent.kde.org/albertofl/krita/commit/058756d2f898127d4751bbda1b40a758e7233e3e 058756d2: Intitalize Private struct to hold KisVectorHelperPipe object] | |||
** [https://invent.kde.org/albertofl/krita/commit/7536541236ed90d376252d77c9ea5058f7aa1992 75365412: Use paintDevice to render brush ] | |||
** [https://invent.kde.org/albertofl/krita/commit/bbd5667e219e055ddf4a80803c16a845888045d2 bbd5667e: Add destructor for Private object] | |||
** [https://invent.kde.org/albertofl/krita/commit/0b2ef645ce666c0173a0805ca31cb6034ef74620 0b2ef645: Inherit from KisScalingsizebrush in KisVectorShapeObject] | |||
** [https://invent.kde.org/albertofl/krita/commit/ebdd8f8c384b1c6a30fa9d0eee1037a5da93e80e ebdd8f8c: Convert brushTip to MaskImage] | |||
** [https://invent.kde.org/albertofl/krita/commit/9e6ee54775c2e06d723f43b1d37e3741b9ce72bd 9e6ee547: Add appropriate brushType] | |||
** [https://invent.kde.org/albertofl/krita/commit/eae68aa720867cc0c94a54caca7abf2b474a2d67 eae68aa7: Add KisVectorHelperPipe Class] | |||
** [https://invent.kde.org/albertofl/krita/commit/30c2f3c9f2c2b11c27cb296a3e7b093f3670e7bc 30c2f3c9: Populate brushesPipe with VectorShapeObjects] | |||
** [https://invent.kde.org/albertofl/krita/commit/2ed1c1d5acd7e5098a85f4948893ff52cfd52ac9 2ed1c1d5: Fix iteration of shapesToimages] | |||
** [https://invent.kde.org/albertofl/krita/commit/cda1fd56f6c6d4cb2b05fcd98b1e4d084a9561eb cda1fd56: Use chooseNextBrush to update the Index] | |||
** [https://invent.kde.org/albertofl/krita/commit/e8248790db65b8f1280f30242041b035822182a3 e8248790: Use KisVectorHelperPipe for the Index] | |||
== Chronicle == | |||
=== Community Bonding Period === | |||
During this period of the Google Summer of Code I tried to contribute to Krita in different ways, including helping users on IRC and Reddit, and also improving the Krita documentation. | |||
The biggest amount of work I did was to contribute with the ''Selections Tools'' section of the manual, as suggested by Wolthera van Hövell. This helped me to understand better how to write documentation, how to use git and gitlab, and how to work with an Open Source project. My work was merged right before the Google Summer of Code started. | |||
[https://invent.kde.org/websites/docs-krita-org/merge_requests/4#note_5561 Link to the closed merge request] | |||
=== First two weeks === | |||
During this period I wrote the documentation for my brush. I don't have experience with writing real world software, but I've read it is always a good idea to start writing the end user documentation, this way there is a clear path on what to achieve at the end of the project. | |||
I also read the specification on [https://www.w3.org/TR/SVG11/ Scalable Vector Graphics (SVG) 1.1], because I wanted to know as much as I could about the <code><symbol></code> and <code><use></code> elements. Upon reading this with more detail, I realized it would be a bad idea to use <code><symbol></code> for this type of brushes. | |||
This is because <q>‘symbol’ elements are never rendered directly; their only usage is as something that can be referenced using the ‘use’ element.</q> Using a <code><symbol></code> would imply that the users have a broken workflow when it comes to editing the brush tips, because they won't be able to edit the brush in the Krita canvas, as the canvas should not show <code><symbol></code> elements only <code><use></code> elements. And changing this behavior would be against the SVG specification. | |||
Because of this, I asked for permission to change the original design of the brush, to use the <code><g></code> element instead. This would bring a number of benefits: 1) the brush tips could be open, edited and saved in the Krita canvas; 2) the brush tips could be parsed using the <code>SvgParser</code> from the Flake library. 3) It would simplify the user workflow. | |||
=== Second and Third weeks === | |||
During this period I worked on implementing the base class for my brush and to have the basic functionality, this includes: Opening an AVB with the <code>+import</code> tab, parse the XML from the SVG to be a <code>QList</code> of <code>KoShapes</code>, adding the mimetype of <code>.avb</code> to Krita; during this period I didn't have much trouble with Object Oriented Programming as the majority of the work was using functions and implementing the simple things, not touching classes much. | |||
=== Fourth and Fifth weeks === | |||
This was a harder time, I started to work with classes and to implement the index that will change with every dab, changing the images accordingly. This was the first time I really had to understand the way OOP, and C++ works, it wasn't an easy time for me. I tried to implement a class that inherited from <code>KisBrushesPipe</code>, however I was not successful, but I had some small achievements, I started to understand how a brush pipe should work on Krita, what basic functionality I needed and how to achieve this. During this period my mentor started to work with me closer, to make sure I understood everything and were not completely lost. | |||
=== Sixth and Seventh weeks === | |||
This was a period of darkness, although my mentor was really helpful and patient with me. I started to read more of the Krita codebase, specially to look at how KisBrushesPipe and KisImagePipeBrush work, it was really hard, a lot of the functionality was not obvious to me and there was no easy way to understand it. | |||
My mentor guided me by telling me to work on a single class and not look at those classes for the moment, that way I could start to improve my brush in a simple way, this was a good advice. I stopped trying to implement those things and slowly worked on built a more humble thing. Here is a point where I did my biggest mistake, I didn't write tests. I was feeling really confused and had a lot of new things to understand and work with, and the unit tests only added to the complexity, so I tried to focus on learning more about the work I was doing before adding another layer of complexity to my code. | |||
=== Eight and Ninth weeks === | |||
Finally out of the darkness. During this period thanks to the help of my mentor I started to work slowly to improve my brush, to understand more and more of the code of Krita and to implement more functionality. | |||
This weeks were also the ones when the Krita Sprint happened, so I got to talk to my mentor directly, we did a lot of progress, when the Krita Sprint ended my project had a lot of new classes and functionality. I was able to read the code of <code>KisImagepipebrush</code> and have a much clear idea of what was happening and why. | |||
Unfortunately this wasn't all a victory, I did a huge amount of progress and this two weeks were probably the ones were I learned the most about programming, but I also didn't produce as good code as I wish I could, there were was a lot of code I needed to clean, I still needed to write unit testing and have lots of things to improve. But overall I am quite proud of how much I learned and improved. | |||
=== Conclusion === | |||
Overall the whole I am proud of all the learning and work I did. It has been one of the greatest experiences to learn and collaborate with such an amazing project as Krita, to meet all the team during the Krita Sprint and to realize how much more I can do to help. | |||
I still have a lot to improve my project. Fortunately the end of the Google Summer of Code does not mean the end of my collaboration with Krita, which I hope will last for years to come and I feel proud to be a member of this community. | |||
I have to admit my project is not yet ready to be part of Krita. There are still things to do, it is necessary to clean the code, to add more comments, and to add more tests. But thanks to the progress of the last few weeks I am confident it won't be that long before my brush can become part of Krita. | |||
=== The future === | |||
Talking to my mentor and some other Krita developers, I was suggested to read more programming books, one of them being "Design Patterns: Elements of Reusable Object-Oriented Software". I plan to read this book to learn more and be able to produce better code for Krita. | |||
I was also suggested by Tiar to start writing and small program that would reset the configuration of Krita, to help non-technical users, [https://phabricator.kde.org/T11427 as suggested by this phabricator task]. | |||
Of course I want to keep improving my brush to take it to the next level, adding new features and options that were beyond the scope of the Google Summer of Code period and my coding abilities. | |||
[[File:Possible future User Interface.png|thumb|center]] | |||
Latest revision as of 03:11, 26 August 2019
Krita: Animated Vector Brush
Summary
- Project Name: Animated Vector Brush for Krita
- Proposal: Google Docs Proposal
- Related blog: albertoefg.info
- Abstract: This projects aims to implement an Animated Vector Brush for Krita, which uses SVG as a source file for the brush tips. The purpose of an animated brush is to change the brush tips automatically with every dab on the canvas. This allows for a quick way to paint different images, create random and fun designs, and explore new ways to paint that are not easy in physical world. In the other hand, using SVG as a source makes it easy to share the brush tips as they are saved as plain text, as opposed to raster image brushes.
Project Goals
- Write documentation for end users as per the Krita Contribution Guide.
- Define the structure of the SVG file containing the source tips for the Animated Vector Brush
- Load AVB
- Parse SVG
- Render brush tips as images
- Write a parasite class to hold the index
- Write a VectorAnimatedBrush class
- Write a VectorShapeObject class
- Write a helper class to populate the VectorAnimatedBrush class
- Change brush tip with every dab
- Phabricator https://phabricator.kde.org/T10930
- Personal Blog https://albertoefg.info/blog/kde.html
Implementations Status
Write documentation
- Goal: The documentation should be written for end users as per the Krita Contribution Guide, it should also be sufficient for the users to understand and use the brush.
- Status: The documentation is mostly done, it is only necessary to add the proper screenshots and update in case of changes.
- TODO: Add screenshots.
- Related blog post: My first two weeks on Google Summer of Code
Commits and Differentials
Load AVB
- Goal: The Animated Vector Brush file should be loaded and call the proper class, in this case
KisVectorAnimatedBrush
. - Status: The implementation is done, the loading of the AVB by the user is using the
+import
tab. - Related blog post: My first two weeks on Google Summer of Code
Commits and Differentials
Parse SVG
- Goal: The SVG should be parsed and transformed to
KoShape
as necessary, so Krita can use them to setbrushTipImage
, paint dabs or change the size of the brush tip. - Status: Done.
- Related blog post: Basic functionality almost ready
Commits and Differentials
Render brush tips as images
- Goal: The
KoShapes
should be transformed toQImage
as necessary, so Krita can use them to setbrushTipImage
, paint dabs or change the size of the brush tip. - Status: Done.
- Related blog post: Basic functionality almost ready
Commits and Differentials
Write a parasite class to hold the index
- Goal: Write a parasite class that will aid
KisVectorAnimatedBrush
class, holding the values of the Index and related data. - Status: In Progress. Although the majority of the class works now, there is a need for comments and cleaning. It can also be extended to add more functionality like different types of sequences: tilt, velocity, etc.
- Related blog post: Implementing a derivated class of kis_brushes_pipe
Commits and Differentials
Write a KisVectorAnimatedBrush class
- Goal: Write a the class
KisVectorAnimatedBrush
that will inherit fromKisBrushesPipe
to work as a brush pipe ofVectorShapeObject
brushes, it will also have aPrivate
struct to hold aKisVectorHelperPipe
object. - Status: In Progress. The class is mostly done, however it can be extended to get more functionality.
- Related blog post:
Commits and Differentials
Write a VectorShapeObject class
- Goal: Write a class that will work as a single brush that will hold a single
KoShape
and a singleQImage
. A series of objects of this class will populate theVectorAnimatedBrush
class, using theKisVectorHelperPipe
class. - Status: Done.
- Related blog post: Krita Sprint News
Commits and Differentials
- Phabricator T10930
- eae68aa7: Add KisVectorHelperPipe Class Note: This class was added in the same commit as the helper pipe class.
- 0b2ef645: Inherit from KisScalingsizebrush in KisVectorShapeObject
- ebdd8f8c: Convert brushTip to MaskImage
- 9e6ee547: Add appropriate brushType
- 058756d2: Intitalize Private struct to hold KisVectorHelperPipe object
Write a Helper Pipe class to populate the KisVectorAnimatedBrush
- Goal: Write a helper class for
KisVectorAnimatedBrush
that will aid holding a parasite object of the class written earlier, and populate the pipe brush withVectorShapeObject
brushes. - Status: Done.
- Related blog post: Krita Sprint News
Commits and Differentials
Change brush tip with every dab
- Goal: Change the
brushTipimage
with every dab - Status: Done.
- Related blog post: Building a Vector Animated Brush
Commits and Differentials
All Commits
- bd654077: Added vectorAnimatedBrush to brush server
- ddee5b98: Load Vector Animated Brush
- d1afdb40: Return false for empty SVG
- 7ed4b9c1: Use SvgParser to loadFromDevice
- cffe647e: Set brushTipImage from the KoShapePainter
- b024e4fb: Render QImages only once
- 065ac9ba: Added a parasite helper class
- 4d3fbd9b: Fix the segmentation fault
- 058756d2: Intitalize Private struct to hold KisVectorHelperPipe object
- 75365412: Use paintDevice to render brush
- bbd5667e: Add destructor for Private object
- 0b2ef645: Inherit from KisScalingsizebrush in KisVectorShapeObject
- ebdd8f8c: Convert brushTip to MaskImage
- 9e6ee547: Add appropriate brushType
- eae68aa7: Add KisVectorHelperPipe Class
- 30c2f3c9: Populate brushesPipe with VectorShapeObjects
- 2ed1c1d5: Fix iteration of shapesToimages
- cda1fd56: Use chooseNextBrush to update the Index
- e8248790: Use KisVectorHelperPipe for the Index
Chronicle
Community Bonding Period
During this period of the Google Summer of Code I tried to contribute to Krita in different ways, including helping users on IRC and Reddit, and also improving the Krita documentation.
The biggest amount of work I did was to contribute with the Selections Tools section of the manual, as suggested by Wolthera van Hövell. This helped me to understand better how to write documentation, how to use git and gitlab, and how to work with an Open Source project. My work was merged right before the Google Summer of Code started. Link to the closed merge request
First two weeks
During this period I wrote the documentation for my brush. I don't have experience with writing real world software, but I've read it is always a good idea to start writing the end user documentation, this way there is a clear path on what to achieve at the end of the project.
I also read the specification on Scalable Vector Graphics (SVG) 1.1, because I wanted to know as much as I could about the <symbol>
and <use>
elements. Upon reading this with more detail, I realized it would be a bad idea to use <symbol>
for this type of brushes.
This is because ‘symbol’ elements are never rendered directly; their only usage is as something that can be referenced using the ‘use’ element.
Using a <symbol>
would imply that the users have a broken workflow when it comes to editing the brush tips, because they won't be able to edit the brush in the Krita canvas, as the canvas should not show <symbol>
elements only <use>
elements. And changing this behavior would be against the SVG specification.
Because of this, I asked for permission to change the original design of the brush, to use the <g>
element instead. This would bring a number of benefits: 1) the brush tips could be open, edited and saved in the Krita canvas; 2) the brush tips could be parsed using the SvgParser
from the Flake library. 3) It would simplify the user workflow.
Second and Third weeks
During this period I worked on implementing the base class for my brush and to have the basic functionality, this includes: Opening an AVB with the +import
tab, parse the XML from the SVG to be a QList
of KoShapes
, adding the mimetype of .avb
to Krita; during this period I didn't have much trouble with Object Oriented Programming as the majority of the work was using functions and implementing the simple things, not touching classes much.
Fourth and Fifth weeks
This was a harder time, I started to work with classes and to implement the index that will change with every dab, changing the images accordingly. This was the first time I really had to understand the way OOP, and C++ works, it wasn't an easy time for me. I tried to implement a class that inherited from KisBrushesPipe
, however I was not successful, but I had some small achievements, I started to understand how a brush pipe should work on Krita, what basic functionality I needed and how to achieve this. During this period my mentor started to work with me closer, to make sure I understood everything and were not completely lost.
Sixth and Seventh weeks
This was a period of darkness, although my mentor was really helpful and patient with me. I started to read more of the Krita codebase, specially to look at how KisBrushesPipe and KisImagePipeBrush work, it was really hard, a lot of the functionality was not obvious to me and there was no easy way to understand it.
My mentor guided me by telling me to work on a single class and not look at those classes for the moment, that way I could start to improve my brush in a simple way, this was a good advice. I stopped trying to implement those things and slowly worked on built a more humble thing. Here is a point where I did my biggest mistake, I didn't write tests. I was feeling really confused and had a lot of new things to understand and work with, and the unit tests only added to the complexity, so I tried to focus on learning more about the work I was doing before adding another layer of complexity to my code.
Eight and Ninth weeks
Finally out of the darkness. During this period thanks to the help of my mentor I started to work slowly to improve my brush, to understand more and more of the code of Krita and to implement more functionality.
This weeks were also the ones when the Krita Sprint happened, so I got to talk to my mentor directly, we did a lot of progress, when the Krita Sprint ended my project had a lot of new classes and functionality. I was able to read the code of KisImagepipebrush
and have a much clear idea of what was happening and why.
Unfortunately this wasn't all a victory, I did a huge amount of progress and this two weeks were probably the ones were I learned the most about programming, but I also didn't produce as good code as I wish I could, there were was a lot of code I needed to clean, I still needed to write unit testing and have lots of things to improve. But overall I am quite proud of how much I learned and improved.
Conclusion
Overall the whole I am proud of all the learning and work I did. It has been one of the greatest experiences to learn and collaborate with such an amazing project as Krita, to meet all the team during the Krita Sprint and to realize how much more I can do to help.
I still have a lot to improve my project. Fortunately the end of the Google Summer of Code does not mean the end of my collaboration with Krita, which I hope will last for years to come and I feel proud to be a member of this community.
I have to admit my project is not yet ready to be part of Krita. There are still things to do, it is necessary to clean the code, to add more comments, and to add more tests. But thanks to the progress of the last few weeks I am confident it won't be that long before my brush can become part of Krita.
The future
Talking to my mentor and some other Krita developers, I was suggested to read more programming books, one of them being "Design Patterns: Elements of Reusable Object-Oriented Software". I plan to read this book to learn more and be able to produce better code for Krita.
I was also suggested by Tiar to start writing and small program that would reset the configuration of Krita, to help non-technical users, as suggested by this phabricator task.
Of course I want to keep improving my brush to take it to the next level, adding new features and options that were beyond the scope of the Google Summer of Code period and my coding abilities.