I've upgraded the VisualWorks CairoGraphics package to use the latest 1.2.0 release of Cairo. And then continued fleshing out the Smalltalk binding/interface. I went to the Cairo guys and asked them for a fun example that would do something with text and other stuff. They pointed me at a little C program that produced the following:
Except... I made that with VisualWorks. The code to do it is longish (but make sure you at least scroll past it):
spikes := 10.
imageWidth := 384.
imageHeight := 256.
center := (imageWidth @ imageHeight) half.
fuzz := 16.
shadowOffset := 10.
innerRatio := 0.7.
random := Random standard.
star := (1 to: spikes * 2) collect:
[:n |
| z |
z := n / spikes * Float pi.
z cos @ z sin * (center - fuzz - shadowOffset)
* (n odd ifTrue: [innerRatio] ifFalse: [1])
+ (random next @ random next * fuzz) + center]
string := 'KAPOW'.
surface := ImageSurface format: #alphaColor
extent: imageWidth @ imageHeight
cr := surface context.
cr lineWidth: 2.
cr save.
cr translate: shadowOffset asPoint.
cr completePath: star.
cr sourceRed: 0 green: 0 blue: 0 alpha: 0.5
cr fill.
cr restore.
cr completePath: star.
pattern := RadialGradient from: center radius: 10 to: center radius: 230.
pattern addStopAt: 0 red: 1 green: 1 blue: 0.2.
pattern addStopAt: 1 red: 1 green: 0 blue: 0
cr source: pattern.
cr fill.
cr completePath: star.
cr sourceRed: 0 green: 0 blue: 0.
cr stroke.
cr selectFontFace: 'Sans' slant: 0 bold: true
cr fontSize: 50.
dimensions := cr measureString: string.
x := imageWidth half - (dimensions width half + dimensions xBearing).
y := imageHeight half - (dimensions height half + dimensions yBearing).
bendPoint :=
[:point |
anchor := imageWidth half @ 500.
angle := Double pi half - ((point x - anchor x) / imageWidth).
t := 3 * Double pi / 4 - angle + 0.05.
angle := 3 * Double pi / 4 - (t ** 1.8).
radius := anchor y
- (imageHeight / 2 + ((point y - (imageHeight / 2)) * t * 2)).
anchor + (angle cos @ angle sin negated * radius)].
cr moveTo: x @ y.
cr textPath: string.
path := cr copyFlatPath.
cr newPath.
path doMove: [:move | cr moveTo: (bendPoint value: move point)]
line: [:line | cr lineTo: (bendPoint value: line point)]
close: [:close | cr closePath].
pattern := LinearGradient from: (imageWidth half - 10) @ (imageHeight / 4)
to: (imageWidth half + 10) @ (imageHeight * 3 / 4).
pattern addStopAt: 0 colorValue: ColorValue white.
pattern addStopAt: 1 red: 0 green: 0 blue: 0.4.
cr source: pattern.
cr fillPreserve.
cr sourceColorValue: ColorValue black.
cr stroke.
surface saveAsPng: string dropSeparators , '.png'
While longish, once you have something like that, it's no time at all to morph it into something like: