Tuesday, November 27, 2007

Declarative Eclipse Branding with SVG

Recently, I had need to add some Eclipse branding graphics to an RCP application.

Rather than take the "easy" route of using an image editor, I thought I'd explore the use of SVG to produce the required images in a declarative kind of way.

Using SVG for this purpose has a number of advantages ...
  • they are cross platform
  • the declarative, text file nature allows the content to be generated
  • they can be created using open-source tools
The downside is that the bitmaps required for Eclipse branding must be in BMP format - not the newer PNG alternative. This is covered in detail in this Eclipse bug report - https://bugs.eclipse.org/bugs/show_bug.cgi?id=21315.

Fortunately, this can be overcome by converting the SVG images to a bitmap format by using a conversion program called a "rasterizer".

A good example of a rasterizer is Batik - an open-source toolkit for manipulating SVG images.
See http://xmlgraphics.apache.org/batik/tools/rasterizer.html for further details on the Batik rasterizer.

Round Trip example

Here's a simple example of some SVG source to get started.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="500"
height="330"
id="drawing">

<defs>
<g id="mytext">
<text
xml:space="preserve"
style="font-size:40px;font-weight:normal;text-align:start;line-height:100%;text-anchor:start;font-family:Bitstream Vera Sans"
x="200" y="125">Hello</text>
<text
xml:space="preserve"
style="font-size:40px;font-weight:normal;text-align:start;line-height:100%;text-anchor:start;font-family:Bitstream Vera Sans"
x="200" y="170">World ...</text>
</g>
</defs>

<rect style="fill:black" width="500" height="330" x="0" y="0" />
<use xlink:href="#mytext" style="fill:white" />

</svg>

This produces a result like this:


In order to produce this image for the web, I used the Batik rasterizer. For example, the command I used was this:


C:\>java -jar c:\jshare\batik-1.7\batik-rasterizer.jar drawing5.svg
About to transcode 1 SVG file(s)

Converting drawing5.svg to drawing5.png ... ... success



Once you have a PNG format image, it's a "simple" matter of converting that to a BMP format. The simplicity involved depends on your platform:
  • if you're on Windows - you can use Microsoft Paint: open the PNG and then save as BMP
  • if you're on Linux - you can use GIMP
Refining your Image

Well, that's produced a very simple image. But one of the advantages of SVG is that you can get very nice effects with a minimum of effort.

Step 1 - Background Gradient

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="500"
height="330"
id="drawing">

<defs>
<g id="mytext">
<text
xml:space="preserve"
style="font-size:40px;font-weight:normal;text-align:start;line-height:100%;text-anchor:start;font-family:Bitstream Vera Sans"
x="200" y="125">Hello</text>
<text
xml:space="preserve"
style="font-size:40px;font-weight:normal;text-align:start;line-height:100%;text-anchor:start;font-family:Bitstream Vera Sans"
x="200" y="170">World ...</text>
</g>

<linearGradient id="top">
<stop offset="0%" style="stop-color: black;"/>
<stop offset="100%" style="stop-color: #484848;"/>
</linearGradient>

</defs>

<rect style="fill:url(#top)" width="500" height="330" x="0" y="0" />

<use xlink:href="#mytext" style="fill:white" />

</svg>

This produces a result like this:



Nice enough, but the default direction for a gradient is from left to right.

Step 2 - Background Gradient - in the correct direction

Here, we use another gradient - with a direction specifier - and embed the first.


<linearGradient id="top">
<stop offset="0%" style="stop-color: black;"/>
<stop offset="100%" style="stop-color: #484848;"/>
</linearGradient>

<linearGradient id="topa"
xlink:href="#top"
x1="0%" y1="0%" x2="0%" y2="100%"/>

</defs>

<rect style="fill:url(#topa)" width="500" height="330" x="0" y="0" />



This produces a result like this:



Step 3 - Background Gradient - with a horizon effect

This refinement adds a horizon - by splitting the image in two - at 200 px down, and using two gradients.


<linearGradient id="top">
<stop offset="0%" style="stop-color: black;"/>
<stop offset="100%" style="stop-color: #484848;"/>
</linearGradient>

<linearGradient id="topa"
xlink:href="#top"
x1="0%" y1="0%" x2="0%" y2="100%"/>

<linearGradient id="bottom">
<stop offset="0%" style="stop-color: #707070;"/>
<stop offset="100%" style="stop-color: black;"/>
</linearGradient>

<linearGradient id="bottoma"
xlink:href="#bottom"
x1="0%" y1="0%" x2="0%" y2="100%"/>

</defs>

<rect style="fill:url(#topa)" width="500" height="200" x="0" y="0" />
<rect style="fill:url(#bottoma)" width="500" height="130" x="0" y="200" />



This produces a result like this:



Step 4 - With a Graphic

Naturally, if we are doing a nice, modern style image, we should use some modern styled clip-art to give the image a lift. Since we are using SVG, there is a whole world of choice at the Open Clip Art project. For my Hello World example, I've chosen a nice clean globe.

In order to use a graphic, download the source to separate file. It can then be included in two different ways:
  1. cut and paste the source code into your SVG file
  2. save it to a separate file, and reference it as below using the image tag.
Note that I have applied a scale transformation to make the image fit in.


<g id="globe">
<image xlink:href="globe.svg"
width="500" height="500" x="0" y="0"
transform="scale(0.25)"/>
</g>

</defs>

<rect style="fill:url(#topa)" width="500" height="200" x="0" y="0" />
<rect style="fill:url(#bottoma)" width="500" height="130" x="0" y="200" />

<use xlink:href="#mytext" style="fill:white" />
<use xlink:href="#globe" x="60" y="80" />



This produces a result like this:



Step 5 - With a Reflection

No self-respecting modern image would be complete without the "reflection" technique! This is amazingly simple using SVG - just apply a transform effect on the use tag.


<use xlink:href="#mytext" style="fill:white" />
<use xlink:href="#mytext" style="fill:white;opacity:0.25" transform="matrix(1 0 0 -1 0 400)"/>

<use xlink:href="#globe" x="60" y="80" />
<use xlink:href="#globe" style="opacity:0.25" x="60" y="80" transform="matrix(1 0 0 -1 0 400)"/>



This produces a result like this:

1 comment:

Jack said...

This is really cool. I find eclipse branding fascinating, throw in the SVG and you've got some fun times. I wish I could keep learning about this stuff, but I've get to get back to work and convert xml to pdf.