Tuesday, March 1, 2011

Text: Effects and Block Shadows

This weekend I revisited an old project: the calligraphy stroke.

I rewrote it using a handy unassuming class called the CalligraphyPathWriter. This is fewer lines of code than the previous model, pipes the data more efficiently, and includes a couple of extra functions.

It no longer only makes strokes. The same basic notion of tracing a shape to apply a calligraphy-like stroke can be applied to creating drop shadows. The only difference is a stroke straddles the path, and a drop shadow lies entirely to the side of the original shape.

The CalligraphyPathWriter constructor includes two floats to define these offsets: if you use 0 and 30: then you're effectively adding a drop shadow to your shape. If you use -5 and 5: then you're effectively creating a stroked outline of your shape.

You can also create a drop-shadow-like effect with code like this:

Graphics2D g;
Shape myShape;
...
double dx = Math.cos(angle);
double dy = Math.sin(angle);
for(int height = 0; height < 30; height++) {
  g.translate(height*dx, height*dy);
  g.fill(myShape);
  g.translate(-height*dx, -height*dy);
}

... but if your shape or java.awt.Paint are complex: this might be expensive. (Also two of the four effects shown below can't be reproduced this way.)

The CalligraphyPathWriter can reduce this down to:

GeneralPath blockShadow = new GeneralPath();
CalligraphyPathWriter writer =
    new CalligraphyPathWriter(angle, 0, height, blockShadow);
writer.write(myShape);
g.fill(blockShadow);

The call write(myShape) iterates over the input shape and populates the blockShadow path with the silhouette of the block shadow.

Applying To Text


Here is a simple applet that creates animated text effects using these new block shadows:

You can download the applet (source included) here.

Type any text in the text field provided. (Any text is acceptable, but it should probably be 20 characters or less?) Then select any one of the buttons:

  • The "Outline" button uses the Scribbler class to randomize the texture of the text, fill and shadow. A little random vertical offset is added, and lastly a light drop shadow is traced (but not filled) around each letter.
  • The "Punch" button separately punches each word forward with an obvious drop shadow. (Also try writing a string with no spaces: then each character is punched.)
  • The "Wave" button fills and traces the block shadow to reinforce the 3D-look.
  • The "Explode" uses another obvious drop shadow, but each character is assigned an angle based on how far away it is from the center. (Then the height has to be divided by the sine of that angle so the baseline is constant.)

My immediate goal this weekend was just to use block shadows for something fun. In the long term I want to define an architecture similar to what I did for simple 2D-geometric transitions. This demo applet uses a very loosely defined TextEffect interface, but it needs a lot more work to support a variety of effects for different export formats.

Also in the future it would be nice to apply gradients to these block shadows. A height-based gradient effect will be very easy. An angle-based effect (which I think would be more popular) will be a little trickier, but is still manageable.