Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

2008-09-18

FOP and fonts, the story goes on

Now I've a better understanding on how FOP handles fonts and how to get its precious informations about font list, duplicates, and failures. In the PrintRendererConfigurator, the #buildFontListFromConfiguration static method does (almost) all the job. It takes following input parameters:
  • A Configuration object with a <renderer> as root element.
  • A URL (as a String) to resolve relative font URLs with. Null is supported.
  • A FontResolver, which can be a DefaultFontResolver.
  • A boolean set to true if an exception should be thrown if an error is found.
  • A FontCache instance or null if caching is disabled.
As it is a static method, #buildFontListFromConfiguration can be called from everywhere with a fresh FontCache instance. The latter is useful as it gathers failed fonts. A fresh cache instance is needed, because cached data may survive the JVM. The cache saves itself in a ~/.fop/fop-fonts.cache file, holding font descriptions. Font descriptions seem to be only invalidated when FOP attempts to load a font for "real" (at rendering time). So when hitting the cache in a test program, it sometimes returned font descriptions that shouldn't have been there. The FontResolver requires a FOUserAgent which is created from a FopFactory. The FopFactory itself is created from a Configuration which contains the <renderer> elements, so there should be some instance reuse here. I've found a private method somewhere which logs font duplicates but I can't find it back to see if there was any hook around (didn't seem so). Anyways it will be cleaner to sort out font triplets with the same value. Printing the font triplets on the console, I noted they take the right font name, whatever the font file is. Adios, proprietary font naming convention!

2008-09-16

FOP and fonts

FOP makes me feel dumb because it is great. In a previous post I already mentioned that FOP's font handling was better than I thought first, so I could have been wrong forcing a custom font naming. As a matter of fact, FOP holds a list of fonts inside the FontCache of its FontFactory. Novelang instantiates the FontFactory so it has full hands on it. Using a Java debugger, let's look at what a FontCache contains.
fontMap = {java.util.HashMap}
  [0] = {java.util.HashMap$Entry} 
    key: java.lang.String
        "file:/…/fonts/URWGothicL-BookObli.ttf"
    value: org.apache.fop.fonts.CachedFontInfo
      lastModified = 1042610200000
      metricsFile = {java.lang.String}
          "file:/…/.fop-font-metrics-14045 \
               .temp/URWGothicL-BookObli.xml"
      embedFile = {java.lang.String}
          "file:/…/fonts/URWGothicL-BookObli.ttf"
      kerning = true
      fontTriplets = {java.util.ArrayList} 
        [0] = {org.apache.fop.fonts.FontTriplet} 
          name = {java.lang.String} 
              "URWGothicL-BookObli"
          style = {java.lang.String} "normal"
          weight = 400
          priority = 0
          key = {java.lang.String}
              "URWGothicL-BookObli,normal,400"
        […]
  […]
failedFontMap = {java.util.HashMap}
Sweet! Here is everything I need:
  • Font name.
  • Font style, "italic" or "normal".
  • Weight. Not just "normal" or "bold" but "light" and "extra-bold".
  • Priority for dealing with duplicates
  • A list of fonts which could not be read (failedFontMap).
The moderately bad news is, fontMap and failedFontMap are private fields but I see no reason to not use dirty reflexion here. The example above is biased as it was created from a Novelang-generated font list, so I'll have to investigate a bit more to see how Fop deals with:
  • Failed fonts.
  • Font name different from font file name.
  • Multiple directories (including nested ones).
To sum up, FOP provides all I need to make Novelang code cleaner and bring following enhancements:
  • Multiple directories.
  • List of failed fonts.
  • Warning in case of duplicates.
  • Fonts sorted by font name.
  • Throw away temporary .fop-font-metrics directory.
  • Cache of font descriptions handled by FOP itself (this is the meaning of the lastModified field in the FontCache).
  • Support more font types. By letting FOP do its job we let its FontFileFinder recognize following font files: *.ttf for True Type, *.pfb for Type One. The *.otf suffix also appears and those fonts may be treated as TTF,

2008-05-12

Command-line arguments with JOpt Simple

Novelang started as an interactive tool because it was easier to use a Web browser for a quick preview of generated documents. But now that I want to publish documentation on the still-to-come website I need to automate document generation, because Novelang website has to be generated with Novelang (or I'd get ashamed). So I have to support a command-line based interface. By now it's a fairly simple one. Helps prints with one of the -h -? --help options whenever other options are activated. That seemed useful to me because when I type some long command and get lost with options, I don't want to run it (starting dangerous things or polluting the console with error message) nor hit Ctrl-C to request help on the next prompt -- and have to copy-paste it again. Here is the help message for now:
Usage:   Main [Options] <document [document2 [...]]>

<document>: logical name of a document to generate.
Starts with '/part/' or '/book/' (like URLs).
Valid names: /part/somedir/mydoc.html or /book/mybook.pdf

Option                      Description                                      
--------------------------- ------------------------------------------------------
-?, -h, --help              Shows this help message                          
-t, --targetDirectory <dir> Where generated files go to (default is './generated')
It's surprisingly hard to write concise help messages. I had to trick the terms to make -t option as short as possible and I'm still above 80 chars. Including line breaks and whitespace to make the "(default is [...]" message appear on another line doesn't work well as the framework generating help message understands this as one single line and generates many, many dashes in the table header. It could have limited dashes to an underline of "Option" and "Description" headers. I chose to explain document names right after general command syntax because the option list "breaks" the layout somehow. On the other hand, if the option list grows a lot, general syntax will scroll up out of view. But there is always the option to add a "verbose help" option later. One special case arises when a document file starts with a dash (-) and therefore can be confused with an option. A double dash (--) as the last option disambiguates this and we can write (though I'm not sure Novelang supports file names starting with a dash but it's another story):
Main -- -mybook.pdf
Main -t somewhere -- -mybook.pdf
Writing nice command-line interface is always more complicated than it seems. Lucky me, I found JOpt Simple, an excellent framework that perfectly suited my needs (including the double dash support). It worked flawlessly for everything I needed, including double dash disambiguation. I just ran through some minor annoyances:
  • Esoteric Artistic Free License.
  • Maven-only distribution hidden somewhere on the website.
  • Doesn't use Java Generics (at least OptionSet#nonOptionArguments() should return a List<String>).
I'd also appreciate multiline option description. Paul R. Holser, author of JOpt Simple, claims that his tool is better that competing ones, and he's not afraid to link on them from his project's home page. After repeated disappointements with Jakarta Commons-CLI and a few tries to grok the API of his competitors, I agree that JOpt Simple is far above others.