Krita 4.1’s comic project management tools now support 90% of all ACBF features.
Missing are still: Transparent(text-area), Text-rotation, Jump, and Anchor.
Best of all, I managed to get most of the values understood semi automatically.
So, in August, I managed to get most of the meta data working for ACBF export. This was something that I was working on because I wanted to simplify the collection and writing of meta data for comics projects. Because meta data is something that accumulates over the course of a project, and the comic project management tools weren’t just there to manage pages, but also to give a place to collect all this meta data and then when finished to generate proper meta data files. So just let the computer handle all the boring stuff when it comes to that.
But, ACBF can handle a bit more than just mere meta data. It can also handle translations, panel definitions, and a bunch of meta data for those too.
Text came in quite late for the 4.0 release, for a variety of reasons, in fact, there was quite a lot of work on text even after the string freeze because it was just so fresh and late. I managed to add some super simple API for the vector shapes when doing the same for the layers, and then when I was poking at bugs in the tool, I realized this super simple API was just enough for me to add text(with formatting) and frames support for 4.0.
And that kinda opened the floodgates. Quickly after I ended up working in some fixes with the cover page(it apparently has a frame definition too), handling ACBF author properly, added keywords for marking a page as a title page or setting the page transition, made the frames not just use bounding boxes but try to have it approximate the actual shape, and supporting standalone ACBF files.
Then, after master opened for strings again, I got in the genre and author roles that were missing, implemented very simple genre match, made it possible to define authors properly, added the ability to define which layers should be searched for text, and realized it is really easy to write a POT file for translation. And not that hard to use a PO file to insert translations. And have the translation comments in the PO file be inserted into the references as a ‘translator’s note’. So did that.
Then I was sorta in the home stretch and I went ahead and implemented the style sheets, and have the ACBF exporter use the style sheets if possible to determine what type of text it is handling, whether said text is inverted, and whether it is emphasized or strong. Implemented background color recognition for the bgcolor attribute, and also made sure that preformatted text tries to approximate its bounding box too.
Also, finally implemented database reference field into the meta data dialog, even though it is probably not very applicable to ACBF files made with Krita.
The reason I was so intent on getting this done wasn’t so much because I want this to be the best ACBF exporter out there or something(because it isn’t), but rather because I want people to get a little spoiled.
I worry that with a format like ACBF, a lot of people who’d try to support it could be very inclined to say “well, I’ll support the meta data part, because there’s other meta data formats as well, so we can just reuse the code(and displaying meta data is pretty simple)”. So, if I make it super easy to generate these files with text and background color and translations and everything, to the point people might generate a full featured ACBF file almost by accident, then there will be more full featured files(coming from other people besides Róbert Pastierovič), then it will be less easy to say “Oh, we won’t support this, and it won’t matter because there’s only a handful of files that support it.” It should also be an encouragement for those who are supporting ACBF because that means people will notice the nice features they’re implementing.
Another thing is that I’ve tried making ACBF files from comics, but transcribing is super tedious, let alone then transcribing translations too, so automating things like these is welcome. As well, I was thinking of this type of pipeline that is used in game and VFX studios, and there the idea is ‘try to automate as much filters and toggles as you feasibly can’, so that if you’re running against a deadline, and you have to modify a base file somewhere that might have larger consequences. Then having something that is 99% automated and only requires you to tweak three things afterwards is a blessing. I wanted to provide that kind of luxury to people who’ll use the CPMT.
Though I imagine I may have come across as a possessed madwoman in the last few weeks.
So lets go over some of the elements and thoughts about them.
Text in ACBF is sorta based on docbook, with the semantic “strong” and “emphasis”, but it also contains formatting elements like “strikethrough” instead of the semantic “delete/del”, and “super” and “sub”. I don’t think you can really semantically capture the last two due their multitude of use cases.
Krita uses SVG 1.1 text at the moment, using SVG 1.1’s ability to describe a different position for any span of text. This is what we use for multiline text. We use text-anchor to define how the text aligns(though these are strictly different things), and we could technically use the textLength and lengthAdjust attributes to implement fake justified alignment, except there doesn’t seem to have been time to implement the use of textLength.
We can figure out emphasis and strong by checking the font-style and font-weight. ACBF has the ability to implement a simple CSS style sheet, where emphasis and strong can be defined, so we can also use these styles to check against. The style sheet is a little odd here, the spec seems to imply only font-weight and style can be set for these, but the official ACBF viewer also accepts font, as well, only bold and normal are accepted for font-weight, but not 400 and 700.
Strikethrough can be figured out by checking the text-decoration(and whether it is “line-through”). Super and sub script can be figured out from the baseline-shift attribute.
And then there’s anchor itself. Because Krita is a drawing program, if I give it an anchor it just goes ‘I don’t recognize this’ and throws it out. Therefore I cannot really implement links for websites and the like in the exporter. The exporter does use anchor when there’s a translator note, in which case it adds the anchor to the note in the text-area, and the note to the references section.
Text in ACBF can have types. These are also semantic. The default is speech, but there’s many others. The only one of these that isn’t really semantic and that is ‘code’.
Of these, two are recognizable by their default alignment: Formal and Commentary.
Formal is has it’s text alignment justified. Krita cannot currently actually write justified text of any kind, but the script can check for it, which it does. So it’s semi supported.
Commentary is the same thing as what we usually call a ‘caption’ in comics. It’s alignment according to the spec is right-aligned. Therefore the script will set both start and end(that’s the closest text-anchor gets to right and left alignment) aligned text to use Commentary.
For the last type of alignment, centered text(Middle for text-anchor), the exporter will check the font against the styles and pick the most closest. This requires users to actually configure the styles, but that doesn’t seem too complicated a task.
Outside of type there’s also inverted. Inverted indicates whether the text-area is in an inverted color. There is the ability to decide what text color the default text is and what text color the inverted text is in the style sheet, according to the spec. The CPMT can set these values, and will use them to determine whether a text is inverted by first calculating the luma value of the inverted and regular text. Then figuring out the average and use that as a threshold to figure out if the text color is inverted or not. This sort of works alright, but the problem is that the python ACBF viewer application doesn’t load colors from the style sheet, so if you set inverted color to black and regular color to white, the viewer will still show inverted as white and regular as black, making certain text invisible, so I am wondering whether I did that right…
The text area has a background color, and that one is figured out by sampling the points that create the text area, sorting the result and then determining if there’s a dominant color. If not, just mix everything together.
For this reason it’s kinda difficult to get the transparent attribute to work. I want to, in the future, see if I can add meta data to the vector shapes, make that readable from python and then implement keywords to indicate whether the text area is supposed to be transparent. This might also be useful for letting people force a text-type on a shape, or to let them force the order of the shapes, as the latter currently relies on z-index, which may be a bit difficult.
Text-rotation could not be implemented because the text shape SVG doesn’t give a transform matrix, so we need API for handling the transform matrix of a shape.
So, transcribing text is kinda a pain, and even copy-pasting over translations is painful, especially when you cannot read them. So I wanted to see how much of that could be automated.
Generating a POT file wasn’t very hard. It is a very simple file format. What was tricky though is that when you try to parse over SVG files and you pull out the text-content, preformatted SVG text looks kinda awful. Furthermore, different DOM APIs have different ways of writing the attributes, so one DOM API writes
<tspan x="0" dy="20pt"> while another writes
<tspan dy="20pt" x="0"> and this makes it rather hard to match translations. To the point where I just decided to strip the tags for matching.
All I can say is that I am waiting for the day Krita will have svg 2 wraparound text so the POT files will not be as intimidating. :p
When a POT file has been translated and a PO file has been created and put into the same folder, the exporter will search that folder for the PO files and tries to get the translations and puts those into the ACBF file automatically:
ACBF also has several meta data elements that can be translated. The title, annotation, keywords and bookmark titles. These are also written into the POT file with a context tag, so it’s easy to recognize them.
Getting translator’s comments out of a PO file is quite easy, so I quickly realized I wanted to support those getting exported to the ACBF file too. Even when I am translating one of my own dialogues and texts to English or Dutch, I notice I sometimes come across things I want to clarify, so hence I find this important. The feature needs to be toggled in the export, as maybe translators are being a bit too jargonny in their comments which may not be appropriate for publishing. There’s also a translator’s note header there than can be configured and will be translatable too. The header will be prepended to translation notes so that it’s obvious who wrote them.
I want to support proper author notes at some point too, but that will require shape meta data again.
Another reason I want to see wraparound is because right now, the text outline is determined from the tspans that make up each line. The ACBF viewer then adds a little bit of margin to this and calculates the maximum text size by itself, which means that for translations, the text becomes super-tiny in ACBF.
The work done for preformatted text isn’t useless though, as in the future there will still be situations where preformatted text will be used because of it’s flexibility, but I do wish things were a little easier.
Pages and Frames
Frames, or panels are gotten from vector layers marked as panels. It was relatively easy to decipher the SVG and then to generate a QPainterPath from that, which in turn can be used to make polygons which in turn can be used to describe the frames. It would be a little easier if I didn’t have to parse the SVG though, but that would require extra API again.
Frames don’t have their background color set, they just inherit it from the pages. This is because right now there’s no extra padding on frames, which means the boundaries will nearly always be on the frame outline. I might need to think of a way to add padding there. Similarly to text, frames could also use an order of appearance kind of tag because the z-index doesn’t always cut it.
Pages have their background color gotten from a sampling around the corners of the page.
Pages in ACBF have two extra properties: The transition type, and the title. A title is used to create a bookmark, so when you create an ACBF with multiple stories or chapters, these bookmarks can in turn be used for finding each story quickly. Pages in Krita are single KRA files, so to control these values I designated a couple of keywords that the exporter searches for in the keyword section of the page data.
acbf_title is the one that is necessary for designating a page as a bookmark. In this case the KRA file title will be used as the title of the bookmark. The title will also be scraped into the POT file for translation.
acbf_none, acbf_fade, acbf_blend, all set the page transition to their respective transition. acbf_vertical and acbf_horizontal respectively set the page transition to “scroll_down” and “scroll_right”. The latter one, much like the alignment on commentary is something I suspect is supposed to be reversed for languages that are read right to left, so hence the generic name.
There’s no Jump tags. Jumps are basically areas you can press to jump around the comic. This is interesting in, as the spec suggests “choose your own adventure”, but also for anthologies with detailed opening pages. This might possibly be resolved with vector shape meta data, and then have the keyword and a page-title defined, which then gets translated to a jump and the appropriate page number.
Another thing that is still missing is better handling of fonts within the style sheet. There’s two things that need to happen here:
- Letting the user define a list of fonts, ending in the fall-back generic font, or no fonts at all.
- Letting the user choose whether a font should be embedded. This one is necessary because embedding is something that is part of a font license, and there needs to be a way to inform the user of that without freaking them out. Also need to figure out how embedding fonts looks like in ACBF.
Outside of that, I got proficient enough with regexp to have simple genre match working. The idea of genre match is that you try to indicate whether something is primarily horror, or primarily romance. I implemented it with brackets, so something like…
Romance(80), Science Fiction(20)
will have Romance set to 80% and Science Fiction to 20%.
Romance (150), Horror(50)
Will normalize the values and have Romance set to 75% and Horror to 25%.
the final thing is that when you export to CBZ, a standalone ACBF file will be automatically generated next to it. Standalone files have the file type embedded as base64 strings, which wasn’t too difficult to do, though right now they are always stored as pngs as base64 strings. I also switched to use QDomDocument to write the files as python’s Elementree has no pretty printing(which is important because it makes the ACBF file less intimidating to edit afterwards with a given plain text editor), and minidom has a weird thing going on where it adds extra white space into textnodes, which is weird and unuseful(because the ACBF viewer interprets this white space too. The spec for that matter doesn’t say anything about how to treat whitespace).
Of course, while I have been going crazy with the exporter, other people have gone in and gone crazy elsewhere.
RagnarB, the author of the Gimp Book python plugin, has spent some time fixing little niggles left and right, but mostly spent some time on improving the page viewer.
The page viewer originally only showed the current page, but after his work it can flip through all pages of the comic in the correct order, and it can be run from the commandline, using the comicConfig.py as the basis, which is pretty cool. It will hopefully get merged soon.