Deprecated: Function set_magic_quotes_runtime() is deprecated in /home/xeno04/tp.walkersoftware.net/textpattern/lib/txplib_db.php on line 14
Walker Software Weblog: Text Effects in Java

Text Effects in Java

Jul 29, 07:31 PM

I haven’t seen many examples of using GlyphVector in Java2D to do text effects, like gradient fills or create outlines of text. So I tried.
Text Demo Screen shot
WebStart demo
Source code
Updated to fix issue with gradients.

There are a few odd things about GlyphVector. It contains methods to transform each glyph (a glyph could be character, part of a character, or multiple characters), but it seems that is incomplete. To transform each glyph, you’ll need to create a GeneralPath, obtain each glyph from the GlyphVector, transform it, and append it to the GeneralPath.

The gradient fills, beveling, and drop shadows could have been faked by using AlphaComposite and rendering multiple times, but the jiggle (Each character rotated slightly) and fatten needed the vector shapes instead of bitmap fakery.

The “fatten” is like Photoshop’s expand (or grow) selection. Expanding the section can help create a lot of effects and generally make text look better (most fonts are too thin for good looking titles). There does not seem to be an good way to approximate this in Java2D. The method implemented here is to use a Stroke to create an outline of the text and use Area to merge the text and it’s outline together. That is very slow. I’ve had a few other ideas for doing this, but I haven’t had time to try them.

I created this a few months ago and never posted. I’m not sure the webstart demo and the source code still match. This was a test-bed I created to try some effects that I later used in other places. I know the UI is not good, I needed something quick and usable. The are many other (better) uses for transforming glyphs like custom spacing between letters and creating type on a curve.

Comments

Great! Thanks for sharing. There is just a slight problem which happens from time to time: the gradient doesn\'t go far enough so the text end up with some small gray areas at the bottom of some letters.

Romain Guy · Jul 30, 03:12 AM · #

Thanks Romain. I\'ve fixed that and updated the WebStart demo and source files.

— Adam · Jul 30, 05:48 PM · #

Hey, pretty fun little app. One downer -- it takes a little over 2 seconds on my dual 2.8 ghz Xeon box to render (WinXP, NVidia 6600 with 256MB, 1GB system memory). Any idea what takes so long? If you have any insights I\'d love to run it by my Java2D teamates and see if we can\'t accelerate this more.

Cheers
Richard

— Richard · Aug 9, 06:46 PM · #

Hi Richard, The slowdown is the \"fatten\" effect. The slowest part of the code follows

// What we need is something like photoshop\'s expand selection.

// The following is very slow...
Area area = new Area(path);
area.add(new Area(bs.createStrokedShape(path)));
shape = area;

\"bs\" is a BasicStroke instance.
If you move the \"Fatten\" slider down to 0 and click update, The app creates the effects in under 30ms on my machine (single processor 1.3 Ghz Mac G4, the times are similar for my Windows laptop - single processor 2.4 Ghz Pentium 4).
Moving the slider off of zero bumps the time up to 1500-2600ms depending on the font.

— Adam · Aug 9, 07:14 PM · #

Hey Adam,

I talked with Jim Graham about the problem. Essentially, the logic behind Area is rather complex due to the nature of joining multiple paths together. The only way to really speed up the effect is to write custom logic meant specifically for this particular problem. Probably not worth the effort unless you needed this functionality in a real application. Photoshop, for instance, has probably tuned a special algorithm specifically for this text problem, whereas Java2D provides a more generic solution.

One hint though, is that every time an Area is created it performs a couple area ops. I\'m not sure if this code is being executed for each glyph or for the final product. If it is per glyph, then try doing it on the entire text string -- it might be faster. Also, you are creating 2 areas and doing an area.add, effectively running 3 area op\'s. If you can get that down it would be a lot faster.

I don\'t know enough about the problem to be any more help than that, good luck :)

Richard

— Richard · Aug 10, 03:45 PM · #

Hello Richard,

The Area ops are done once per string. Area.add (in fact, most Area methods) only accept Area instances as parameters, so there isn\'t much of a way to reduce that.

— Adam · Aug 10, 04:31 PM · #

Commenting is closed for this article.