Those who know me, or at the least know my history with Krita is that one of the prime things I personally want to use Krita for is making comics. So back in the day one of the things I did was make a big forum post discussing the different parts of making a comic and how different software solves it.
One of the things about making a comic is that is a project. Meaning, it is big and unwieldy, with multiple files and multiple disciplines. You need to be able to write, to draw, to ink, to color. And you need to be able to do this consistently.
The big thing I was missing in Krita was the ability to quickly get to my selection of pages. In real life, I can lay down pages next to one another, and always have them in my minds eye. In Krita, getting the next or previous page is always a matter of digging through folders and finding the correct page number.
Adding to this, I am also a bit of a perfectionist, so I have been training myself to start drawing scenes or writing as soon as I have an idea, because any idea is way more useful when you’ve got it down on page. You can append it to an existing story, or just work it in and reuse the drawings and compositions. And this was also a bit difficult to do, because how does one organise and tag those ideas?
So hence I spend the last few weeks on writing a comics manager for Krita.
Comics Project Management Tools
The comics manager, or more officially, the Comics Project Management Tools are a set of python scripts that form a plug in to Krita. They show up in the form of a docker.
Python scripting was recently added to Krita because people were willing to pay and vote for the stretchgoal in our previous kickstarter. It shines in this case as the majority of the tasks that needed to be done were storing simple information and showing GUI for editing that information. Being a developer for Krita on the C++ side also meant that making use of PyQt was very natural.
So, I made a docker in Krita. It starts with a “New project”.
Here, the most important part is making sure the artist only has to fill in the most vital information. That is… just the project name and the concept, actually. The location is asked before this window shows up.
The concept is basically a personal note, like “A comic about vampires fighting robots in a post-nuclear wasteland”, or “A scene where character A teaches character B how to ice skate.”
The project name, is actually sorta arbitrary. Usually any type of writer doesn’t know what to title their story until they’re halfway through, so the project name is intended to be more of a code name that is used to automate page naming. For that reason I also spent a day writing a “sophisticated” project name generator, of which most of the day was spent filling up the two lists the project name parts are pulled from.
Next to that are details like the language(which it attempts to guess by asking QLocale for the system language), and the names for the page, export and template folders. The metadata can also be filled in already, but again, not necessary. So basically, the only thing an artist struck with inspiration needs to do is press New Project, pick a location, press “generate” and then “Finish”.
After that, the CPMT will make a project folder(if that was checked), will check for, and if necessary, make folders for the pages, export and templates, and will serialise all the information you put in, into a comicConfig.json file.
Originally, this was a yaml file, but I discovered that there’s no yaml library in the python standard libraries, and I figured that the majority of our users would panic at the idea of having to install a python library on windows(Krita users are very sweet, but for a good majority of them, computers are magical mystery boxes that will explode when pressing the wrong button. As an more savvy computer user, I can of course, confirm that this is true, but there’s still a massive difference between knowing how to fix the magic mystery box when it goes wrong, and being helplessly subjected to its moodswings). Either way, I just wanted to have a config file that was somewhat easily readable by someone coming across it when clearing up their computer for space. This is also the purpose of the concept line, to answer the question: “What in the hell was I trying to do here?”
Creating a default template gives an over complicated window that will ask for a name, dpi, width and height, and the precise sizes of the margins and bleeds. The margins and bleeds are print terms.
When printing something, theoretically we…
- Take a large piece of paper.
- Align it to a printer
- Print several pages at once on that large piece.
- Cut the pages.
- Fold the pages
- and finally, bind the pages in some way or another.
Those steps above have many places where things can go wrong. In particular, the first things people started to learn when using mechanical printing was that aligning a text was difficult. So people introduced a margin to their text layout, so that even when it was slightly off, the whole text would still fit on the page.
The same thing goes for cutting, folding and binding. This is what the bleed is for. Sometimes, you want to have images that go all the way to the edge. So we create a second border, the bleeds, which indicate where the image will get cut off. The artist will paint over these too, but this method allows for determining where the absolutely important items, like the speech bubbles, go, as well as determining where the drawing doesn’t need to be super detailed, just nice enough to look right.
So the template creation tool allows you to set a margin and a bleed and will create a page with guidelines at those places. An experienced artist will likely have a collection of such templates already, so hence import template, which will copy the chosen template to the templates folder.
CPMT will remember the template chosen in for “Add page” and use that one to create pages with “Add Page” without showing the dialog. “Add page from template” will always show the dialog, as well as showing all the templates in the template folder, and the user can configure the default template for “Add page” in the project settings.
Originally, I had wanted to tell the user to select a page size, margin and bleeds in the project settings. However, those are a lot of things to fill in. Furthermore, there would also be need for a template for spreads(that’s a panel that covers two whole pages), as well as a template for the cover which is radically different to the regular pages. And these cannot be determined computer wise, because often there’s a little margin in the middle or extra bleed to either side for such templates and this can be unique per printing company. And that doesn’t even begin to cover situations where you are not making a print-style comic.
So I thought about this for a long time and decided that the most important thing would be a way 1) make images from template kra files and 2) make one of those templates a default template, easy to add with a single button, while still allowing for adding the others in a simple manner.
So, once you press ok, or add page with a default template, it will open the template, and resave it in the pages folder with projectname-firstavailablenumber.kra and show it in the pages list.
The Pages List
The pages list is probably the core element of the comics project management tool. On a technical level is a QTable view with a QStandardItem model, which in the first column shows a list of QStandard items with the page “preview.png”(thumbnail) as the icon and the page title as the text, and on the second column, the image subject as the text.
For the user, it is a list of pages, with their icon and title/filename on the first column, and the description on the second. The pages can be rearrange by moving the row selector on the right, and the config will then update the way the pages are arranged. Double clicking the page title will open the file in Krita.
Originally, I wanted the description to be editable from the docker, and was almost succesful, except that the python ZipFile library has no mechanism for overwriting/deleting files from a existing ziparchive, so I couldn’t only edit the documentinfo.xml. This is a bit of a pity, as editing the description from the docker was very convenient for the half hour that it did work. Now the user has to go to the document info to fill in either the subject or description. I want to keep this kind of information inside the image as that allows for moving the image around irrespective of project, so storing the information in the config file isn’t an option.
This is also why the templates are stored inside the comics project, so that when moving to a new computer, the whole project should still work. I went through a lot of trouble to ensure that all the paths are relative, and right now this is also where all the code probably should be a little cleaner
Anyway, the pages list allows reordering pages, accessing pages quickly, removing pages from the list(but not from disk, too dangerous), and adding existing pages. This is all stored in the config, and thus also loaded from it.
Originally, the loading was done by opening the file in Krita, requesting the thumbnail, and a title, but that could take up to a minute. Now, I get ZipFile to open the kra file(which is a zip), load the “preview.png” into a QImage, parse the “documentinfo.xml” with Elementree and get out the title and subject/abstract for showing that information. A part of me is wondering if I should allow a simple docker that just shows the “mergedimage.png” inside a given kra file for reference.
So the pages list is the most important element, but there are of course other elements, the second of which is the meta data.
As indicated in the setup section, writers usually don’t know the initial title of their work, and in general it isn’t too wise to force them to go through all the meta data information at the start. On a similar note, it is often hard to figure out what kind of meta data should go into a given field, and anyone who has attempted to read the actual specs of meta data standards knows that the people making these specs are insane and completely incapable of adding real world examples to their specs.
Personally, I also know that when I am writing, I slowly collect a selection of summaries/titles/keywords that should be going into the metadata, so hence I figured it might be useful to create a organised place to put them.
So, what does comics metadata look like?
Starting with that, what do comics formats look like? As digital distribution is a pretty new thing, and comics in general are a bit slow with providing these things, most comic readers use a guerilla format that probably got created somewhere around the nineties/early 2000. It is basically an archive with images inside, ordered and read alphabetically.
I say it was created around that time because there’s like 4 variations of the format. The simplest is CBZ, which is a zip archive with images. Then there’s CBR, which is a rar archive with the images, because around the early 2000 the rar archive was obviously so much better at compressing than zip files. Similarly, there’s CB7, which is of course, a 7-zip archive with images. And of course, Linux nuts came up with CBT, a tar archive with images.
As you can tell, none of these have obvious meta-data schemes. Luckily for us, a guerrilla format has guerrilla attempts at creating metadata. No less that 5 different schemes can be found on the internet.
- ComicInfo.xml (https://wiki.mobileread.com/wiki/ComicRack) is a file that is added by the windows comic managing software “Comic Rack”. It has no proper specification, but is apparently common enough to be considered relevant.
- CoMet.xml (http://www.denvog.com/comet/) is one of the attempts at making an official spec. I haven’t figured out if it is actually common.
- ComicBookInfo (https://code.google.com/archive/p/comicbookinfo/wikis/Example.wiki) which unlike the other three is a json file stuck into the zip info. The logic being that this is easier to read than those nasty xml files. For the computer that is, I don’t think most people realise there’s such a thing as a zipfile header and that it can have information in there. Anyway, the spec seems to have been devoured by googlecode’s passing, leaving us only with this lone example file. But at the least it has an example file.
- Comic Book Markup Language(http://dcl.slis.indiana.edu/cbml/) This… is some academic attempt at making comics machine readable. It says it has a spec. It doesn’t. It instead decides upon two extra tags for something or another spec, but that other spec isn’t really a spec either.
- ACBF (http://acbf.wikia.com/wiki/Advanced_Comic_Book_Format_Wiki) or Advanced Comic Book Format is an open source attempt at making a slightly more advanced markup similar to CBML, but unlike CBML it actually has a spec and examples, even if all of that is on a combo of a wikia/launchpad site that is on one hand full of more scripts you can shake a stick at(wikia.com) and on the other a extremely difficult to navigate website(launchpad). None the less, there’s two readers that can read it(sorta). One is ACBF viewer, a pyGTK based application, and the other is Peruse. Well, Peruse master. Peruse from the KDE neon repository takes your cbz with acbf meta-data just fine… and then shows nothing. It is fixed in master, apparantly.
So, for the purpose of writing a meta-data editor, we first look at the things these guys have in common. Except CBML because that has no spec as far as I am concerned.
All of them have a title. The title is the title of a work. It’s pretty uncontroversial. Even dublin core calls the title of a work “title”, and it is a sentence.
All of them also have… a description. You know whatever is on the back of the book to entice you to read it. In the English language, we have the following words to talk about this piece of text:
- Synopsis (Yes really, often book publishers ask authors for a synopsis, that is the whole plot in a paragraph, so they can determine whether it is worth publishing the book, and often this same synopsis is chucked on the back-cover, leading to many books where the back-cover spoils the whole story.)
And from this you can gather that this is where many meta-data schemes get confusing:
ACBF stores this in the “Annotation” element. ComicRack in the “Summary” element, CoMet in the “Description” element, and ComicBookInfo in the “Comments” element. Dublin Core uses the “Description” element for this.
But still, it is relatively uncontroversial. Just give someone a text area, like QPlainTextEdit, and let them type in something.
Language is a QComboBox with entries pulled from a csv having the ISO languages and their codes and defaults to the system locale. Reading direction has to be seperate from language because sometimes you have people writing comics in the opposite direction of their language. Still, it is a combobox that is set to default to the system language reading direction.
Of the four metadata schemes, CoMet and ComicRack define reading direction, but only CoMet calls it by its name, while ComicRack calls it “Manga”. I am not sure what ACBF intends here. CoMet is also a bit annoying that out of the four schemes it is the only one that requests the proper language name instead of the ISO language code.
Then there’s the smaller meta-data, like the Genre. All of the specs have genre listed as a seperate “Genre” element that can occur several times. Dublin Core has no such element, so it goes into “Subject” instead. ACBF is unique in that it allows a limited list here. ACBF also allows noting percentages, but that got me complicated too quickly.
So, because there’s multiple entries, one would think, QLineEdit, with comma separation. Because we cannot use a QComboBox, that doesn’t allow for multiple entries at once. I also didn’t really want to use checkboxes because that doesn’t allow what people feel the genre of their work is. For example, a horror writer differentiates between psychological horror and gothic horror, while a fantasy writer differentiates between urban fantasy, swords and sorcery, epic fantasy, etc.
So to give people an indication of which types are acceptable, I set up a QCompleter on the QLineEdit. The metadata editor checks on initialisation the folder key_genre for txt files, and uses each line as a stringlist entry, which then goes into the QCompleter. However, QCompleter doesn’t handle comma seperated entries by itself. Thankfully, many people on the internet had been attempting to make a QLineEdit with comma separated autocompletion, so I was able to cobble something together from that. This way the artist can type in entries, be encouraged to pick certain entries. When exporting we can then check if the entries don’t match and chuck those into the keywords list.
I rather liked this approach, as it helps people, but because the data is pulled from outside the code, from a simple format, they can also extend it.
So I decided to reuse it for Characters, Format and Keywords as well.
Characters is also near universal. It probably is inspired by the big overarching universes in American comics. The ComicBookInfo json just puts it in “tags” but is a it unique in that. ACBF has a list characters with name elements for each character. CoMet and ComicRack have reoccuring “Character” tags.
Format shows up in both ComicRack and CoMet. I have no idea what the former means by it, and am equally confused by the description of the latter. I suspect it means a format-genre. Either way, it is not Dublin Core format, which means “physical format”.
All of them have a place for extra keywords, which I am thankful for.
Then there’s series, volume and issue. ACBF calls series a “sequence” but otherwise there’s not much confusion here. Just a QLineEdit and two QSpinBoxes with Vol. and No. as prefixes.
Then there’s the content rating. Originally I had this as a line edit that pulled from a text-file as well, but as I realised different rating systems use the same letter to mean slightly different things, I decided to switch over to a CSVs for this. The first row for the title of the rating system, and after that, the first column is the letter, and the second column the description.
The CSVs results into two comboboxes, the first of which gives the type, and the second the letter. By using the combobox’ model we can put the description as a tool tip to the letter. The comboboxes are both editable for the person who has no idea they can add their own ratings systems but still wishes to rate differently.
Next up is the author. So typically an author is written down like “John Doe”, but for archiving purposes, it is usually written like “Doe, John”. Furthermore, in comics there often multiple creators credited. The latter is most common in American comics, where there’s a separate Writer, Penciller, Inker, Colorist, and Letterer, and often the Editor is also credited. In European comics this is usually just a “Scenario” and “Artist”, and in Manga it is one or two authors, and an army of assistants, but the latter are never credited and one wouldn’t know they existed unless they read the author’s ramblings in the volume bound releases.
All of the specs have spaces to refer to authors. They of course, do this in wildly different manners.
ComicRack has seperate elements for “Writer”, “Penciller”, “Inker”, “Letterer”, “Colorist”, “CoverArtist”, “Editor” and “Translator”. CoMet is similar, except it calls “CoverArtist” “coverDesigner”. ComicBookInfo and ACBF both instead use a tag to refer to an author and then assign a role to them. ComicBookInfo calls them “Person” and ACBF makes an author element and says only specific roles are valid. The Dublin Core specifies Creator and Contributor tags, which can be refined with a meta tag.
Of these, ACBF is unique in that it actually bothers to seperate the different parts of a name as well as allow nicknames and contact info.
So… how to make a gui element for that? At this point I had gotten comfortable enough with QT model/view programming that I just made a QTableView with a QStandardModel item and having columns for Nickname/First Name/Middle Name/Last Name/Role/Email/Homepage. For the role, because many of them ask for a limited list, I subclassed QStyledItemDelegate just enough to give a line edit with a QCompleter that takes it’s autocompletion entries from the txts in the key_author_roles folder. Like with the page list, people can add authors, remove authors, and rearrange authors. By default, it has an entry for John “Anonymous” Doe, which seemed a sensible default that would demonstrate the gui, but the first feedback I got was from someone who was not familiar with the meaning of the name “John Doe”, so I am a wee bit worried about translation.
I still want to add buttons to optionally scrape the pages list for authors, as well as the ability to generate a text object in the current open file with the credits nicely outlined.
Then, the final part of the meta data is the publishing meta-data.
All of the schemes have some place to put the Publisher Name and the Publishing Date. ACBF also allows for City, and I am a little confused why the others don’t.
The date is a little bit more confusing. ComicRack and ComicBookInfo require a separate publish year, CoMet an ISO date and ACBF requires any kind of date, with the ability to specify an ISO date explicitely. QDate and QDate input to the rescue here.
Then, there’s ISBN. ACBF only accepts ISBN, and CoMet allows for an ISBN or some unique publishing number. The other two don’t have anything.
Then there’s the license. Like the content rating, I am pulling this from a CSV with some examples, and like the content rating, I have it editable and default to have nothing in it. My reasoning here is that for example, we could have a teenager making a fancomic, and I think it would kind of suck if they got bothered because their fancomic has a license defined.
Either way, of the four schemes, ACBF asks for a license, but no rights holder, CoMet only a rightsholder and no license, ComicBookInfo and ComicRack don’t ask for anything. Dublin Core says that the “Rights” tag should contain anything pertaining the license and rightsholder. I am not quite sure how to help people here either how.
And that is all the meta data. So, the idea is that the author just types in some things, and then later comes back and types in more. And eventually, somewhere over the course of the project it has a proper meta-data definition.
So, I have been discussing these four metadata formats, does that mean I intend to export to them? Yes.
So, there’s a big fancy export button on the comics management docker. Pressing it does nothing, unless you have set up the export. On the other hand, after you have set up the export, pressing the button is the only thing that needs to be done.
The exporter right now can export to three formats. The first is CBZ, with all 4 metadatas acceptable. The second is EPUB, which uses Dublin core metadata. Finally there’s ‘TIFF’ which is not really an export format so much as a intermediary format for publishing programs like Scribus. While Epub and CBZ need to be in 8bit srgb/grayscale, tiff can handle multiple colorspaces and high bitdepths.
Each of them has a resize menu, which can resize by width, height, percentage or DPI. These options were necessary because it otherwise is too difficult to determine how to handle different sized documents sensibly. (Someone who uses spreads doesn’t want to resize by height, and someone working on a by-panel basis instead of per-page would prefer DPI or percentage resize). For similar reasons the crop menu allows you to select “crop to outmost guides” and pixels, so that it is easy to define a per-image cropping mechanism.
The exporter also allows removing layers by color label, which is useful to make sure layers sketch layers or commentaries are removed.
The exporter exports everything to the export folder, both packaged and unpackaged, so that it is easy to get to the right elements and adjust them.
So that is quite easy, you set it up, and then press the export button whenever you feel like making a result cbz or epub that can be read from ACBF viewer or other readers.
There’s still metadata menaces here. I got pretty confused with the ACBF spec here as it asks for a ‘unique identifier for cataloguing purposes’ and I have no idea what that means. Note that it doesn’t say “universial unique id”, nor does it specify what kind of ID this ought to be, and none of the existing ACBF files have anything like it(despite the spec saying it is mandatory), so I decided to just make a QLineEdit and then someone else can figure it out.
For EPUB… anyone who has attempted to read that spec knows it is overcomplicated(and yet still easier that CBML). So I just opened Sigil, made an EPUB that sorta looked like I wanted it to and then reproduced that EPUB in detail. This still took me a full day, so let alone if I had actually tried to read the spec.
So, I wanted a docker to organise and access my comics pages. I ended up with a docker that can support a full-on production process(theoretically).
What is next?
I already noted here and there that there’s elements I want to improve. On top of those, I also want to…
- make it possible for people to select a folder with additional meta-data auto-completion keys.
- when vector python api is in, allow people to specify the name of a layer that has the panel data, so this can be stored into ACBF.
- when the text works and is in the python api also give ACBF export the text layers.
- General GUI clean up. There’s parts of the editor that are a bit messy.
- Improve the EPUB look.
- Improve the other metadata.
- Fix bugs… like reordering pages doesn’t actually work >_>
- Krita has gained an beautiful plethora of bugs with saving/loading via python thanks to async saving being implemented, so those bugs need to be catalogued and put onto bugzilla and fixed.
But for now, I am gonna take a break. I also poked someone to do some testing for me, and I might poke some more people for testing, and then fix some bugs. And then worry about python scripting translation support. Maybe then merge.
Something like that at the least.