Sunday, March 24, 2024

Fonts Across the Libre Desktop: Design and Graphics Focus

Today, each application, and each toolkit, offers font selection. But fonts have become gradualy more complex, and none of the interfaces seem really excellent. None of the libre graphics programs support the range of font features avaiable in newer or more “mainstream” commercial software such as Photoshop or Figma. It’s not a race, we dont have to copy other software, but the additional complexity of fonts, and OpenType in particular, was added to meet real needs that we can’t easily serve today.

Desktop packaging systems were not designed for packaging individual fonts (and users end up searching 100,000 packages without previews).

We could improve things one program at a time (I originally wanted to start with GIMP) but that leaves the user frustrated.

We could improve one toolkit at a time, such as Gtk or Qt.

Or we could make a desktop-wide service that any toolkit could use, and that’s client-agnostic, so people could write multiple font tools. That way, we could maybe pool our knowledge, too.

This proposal is to see how far we can plausibly take the idea of a desktop font service for font management, selection, configuration, searching. Perhaps the service could sit on top of dbus, with a font client being started automatically by the desktop (dbus is cross-platform).

Sunday, January 8, 2023

GEGL Plug-Ins for GIMP. Part Three: Writing C Plug-Ins

GEGL Plug-Ins for GIMP. Part Three: Writing C Plug-Ins

This is the third in a series of articles about GEGL plug-ins for the GIMP image editor. See also part one and part two for more about GEGL plug-ins and using them from inside GIMP.

You don’t need to know C to use this article, or be a programmer.

Note: you can also use GEGL plug-ins outside of GIMP, e.g. in the gegl command-line program and maybe even in GNOME-Photos, unless you use GIMP-specific features such as calling other GEGL operations that GIMP provides.

Why do it?

GEGL Plug-ins are super easy to use in GIMP with on-canvas preview, and you can even save and load settings. They are in the C programming language and are nice and fast, sometimes taking advantage of your graphics card or multi-threading.

Although you can write scripts for GIMP in Python, Schema, JavaScript, Lua, and maybe more languages, those scripts don’t get a preview at all, or just get a tiny one in a  pop-up window.

GEGL plug-ins can also be used as part of more complex GEGL graphs, like building blocks.

How hard is it?

Someone who hasn’t written any C before and isn’t a programmer can translate the GEGL Chain syntax shown in part two into C, with a little practice. You may need help from a C programmer if you get errors or get stuck. This article mentions some of the common errors, though.

Allow about an hour to turn a GEGL chain into a C plug-in the first time, and about another hour to get it to compile if you haven't done that before.

Monday, December 12, 2022

GEGL Plug-Ins for GIMP. Part Two: GEGL Graph

In Part One of this article we looked at running GEGL plug-ins as live filters, using the GEGL Operation dialogue. GEGL plug-ins are super cool and have live on-canvas preview. Now in Part Two we’ll take it to the next level and look at the more powerful GEGL Graph GIMP plug-in.

Saturday, October 29, 2022

GEGL Plug-Ins for GIMP. Part One: Using GEGL Plug-Ins

If you don’t know about GEGL plug-ins for GIMP, you’ve been missing out. There’s not many of them, but that’s changing with more people writing them. And they offer flexibility and power you didn’t know GIMP had. 

This three-part article first shows some of the gegl plug-ins that are available, and how to get them going (it’s easy, don’t worry)

Then, in part two, we’ll look at the GEGL Graph plug-in you can use as a way to make your own super-powerful filters.

Finally, we build up to writing a simple GEGL plug-in in C, written for people without a maths or programming background.

Monday, December 7, 2020

CSS Within XSLT - a way to simplify simple HTML generation from XSLT

It can be a challenge to keep CSS files up to date as you change XSLT transformations to produce different HTML output. You've got to remember what you changed and then work out which CSS rules are affected and update them. Removing out-of-date rules is important, and can even affect your site’s ranking in search results, but it’s hard to do and requires attention to detail.

Recently I’ve been taking a different approach and I’m finding it much more productive.

Friday, March 8, 2019

Happy Birthday, World Wide Web

On W3C, The Web, Information

The great dragon Obrfynar climbed the side of the mountain; reaching the podium, she turned to face the audience. There was polite applause, curtailed because everyone wanted to listen. She was, after all, one of the most famous dragons on the conference circuit. Mountain birds flew hastily away in case she cleared her throat, but she just took a drink of sheep’s blood from the glass on the podium and began to speak.
“We are Dragon-kind! All look to us in awe! We are the mightiest! And from the beginning of time we have known what we want, what we need, what we must have, what we will have! And what is it?”
There was a predictable roar from the crowd. Any birds foolish enough to be watching had long fled or were roasted in the excitement. The roar said one word:


We must seek gold. Wherever it is, we must find it and hoard it!”

Saturday, October 6, 2018

Layered Fonts with CSS and JavaScript

The established ways of using layered fonts on the Web all have problems, so I tried to come up with something new.

Layered fonts are typefaces designed to be overprinted, so that you get a colour effect. Here's an example from Tom Chalky’s Rivina font family:

If you look closely at the word “Chapter” you can see the letters are blue with a greyish outline. I've magnified some of it in the inset circle. The way this works is that there are two separate fonts: TC Outline just draws the outer edges of the font and TC Fill draws the inside of the letters; the text is repeated at the same location, once in each font, to create the effect.

More complex fonts can include many more “layers” than the two I’ve used here (and in fact Rivina includes more variants than I’ve shown).

This technique was invented in the 19th century and has been used in every medium to make a simple coloured printing of headlines.

To use fonts like this on the Web and not be ashamed of ourselves we need: ...

Thursday, December 3, 2015

Declarative Index Proposal for Printing with CSS

This proposal is about formatting an index with HTML and CSS. It’s something you can’t do today in a standard, cross-implementation way.

The part you can’t do today is getting the lists of page numbers right. The same problem occurs in an index and in cross references. There are vendor extensions to do it, but they are not compatible, so it’s a good candidate for standardization.

A back of the book index looks like this:

Friday, December 26, 2014

Christmas 1976 (give or take a bit)

When I was seven , back in 1970, my father took a new placement as Vicar at the village of Haynes, in Bedfordshire. We went to look at the house in Winter; I was so cold that my mother put plastic bags over my socks, inside my shoes, to try and warm me up. I don’t remember whether it worked very well, but at any rate later that year we moved into the vast, crumbling old vicarage in Haynes Church End.

I hope Terry Stevens won’t mind me using his photograph of the vicarage and the church:

At holidays, and especially at Christmas, the family would descend. One year we had fifteen people to Christmas Lunch, most of them stayed for at least a week. We didn’t have enough bedrooms: there were people on sofas and couches, and others staying at nearby Hawnes School (later Clarendon School) or with Henry and Penrose Green or another neighbour.

That was the year the water in the toilets froze: the crumbling mansion had what I called “central heating” consisting of a total of three radiators for the entire house, placed in hallways as a sort of mockery of actual heating. My older brother Robert took away the cast iron Victorian fireplace from the front room to reveal the sixteenth century brick and stone fireplace behind it; at least after that we could have a roaring log fire in that room as well as the smaller coal fire in the living room. The fires did not, however, heat the whole house, and rubber hot water bottles were used at bedtime. Grandma made sure we knew about it the next morning when the pee in her chamber pot froze.

Christmas for so many people was tempting fate a little too much, and the ’fridge broke down. The repair man kindly came out to the vicarage—it turns out that a lot of people will go an extra mile to a vicarage, possibly as a sort of spiritual insurance plan—and told us that the problem was the ’fridge wouldn’t work when it was colder in the kitchen than the temperature to which we had set the ’fridge.  Which was fine except that it meant the freezer part of the ’fridge also didn’t work!

We also had a year when the turkey wouldn’t fit in the oven, and another when the oven actually went wrong; the village came to the rescue and on each occasion the turkey was roasted in the ovens at the village hall (or possibly the “mission hall”), a couple of miles away.

Another year there were power cuts, and we cooked the food on a gas camping stove in the kitchen. We hadn’t heard about carbon monoxide poisoning but I suspect the house was so drafty that we were perfectly safe. There were two-inch gaps between the two halves of the sash windows in places.

Mum hated cooking at the best of times; a lot of that came from an incident early on in my parents’ marriage: we’re shaped not only by genetics but also by experience. At the worst of times, cooking for fifteen adults and five under-fives, Mum never really complained, at least as long as everyone pitched in and helped. But in retrospect part of that was because she wanted everyone to be happy at Christmas, so she summoned extra strength.

The house was large enough that you could always get away from people; there would be a room with television and a room with people playing parlour games or sitting and reading or chatting. Of course, the rooms could be fairly full. When Grandma had to go to the toilet she made sure to make her way to the door slowly, leaning heavily on each person’s knees in turn as if she could hardly walk. The illusion didn’t last: when she got out of the room you could hear her footsteps speed up.

Christmas day also had a church service in the morning (distressingly close to the Christmas Eve midnight service the night before!), and, after lunch, the ritual opening of the obscenely large pile of presents under the artificial flame-resistant   tree. Yes, artificial, because, long before I was born, Robert came home with a candle they’d made at school and, dancing proudly, fell over. The village (St. Ippollits then, and no-one there can spell Saint Ippolytts either; even the street signs were all different) helped out with new presents and a replacement tree from the primary school, but ever after the tree had to be artificial.

No presents were opened until the dishes were all done and everything was clean and tidy. And afterwards was a walk.

People stayed for several days after Christmas, and lived off cold pheasant and turkey and after that turkey soup. We always had a brace of pheasant from the local farmer, Tom Davies at Home Farm, and we always loved them. They’d arrive a week to ten days before Christmas so they could hang, which improves the taste. Really, it does. Sometimes there was also a large box of brussel sprouts, always tasting best after the first frost. The Christmas Pudding would sometimes be one that had been given to us the year before by the Scotts from St. Ippolytts, as you’re supposed to let them age. One year we had a new one, but the person who steamed it didn’t realize you had to take it out of the plastic pot first. No problem, there was one from the previous year in the cupboard, and once the pressure cooker was cleaned of melted plastic it was all systems go.

Living here in Canada, in Eastern Ontario, it seems hard to remember that some years we hadn’t had the first frost by Christmas; other years the house froze up. The winters in England were mostly cold and damp, which is vastly more unpleasant than the Ontario cold and dry winters. But we had the coal and log fires and we had the church, and at night we could close the eighteenth century wooden shutters and the wartime blackout curtains and make it less spooky; at Christmas the house came alive. I slept in the attic, and after I went up the stairs each night I'd hear someone else coming behind me, maybe five or ten minutes later. It was the boards creaking.

So the house was always cold in the winter, but it was full of people at Christmas, and, being a vicarage, often full of people at other times too. I loved it there, even if I hated the cold. Of course, I wasn’t the one paying the food and heating bills!

Thursday, October 2, 2014

Some Myths About XML and RDF

It doesn't make sense to compare XML and RDF any more than it makes sense to compare poetry and paper, or a tax bill and a bottle of ink. But people do it.

XML here is like blank paper, a medium. It doesn’t give give meaning to the poem, and you could write the poem on something else, but that doesn’t diminish the usefulness and value of paper. Which brings me to the first myth, one I have heard often:

1. XML has no semantics, therefore XML cannot express RDF

This makes no sense if you think of XML as the paper, or as the electrical cable carrying a telephone conversation. Er, OK, if you’re young and use these new-fangled portable telephones, the radio waves carrying a telephone conversation.

But if it did make sense your RDF would lose all its meaning when you serialized your RDF graph as RDF/XML. When you send that XML to someone else and they reconstitute an RDF graph, they say there’s meaning in that RDF graph. How was the meaning transmittted if XML cannot store meaning?  I call this the XML Phlogiston argument.

2. XML is about trees and cannot represent graphs.

One RDF advocate accused me of not knowing what a graph was when I said this was not the case, but the existence of RDF/XML, and for that matter GraphML, proves otherwise. XML can store graphs just fine.

3. RDF lets you concatenate graphs to combine them but XML cannot do this.

This is a more subtle myth. First, you can’t concatenate two RDF/XML documents as-is, because the result would not be well-formed XML. But you can use a simple XQuery expression such as
    <rdf xmlns:ref="
>{ doc('a.xml')/*/*, doc('b.xml')/*/* }</rdf>
to return a single combined document.

The hard part is called schema mapping or ontology matching - if one document uses vehicle, automotive, four-wheeled, short, sports-car, and another uses car, green, you can’t assume all green cars are sports cars, and no automatic combination of the graphs is possible, regardless of whether you use n3 or turtle or sparql or strawberry jam,and it’s as true in JSON and XML as in RDF.

4. XML Failed

I’ve heard this one even from colleagues, some of who believed the goal of XML was to replace HTML. That wasn’t our goal at all, and XML is doing very nicely in its original intended use of technical documentation, thank you. So this isn’t really about RDF and XML except that I sometimes hear it in that context.

Are there other RDF and XML myths?

