Sunday, January 18, 2009

FOP Positive Descender Underline Bug

Well here is my cowardly effort at giving back to the open source community. But first! What is the open source community?

It's all about nerds. I'm one and so are you if you are reading this after doing a google search for a solution to the positive descender underline bug in Apache FOP. But if not I'll give a quick run down. In the world of computer programming there is a movement which holds dear the concept that ideas and information are free. Free as in unshackled, free as in free to be exchanged. Sometimes you have to pay money for the info and ideas, but if / when you do you should have access to the whole idea. The same way when you buy a car you are allowed to open the bonnet and tinker with the guts. So programmers often allow others to see their work and we are all enriched by it. For a more detailed discussion: open source [wikipedia]

The Bug:
The bug I have solved manifests itself in a bit of software called Apache FOP. This software allows me to take some stuff drawn on the screen in Adobe Flash and turn it into pdf documents or png images. The problem happens when you try to underline text in an embedded font which has a positive descender. A positive descender means that part of the text of the font hangs below the baseline. For example in Lucida Sans the p, y, j and g all have little squiggly bits hanging below the base of the other characters. In this instance FOP fails to draw an underline because it throws an error that says it can't draw a border with a negative height.

Suspect Math:
The cause is a bit of suspect math in the underline
public abstract class AbstractPathOrientedRenderer extends PrintRenderer {
protected void renderTextDecoration(FontMetrics fm, int fontsize, InlineArea inline,
int baseline, int startx) {
boolean hasTextDeco = inline.hasUnderline()
|| inline.hasOverline()
|| inline.hasLineThrough();
if (hasTextDeco) {
float descender = fm.getDescender(fontsize) / 1000f;
float capHeight = fm.getCapHeight(fontsize) / 1000f;
float halfLineWidth = descender / -8f / 2f;
float endx = (startx + inline.getIPD()) / 1000f;
if (inline.hasUnderline()) {
Color ct = (Color) inline.getTrait(Trait.UNDERLINE_COLOR);
float y = baseline - descender / 2f;
drawBorderLine(startx / 1000f, (y - halfLineWidth) / 1000f,
endx, (y + halfLineWidth) / 1000f,
true, true, Constants.EN_SOLID, ct);
So you can see the bolded parts involve some calculation of a y position based on the descender value of the font. If the descender value is negative it all works nicely, if it is positive we end of with an inverted set of values in the call to drawBorderLine() method.

My Solution:
Here you see what I changed:
protected void renderTextDecoration(FontMetrics fm, int fontsize, InlineArea inline,
int baseline, int startx) {
boolean hasTextDeco = inline.hasUnderline()
|| inline.hasOverline()
|| inline.hasLineThrough();
if (hasTextDeco) {
float descender = Math.abs(fm.getDescender(fontsize) / 1000f);
float capHeight = fm.getCapHeight(fontsize) / 1000f;
float halfLineWidth = descender / 16f;
float endx = (startx + inline.getIPD()) / 1000f;
if (inline.hasUnderline()) {
Color ct = (Color) inline.getTrait(Trait.UNDERLINE_COLOR);
float y = baseline + descender / 2f;
drawBorderLine(startx / 1000f, (y - halfLineWidth) / 1000f,
endx, (y + halfLineWidth) / 1000f,
true, true, Constants.EN_SOLID, ct);
Now the bolded bits firstly show I get the absolute value of the descender, I divide it by 16 (rather than by 8 then by 2) and finally I add half the descender value to the baseline to get the y position.
The short of it is that the code now works for both negative and positive value descenders. The world rejoice!

Did I submit this back to the opensource project? No, because I've already hacked up my copy of FOP beyond recognition to reduce the on disk output size of pdfs using large svg images (by reducing the number of decimal points of precision from 8 to 3) and using a file backed caching system to step around the memory issues associated with printing said large pdfs. Feel free to ask me for more details about those fixes, if I don't get around to writing about them here.

Wednesday, January 14, 2009

Woodwork, My Bedside Table

I love making stuff. By trade I make software but I have trouble explaining to non-software types what it is that I have done. It is difficult to show my wife the amazing indexed search system I implemented or explain how I overcame the font underline issues in Apache FOP when using a font with a positive decender value. But wait! Woodwork on the other hand produces a tangible item that can be touched and felt, smelt and tasted... though you probably shouldn't.

Project 1: My Computer Desk
I used to live in Melbourne but since I failed to grow gills and/or a protective layer of fur and blubber (working on the blubber) I moved to somewhere sunny and warm. In the move I threw out my old student desk because I was struck by a sever case of good taste. I was left without a desk, but gained a large room I could work in. The short of it is that I designed and built a computer desk with three draws on one side and a shelf on the other for my computer. It turned out ok though it is clear there is a good reason we pay cabinet makers to build such things. If you cared to read my previous post you would understand that I spent a lot of time, little money and no experience in creating my desk. I really needed to spend more time I think.

Project 2: My Bedside Table
In this new house I am in there is a "granny flat" where my parents stayed while they visited. In it we put a bed but alas, no table beside it! So I am making a bedside table. I've got a couple more tools and a computer desks worth of experience.

The design:

A marvel of engineering and sensible elegance no? The whole thing is to be made of pine then stained and sealed. I've already made a start.
What I've done:

Here you can see one completed shelf and the four frame pieces for the second shelf. I'm using lap joins to cross hatch the frame because I think I'm tricky. To cut out the waste of the lap joins I initially used a hand tenon saw to cut each edge then make three cuts in the waste. I then used a chisel to clear the waste. This is what my big book of wood working tells me to do. What the big book doesn't say is that if you are an inexperienced tit with about seven thumbs, most of them on your left hand, you have little chance of making rebates that will fit together. I had to learn that the hard way.

None of my joins worked. Each plank had what looked like a suitable rebate but when put together they didn't sit flat and were really hard to squeeze in to place. Not to fear I'm a software engineer! When experience lets me down (I have so little) I look for someone else's technology to save me. I essentially wanted to download the Apache Joint Maker 4 Pine but that doesn't exist. Instead I used my Christmas gift vouchers to buy a router. I set the depth and ran the router over each of my chiseled rebates and it sheared off the wood I'd missed and now all the joins meet perfectly.

The actual shelf bit is made of three planks joined side by side with glue (I just need it strong enough to hold while I attach them) and joined to two of the cross pieces by screws hidden in pocket holes.

The next step is to make the legs and cut the housing holes for the shleves then a lick of stain and estapol and she'll be right.

Another project?
After I've done this I think I might make a little TV stand for my spare TV. Really just another excuse to use power tools and learn a bit more. I've told people I'm going to retire early (about 40) and they say "But what will you do? Wont you get bored?" (they actually misspell won't when speaking... somehow) As if the only thing I do is work! Pah. I intend to make stuff out of wood and build a car (from the ground up, not just do up an existing one) and race a car and probably crash a car and injure myself with power tools. What more could a man want?

I'll update my blog with my progress. Also I might write a bit about how it is that I intend to retire so young.

Wednesday, January 7, 2009

Three Exchangable Comodities

In my world view, soon surely to be yours too, there are generally speaking three exchangable comodities that any human may possess. These can be used in some combination to achieve nearly anything you might choose to do.
  1. Time
  2. Money
  3. Experience / Knowledge
These must be considered in the context of a specific task. For that task then a person has a pool of each resource and a lack in one can be compensated for by an abundance in another.


Given enough time a person can do anything. The sad thing being that many tasks require so much time that no one person can supply it. For example, say I want to build a house: With enough time I could build the mud bricks I'd need, then lay them (having designed the house) then make tiles / shingles and so on and so forth. This is of course how they did it many years ago, possibly as early as 1982, though I'm not sure humans had discovered shelter yet...

Ah, money. Many people really don't understand what money is, but this three comodity model is reasonably good at demonstrating it. Money is an abstract representation of applicable resource. It is a way of trading your experience and time for someone else's experience and time. In the above example it would take me many long hours (lifetimes?) to build a house. However I am quite skilled at developing software solutions to business problems. I get paid to use my skill over time so I can use that money to exchange for someone else's skill and time to build my house. Lovely. That really is what money is about. How else can I trade my knowledge with a builder? What use has a brick layer for a multi-user distributed database application? Well arguments could be made, but it general they would prefer $$$, though beer is a close second.

Experience / Knowledge:
The final piece of the puzzle. If you have plenty of experience doing something, generally speaking the less time you need to do it. If you can do it you don't need to pay someone else to do it. To do a basic service of my car takes me a good 3-4 hours. That's changing oil, filters, plugs and checking brakes etc... A good mechanic can probably do it in 1 hour (maybe less? heck I'm not even experienced enough to know.)

So time, money and experience are exchangable. Or at least that is how I look at most problems I run into. I use this theory to help evaluate various decisions I have to make.

Service my car:
  1. Time: 3-4 hours
  2. Money: $100
  3. Experience: not much.
If I want to spend less money I'd need either enough time to develope and build my own oil filter or lubricant or I'd need enough experience and knowledge to find good cheaper substitutes.
To reduce time I could pay a mechanic or just know how to do everything without need to constantly look up my books.
To reduce my experience required I could pay a mechanic or spend longer learning everything.

I guess you get the picture.

Cognitive Imperial, I

Cognitive imperialism is a fancy-pants way of describing the act of convincing others to a particular way of thinking; that is building an empire of thought.

Yes, I did major in Arts at university and so undertook philosophy, psychology, literature and other perverse studies. Fear not however! I quickly saw the error of my ways and changed to a double major of computing and marketing in the school of business (I actually wanted a job when I finished).

So this blog is my cognitive imperialism, my attempt to express my world view in a way that conquors the thoughts of others and sways them to hold my beliefs. Failing that I'll just discuss my thoughts on cars, motor-sport, computing, home improvement and possibly current events relating to free thought. So in other words much like every other blog. I will attempt to provide some level of contraversial or maybe thought provoking content, or in the case of my computing discussions, useful solutions to ugly problems.

So with no more time wasted on introductions I will present my first mind expanding thought:
Farts, along with sudden groin hits, are surely the only universal comedy. I recon that if aliens were to land and we wanted to give them a good giggle all we need to do is wait for a dramatic pause in the greetings and let loose with a good, loud and squeeky fart. What a way to break the galactic ice?

That aside I'll be back to discuss my current wood-working project: a bedside table! Hooray for excitement.