[update: yes, no. 2 should have read, and now does read, graphs, thank you to those who pointed it out.]

Sunday, August 17, 2014

Back-of-the-book Indexes and CSS

An index in the context of printed books is a list of topics with associated page numbers, usually printed at or near the end of the book.

The plural is indexes, unlike the mathematical indices, which are different beasts that happen to share the same singular form, index.

To make an index for a digital document, you:
  1. Mark the targets, the topics, in the main book itself;
  2. Extract the list of topics, or index headings as they are called, and sort them;
  3. For each topic, collect the list of appropriate page numbers;
  4. Collapse runs of adjacent page numbers into ranges.
All of this can easily be done declaratively. There are some minor complications to resolve, but they are not too hard:
  1. Sorting multilingual headings, symbols, and other items;
  2. Multi-level indexes;
  3. Mixtures of references of differing types;
  4. References to footnotes;
  5. Balanced column formatting.


Books might well have multiple scripts in use, such as Latin for English and Spanish and Devanagari for Hindi. It may be necessary to use different collations for different parts of the index, for example to get an index of Spanish names to sort names starting with Ch properly without affecting the index of French names on the next page. It may be appropriate to provide a sort key for an individual index heading to get it to go where you (as author) want it.

Even a moderate sized book can have hundreds or thousands of index entries, so sorting them obviously should be done automatically.  However, it is possible to do that outside of CSS, for example with JavaScript or XSLT, before formatting. A minimal proposal for supporting indexes in CSS therefore does not need to address sorting the index.

Multi-level indexes

It’s not uncommon to see sub-topics collated together in an index:
    Socks, black, 28, 73; argyle, 24-56, 72; white: 24

This is done partly to save space in the index, partly to make using the index more efficient (everything to do with socks is in one place, instead of under A for argyle,, B for black and so forth) and partly to avoid ugly and potentially confusing repetition of the main head (socks) for each sub-entry.

The consequence for software is just that you need a multi-level sort.

As with sorting the index itself, collation and sorting of sub-entries can  be done before formatting the document and doesn’t need to be specified with CSS. We only need to bother ourselves about the page numbers, which must of course be supplied by the formatter.

Mixtures of references of differing types

It’s common to indicate in an index more than just the page number but also what the reader might find there: a discussion, a definition of a term, a figure, a table, a mention in passing. Note that the actual index heading might not appear in the text; a discussion of argyle socks might not mention the word “sock” but only talk about the pattern, or perhaps use the word “stocking;” this is part of why a well-crafted index can be more valuable than automated searching for some applications.

The usual ways to distinguish the different types of reference are to use bold page numbers for definitions, italic for figures, and perhaps to prefix the page number with a symbol such as an asterisk (*) or dagger (†) for a table.

This means that if you have a figure that occurs in the middle of a discussion it’ll be listed separately:
    Socks, argyle, 24-28, 26, 72

References to footnotes and other page areas

A reference to a footnote usually has an annotation such as 46 note 1 so that the reader has warning both of where to look on the page and that the reference might not be part of the main discussion. If there are references to multiple footnotes on the same page they could be listed,
    Socks, argyle, 24-28, 26, 72 note 1, note 3.

Other areas that might have specific annotations in an index include sidebars, examples, tables, side-notes (marginalia) and other secondary content. Books with large, dense pages such as the Encyclopædia Britannica might divide the page into areas and have a reference like 46C to mean the bottom left quadrant of page 46 but these are specialized books, often produced with highly customized software.

Balanced Column Formatting

I’ll mention this for completeness, because the index-specific processing is all about the references. Indexes are usually printed in relatively narrow columns, three or more to a page. On the last page of the index the columns will probably all be balanced so they are the same height (give or take one or two lines in the last column).

It can be important with the back matter in a book to remember that the book must usually be a multiple of 16, 32 or 64 pages to be printed economically by folding large sheets of paper. So if you end up with two lines of index on the last page you’ll want to set a shorter page if that avoids having 63 blank pages after it!

Formatting with CSS

CSS doesn’t yet support index generation, but XSL-FO extended CSS 2.1 to add properties for indexes, and this was implemented and today is widely used in production. So maybe we can do something similar.

You can also refer to the XSL-FO 2.0 draft for a much more detailed explanation that I am going to give; we don’t need as much because CSS already has ways to do most of what we need. I think there may also be a mistake in the summary of generated page numbers as page 14 doesn’t appear anywhere; if so, sorry.

Let’s suppose for now that we have an HTML (or XHTML) document containing a sorted index ready to format. it might have markup like this, to generate
    Socks, argyle, 24-28, 26, 72

<li class="index-entry">
    <span class="head">Socks</span>
    <span class="subhead">argyle</span>
    <a href="#ie41" class="ie"></a>

    <a href="#ie42" class="ie"></a>
    <a href="#ie46" class="ie"></a>
    <a href="#ie50" class="ie"></a>
    <a href="#fig17" class="ie figure-ref"></a>
    <a href="#ie51" class="ie"></a>
    <a href="#ie52" class="ie"></a>
    <a href="#ie53" class="ie"></a>
    <a href="#ie141" class="ie"></a>
    <a href="#ie142" class="ie"></a>

We don’t know the page numbers in advance so we can’t put them there. They’ll be supplied by the content property.

Suppose when the document is formatted the targets referred to end up being on pages 24, 24, 25, 26, 26, 26 (the figure), 26, 27, 28, 72 and 72.

The formatter will need to process this list:
  1. separate out the figure reference
  2. collapse duplicate numbers in the list
  3. collapse ranges into a start and end with a separator
  4. merge the separate streams (here, references to text and to figures) by sorting on the first number in each range.
A complication is that the page number used for sorting will presumably be the page built-in variable, but the value printed will be as it might appear on the page running header or footer, so that an introduction page might get roman numerals (Socks, white: xxiii) and an appendix might get a preceding letter, known as a folio prefix, such as B for Appendix B (Socks, internet proxy: B-42). This is the same as for general cross-references within a book, of course.

When eliminating duplicates, the value of the index-merge property determines whether a sequence of three or more consecutive page numbers are merged together to form a range, or if they are kept separate.

A second complication is that if there were ranges in the example instead of just individual references, the formatter would typically expand the ranges into a list of individual pages first (in practice this will be a short list) between steps one and two in the process, because that simplifies the process of eliminating duplicates.

In addition, items with different index-class values are normally kept separate, but a property index-merge-differing-classes can be set so that the figure reference in the example would vanish, as it’s contained with the 24-28 page range.

After handling page ranges the index entries are formatted normally, with the content property and :before and :after being available to support the various page number formats, and to allow marking index entries to colour plates (say) in [square brackets], just as for a normal cross-reference. However, the number of “a” elements/nodes may in general  be fewer than in the original document before index processing. It can never be more: references within a range that were expanded to simplify processing in an implementation do not result in new elements being created.

Issue: should the transformation from original list to sorted, merged list use the shadow DOM?

Issue: how best to supply the comma, en dash or “ and ” between entries? XSL-FO just inserts a text node with no standard way to change the en dash or comma and space.

Properties (proposed)

index-class: a user-defined “ASCII-lower-case” string; entries with different index class values do not by default get merged together, so that you can keep figure references even when they fall within a range of text pages, of keep a definition even if it, too, falls within, say, a range of figures.

index-item (none, begin, end, span, point): set this on the “a” element. It does not inherit. “span” means that all of the pages generated by the target element are added to the index; otherwise the page on which the element starts is used. The begin and end values are used in pairs to mark index ranges and point is used for a stand-alone page reference. None turns off index processing on the given element.

index-list: Use index-list for the containing element to indicate that its children are to be processed as index citations; this would be used on the “p” element in the sample markup above. Values are none (don’t do index processing), no-merge, same-index-class, all). A value of same-index-class means page ranges are merged only when they have the same associated index-class value. A value of  between-classes means index-class values are ignored for the purpose of merging. A value of no-merge enables index processing but not merging of adjacent pages into a range. In all cases page numbers that are explicitly marked as being a range using index-item begin and end are kept as a range.

Issue: is this enough? I’ve proposed merging XSL-FO merge-pages-across-index-key-references and merge-ranges-across-index-key-references into the values of index-list but I have lost the ability to merge between index classes and not within a class; I think that combination never made sense. The page-number-prefix and suffix can be done with before/after.

Other items

Indexes might contain cross-references such as “Stockings: see under socks” which do not need special formatting. One might make the text be a link, of course.

Column balancing is outside the scope of index processing.

Formatters are not expected to support index entries that point back into the index itself.

If you reset the global page counter, the index facility proposed here will give you strange results.


Fonts Across the Libre Desktop: Design and Graphics Focus

Today, each application, and each toolkit, offers font selection. But fonts have become gradualy more complex, and none of the interfaces se...