October 25, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Java JAXP, Creating Graphics Using Java and SVG

  • January 23, 2007
  • By Richard G. Baldwin
  • Send Email »
  • More Articles »

Java Programming Notes # 2212


Preface

General

This is the first lesson in a two-part series designed to teach you how to write servlets to produce SVG code that will be rendered in graphic form by an SVG-compatible browser.

In this lesson, you will learn how write an SVG graphics library to eliminate or at least alleviate the requirement to write raw XML code or raw JAXP DOM code.  This tutorial will introduce you to the beginnings of an SVG graphics library that makes it possible for you to produce SVG output simply by making Java method calls.

Viewing tip

I recommend that you open another copy of this document in a separate browser window and use the following links to easily find and view the figures and listings while you are reading about them.  You may also find it useful to open a third browser window at the Resources section near the end of the document.  That will make it easy for you to open those resources when they are mentioned in the text.

Figures

  • Figure 1. The basic image.
  • Figure 2. Image with horizontally compressed gradient.
  • Figure 3. A cropped version of Figure 1.
  • Figure 4. Viewing the SVG/XML file in IE 6.

Listings

Supplementary material

I recommend that you also study the other lessons in my extensive collection of online Java tutorials.  You will find a consolidated index at www.DickBaldwin.com.

Preview

The Java 2D API
According to Sun, "The Java 2D API is a set of classes for advanced 2D graphics and imaging, encompassing line art, text, and images in a single comprehensive model. The API provides extensive support for image compositing and alpha channel images, a set of classes to provide accurate color space definition and conversion, and a rich set of display-oriented imaging operators."
Desktop applications

When we write desktop applications using Java, we have access to Sun's Java 2D API (see Resources).  We can easily use the API to provide rich graphical output for the benefit of the user.

Servlets

However, if we are writing servlets instead of desktop applications, it isn't obvious that the Java 2D API is directly useful.  How can we provide the same level of rich graphical output that is possible with desktop applications?

I suppose that one possibility would be to cause the servlet to produce an output that causes the web client to download and execute an applet.  Although I have never done so, it seems that an approach like that would make the Java 2D API available to the servlet/applet programmer.

Walter Zorn's JavaScript library
According to Walter Zorn, "This JavaScript VectorGraphics library provides graphics capabilities for JavaScript: functions to draw circles, ellipses (ovals), oblique lines, polylines and polygons (for instance triangles, rectangles) dynamically into a webpage."
Zorn's JavaScript library

Another possibility might be to cause the servlet to produce an output consisting of JavaScript code that makes use of Walter Zorn's JavaScript graphics library (see Resources).  That might not be a bad idea, except that as of this writing, the capabilities of Zorn's graphics library fall far short of the capabilities of the Java 2D API.

On the other hand, since the code produced by the use of the library is simply JavaScript code, the output should be compatible with most, if not all browsers that are in common use as of the time of this writing.  I will have more to say about the use of Zorn's library in a future tutorial on producing graphic output with the Google Web Toolkit (GWT).

Scalable Vector Graphics (SVG)
According to the W3C, "SVG is a language for describing two-dimensional graphics in XML. SVG allows for three types of graphic objects: vector graphic shapes (e.g., paths consisting of straight lines and curves), images and text. Graphical objects can be grouped, styled, transformed and composited into previously rendered objects. The feature set includes nested transformations, clipping paths, alpha masks, filter effects and template objects."
Scalable Vector Graphics

Another approach is to use Scalable Vector Graphics (see Resources).  Scalable Vector Graphics, (or SVG as it is more commonly known), is a W3C recommendation for the use of a special dialect of XML for the production of graphical output.

As the title of this tutorial suggests, the use of SVG with Java is the main topic of this tutorial.  In this and Part 2 of this tutorial, I will teach you how to write servlets to produce SVG code that will be rendered in graphic form by an SVG-compatible browser.

The capabilities of SVG are extensive, and don't have to take a backseat to the Java 2D API.

SVG and Internet Explorer
As of the date of this writing, IE 7 has been released for a couple of months, but I haven't installed it yet.  I don't know if it has support for SVG built in, or if the Adobe plug-in will cause it to support SVG. From the rumors that I read in the blogs, direct support of SVG is not in Microsoft's plans for IE 7.

All of the examples in this tutorial were produced using Firefox 1.5.0.8.

SVG browser compatibility

There are some downsides to SVG.  Unfortunately, not all browsers currently support SVG, and those that do don't necessarily support it fully. 

Firefox 1.5 and later versions of Firefox support a subset of SVG.

IE 6 doesn't support SVG directly, but there is a plug-in available from Adobe (see Resources) that reportedly makes it possible to render SVG in IE 6.  (Since I don't make much use of IE, I have never installed the SVG plug-in.) 

Requires XML code

Another downside to the use of SVG for many programmers is the requirement to produce XML code in a special dialect that describes the graphic image.  One way to accomplish this is to simply code the raw XML code into output statements so that it will be written into the output.  This is difficult even for persons with considerable expertise in XML, SVG, and Java programming if for no reason other than the requirement to use escape sequences for numerous quotation marks that are required in the raw XML code.

A somewhat easier way, but one that is still not ideal, is to write JAXP DOM code to describe the desired graphics image in a DOM tree, and then to use JAXP to transform the DOM tree into the required raw XML code.  Using JAXP DOM code to produce a DOM tree that represents a complex graphic can be a laborious task.

One of the purposes of this tutorial is to show you how you can write your own SVG graphics library to eliminate (or at least alleviate) the requirement to write raw XML code or raw JAXP DOM code.  This tutorial will introduce you to the beginnings of an SVG graphics library that makes it possible to produce SVG output code simply by making typical Java method calls.

Breakdown between parts of the tutorial

I will present and explain two sample programs in this lesson followed by two additional sample programs in part 2.

The first sample program that I will explain in this lesson will:

  • Create a DOM tree describing a specific graphic image in SVG format
  • Transform the DOM tree into raw XML code
  • Write the raw XML code into an XML file (otherwise known as an SVG file) with an extension of svg

The graphic image can be rendered by manually loading the SVG file into Firefox 1.5.

Lots of tedious programming is required

As you will see, even for a simple graphics image, this program requires the programmer to write many statements consisting of raw JAXP DOM code, which is later transformed into raw XML code.  That is definitely not a fun way to spend your summer vacation.

An SVG graphics library

The second sample program that I will explain in this lesson moves most of the difficult and tedious code into a small SVG graphics library class.  This makes it possible for the application programmer to concentrate on the use of the methods in the graphics library rather than having to concentrate on the nitty-gritty details of SVG and JAXP DOM code. 

The SVG graphics library that I will present and explain is far from complete.  However, it will serve as a proof of concept and will show you a methodology for writing your own SVG graphics library.

A requirement for XHTML files

While you can use Firefox 1.5 to render SVG code that is contained in an SVG file simply by manually loading the SVG file into the browser, as near as I can determine, in order to cause Firefox to render SVG code that is downloaded from a web site, the SVG code must be presented in the form of an XHTML file.

Not a valid XHTML file
Note that the actual file that will be produced is not a valid XHTML file because the SVG elements are not allowed in a valid XHTML file.  At least, that is the result indicated by attempting to validate the file at http://validator.w3.org/file-upload.html.
One of the programs that I will explain in part 2 of this tutorial will create a DOM tree describing the SVG code for a particular graphic image and then transform it into SVG code that is wrapped in a file that would otherwise be a valid XHTML file.

A useful capability

The capability demonstrated by the program described above will be useful for the creation of static XHTML files containing SVG graphics that you may want to post on your web site for downloading by your clients.

The program will also be useful as a precursor to creating inline SVG code in a servlet and to cause that SVG code to be rendered in a Firefox browser that accesses the servlet.  That will be the purpose of a servlet program that I will also present and explain in part 2 of this tutorial.

What about internal references to SVG files?

A third option is to create an SVG file stored on a web server and then to reference that file for downloading from within an XHTML file.  Presumably, the SVG file could be a static file, or could be a temporary file that is created dynamically by a servlet immediately before the XHTML code is sent from the servlet to the client.

So far, I have been unable to get this to work, but my problems seem to have more to do with server administration issues than with Java code, SVG code, or XML code.  Maybe I will get those issues resolved and can show you how to do that in part 3 of this tutorial, (which is not currently on my list of things to do).

The basic image

Figure 1 shows the basic image that I will be working with in this tutorial.

Figure 1. The basic image.

This image consists of an ellipse with a blue border.  The thickness of the border is two pixels.  A circle without a border is placed inside the ellipse.

The fill color for the ellipse is a color gradient that goes from yellow on the left to red on the right.  The fill color for the circle is a color gradient that goes from green on the left to blue on the right.  In both cases, the starting and ending points for the gradient are at the left and right edges of the graphic object being filled.

Horizontally compressed color gradient

Figure 2 shows a somewhat different take on the same basic image.

Figure 2. Image with horizontally compressed gradient.

Figure 2 shows the same image as Figure 1, except that in Figure 2, the gradient begins twenty-five percent of the way across the ellipse going from left to right and ends seventy-five percent of the way across.  Thus, the left one-fourth of the ellipse is solid yellow and the right one-fourth is solid red.  The color gradient progresses from yellow to red between these two points.

Won't use this image

Other than to show you that this is possible using SVG color gradients, I won't be using the version of the image shown in Figure 2 in this tutorial.  However, at an appropriate point, I will explain the code changes that were required to produce the image shown in Figure 2.

When I get into the use of XHTML files in part 2 of this tutorial, I will also add a containing box and some text to the image shown in Figure 1.

Why bother?

At this point, you may be wondering why anyone would bother with SVG image files when they could be using more conventional bitmap image files such as JPEG files and GIF files.  There are at least two good reasons why it may be attractive to use SVG in place of bitmaps:

  • Scalability
  • Bandwidth

Scalability

Once an image has been committed to a bitmapped image format such as GIF or JPEG, the ability to scale the image to make it larger is greatly impaired.  In particular, if you were to attempt to enlarge the typical bitmapped icons that you see on your computer's desktop, you would see that they become very grainy when enlarged.  While it may be possible to do some sort of interpolation to decrease the graininess, bitmapped images were never intended to be enlarged and attempts to enlarge bitmapped images always seem to be marginal at best.

On the other hand, SVG files are designed to be displayed at any scale with little or no loss of quality.  Hence the name Scalable Vector Graphics.

Bandwidth

As an experiment, I cropped the JPEG image shown in Figure 1 down to the smallest rectangle that would contain the ellipse.  The result is shown in Figure 3.  (As you can see, I actually cropped it a little too much and clipped off part of the border at the top.) 

Figure 3. A cropped version of Figure 1.

After cropping and saving the image, (despite the fact that JPEG uses a lossy compression algorithm that degrades the quality of the image), the size of the JPEG file shown in Figure 3 was still 3,534 bytes.  The SVG file required to produce the image, on the other hand, was only 604 bytes.  Therefore, for this example, the bandwidth required to download or otherwise transmit the JPEG image file was more than six times greater than the bandwidth required to download the SVG file.  Add this to the fact that lossy JPEG compression degrades the quality of the image and bandwidth considerations also stand out as a good reason to use SVG coding instead of bitmapped images.

General background information

Java 2D API versus SVG

Programming to produce images using the Java 2D API is completely different from programming to produce images using the SVG.  There are major differences in at least the following categories:

  • Specifications
  • File format

Java 2D API specifications

The "Java 2D API Specification" (see Resources) and its associated documentation constitutes a "How To" manual for writing programs that will produce certain graphic images on the computer screen when a Java program has been compiled and executed.  For example, the documentation for the Ellipse2D class tells you everything that you need to know to instantiate and configure an object of the Ellipse2D class.  The assumption is that you will instantiate and configure such as object as part of a larger overall program.  Then when you compile and execute the program using the Java virtual machine, a visual rendering of the ellipse will appear on the screen.

An SVG specification example
Section 9.4 The 'ellipse' element tells you what must be contained in the XML data if you want that data to be capable of being rendered in such a way as to cause an ellipse to appear on the screen.
The SVG specification

On the other hand, the "Scalable Vector Graphics (SVG) 1.1 Specification" (see Resources) is not a "How To" manual.  Rather, it is something of a "What to Produce" manual.  In other words, it doesn't tell you how to do anything.  Instead, it tells you what you must produce in the way of XML data if you want to be able to use that data to cause certain graphic images to be displayed by an SVG-capable rendering engine. 

Few if any assumptions

The SVG specifications make no assumptions as to the program that will be used to render the XML code into visual graphic images.  Also, they make no assumptions regarding the display medium on which those images will be rendered. The display medium could be paper, it could be a computer screen or a PDA screen, or probably could even be a hologram.

Creating SVG/XML code
If you are a glutton for punishment, you can create the code manually using a simple text editor.
No programming or rendering instructions

Furthermore, the SVG specifications don't tell you how to write the program that will be used to produce the required SVG/XML output.  In fact, the specifications make no assumptions as to what programming environment will be used to write a program that can produce the required SVG/XML output.

What about the SVG rendering engine?

The SVG specifications provide no instructions regarding the use of a particular programming environment to write a program that will render the SVG/XML code into visual graphic images.  Rather, the specifications assume that you can figure out on your own how to write the code to produce the required SVG/XML output, and that you have access to a program that can reliably render that code on your desired display medium.

The bottom line regarding SVG

The bottom line is that the SVG specifications simply tell you what must be contained in the SVG/XML data in order to cause an SVG-capable rendering engine to produce the expected graphic images on the required display medium.

File format

Now let's consider the differences in the file formats required to produce images for the two approaches.

Java files

If you write and compile a Java program that uses the Java 2D API to produce graphic output, the instructions for producing that output are integrated into the bytecode file(s) that are used by the virtual machine to control the overall behavior of the program.  That behavior causes your images to be rendered on the computer screen (or possibly on a printer, a PDA screen, a cell phone, etc.).  Some of those bytecode files are produced by compiling the source code for your program.  Other bytecode files are contained in the Java class libraries, having been placed there by the folks at Sun.

No single data file

The important point is that there is not a single identifiable data file that represents the image.  Information representing the image is integrated into a lot of other information that determines the overall behavior of the program.  There are probably very few people in the world that can examine the data in those files and make any sense out of it with regard to the graphic images that it will produce.

SVG files

SVG data files on the other hand are totally transparent.  They are simply XML files, written in plain text according to the SVG specifications.  They constitute a specific dialect of XML.

A human SVG rendering engine.
While it probably wouldn't be a lot of fun, a technical person with a reasonable amount of drawing talent and a few drawing tools (compass, straightedge, measuring scale, black and colored pencils, etc.) could probably function as an SVG rendering engine and render the data in an SVG file onto paper.
Anyone who can read the English language can read the contents of an SVG file.  Persons with reasonable technical skills can then compare what they find there with the SVG specifications and pretty well determine what kind of graphic output will be produced when the file is rendered. 

Thus, the contents of an SVG file consist primarily of the instructions necessary to tell a rendering engine how to draw the image.  In fact, someone who understands the particular SVG dialect of XML could use a text editor to modify the SVG/XML data to cause the rendering engine to produce a totally different image from the one originally described by the SVG/XML data.

Discussion and sample code

As mentioned earlier, I will present and explain two sample programs in this lesson followed by two additional sample programs part 2 of this series.

XML, DOM trees, JAXP, etc.
In case you are unfamiliar with XML, DOM trees, JAXP and such, I recommend that you take advantage of the many tutorials that I have written on those topics.  You will find links to those tutorials in the Resources section near the end of this lesson.
Svg01

The first sample program named Svg01 will create a DOM tree describing the graphic image shown in Figure 1 in SVG format.  Then it will transform the DOM tree into raw XML code and write the raw XML code into an XML file (otherwise known as an SVG file) named junk.svg.  The graphic image can be rendered by manually loading the SVG file into Firefox 1.5.

As you will see, this first program requires quite a bit of difficult and tedious programming.

Svg02

The second sample program named Svg02 moves most of the difficult and tedious code into a small SVG graphics library of my own design.  Having the graphics library available makes it possible for the application programmer to concentrate on the use of the methods in the library rather than having to concentrate on the nitty-gritty details of SVG, XML, or JAXP DOM coding. 

Completing the graphics library
Perhaps one of the readers of this tutorial will pick up where I left off, extend the graphics library to incorporate the complete SVG specification, and publish it for the entire world to use for free.
The SVG graphics library that I will present and explain is far from complete.  However, it will serve as a proof of concept and will show you a methodology for writing your own SVG graphics library.

The Svg01 program

Before getting into the programming details, I want to present and briefly explain the contents of the SVG/XML file produced by the program.  A listing of that code begins in Listing 1.

However, even before getting into that, I want to highlight a few good online resources on the topic.  (You will also find links to these resources in the Resources section so that you can easily find them later).  These resources may be useful in helping you to interpret the SVG specifications.

The article titled Create vector graphics in the browser with SVG by Uche Ogbuji provides numerous examples showing graphic images along with the corresponding raw XML code.

The article titled SVG Tutorial is an excellent resource for understanding how the SVG specifications translate into XML code.

The article titled SVG Basics is another good resource for helping you to associate raw XML code with the graphic images that are produced by a rendering engine on the basis of that code.

Abbreviated SVG/XML code for Figure 1

Now, getting back on topic, Listing 1 shows an abbreviated version of the raw XML code that was rendered in Firefox 1.5 to produce Figure 1.  Much of the raw XML code was omitted from Listing 1 to make it easier to see the overall structure of the document.

Listing 1. Abbreviated SVG/XML code for Figure 1.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<svg height="100%" version="1.1" width="100%" 
  xmlns="http://www.w3.org/2000/svg">

  <defs>
    ...
  </defs>
  
  <g>
    ...
  </g>

</svg>

The XML declaration

The first line in Listing 1 is an XML declaration.  Since this is not intended to be an XML tutorial, I won't attempt to explain its purpose.  Suffice it to say that it probably needs to be there.  I'm sure that if you want to learn more about it, you can use Google to find more material on the topic than you can possibly find the time to read.

The root element

Every XML document requires a root element, which contains all of the other elements.  In this case, the root element is the element named svg shown in Listing 1.

The purpose of the version attribute shown in Listing 1 is probably fairly obvious.  The same is true of the height and width attributes, although the meaning of their values may not be clear.  My recommendation is that you simply experiment with the values for the height and width attributes and you will probably be able to determine for yourself the behavior that they induce.

The remaining element attribute for the svg element shown in Listing 1 is known as a namespace attribute.  The purpose of a namespace attribute is far too complicated for me to try to explain in this lesson.  If you are really interested in its purpose, I'm confident that you will find a large amount of explanatory information on the web.  Otherwise, just accept the fact that it needs to be there.

The defs element

The defs element shown in Listing 1 is simply a container for two elements that I will explain later.  These two elements provide definitions of the two different color gradients that you see in Figure 1.  One color gradient goes from yellow to red and the other color gradient goes from green to blue.  Each gradient definition is given a name, which can be referred to later to cause other graphic objects to be filled using those color gradients.

The g element

Listing 1 also shows an element named g, which serves as a container for the ellipse element and the circle element shown in Figure 1.

Parent-child relationships

In XML terminology, the defs element and the g element are both child elements of the svg element.  From a DOM tree perspective, they are both child nodes of the node in the tree that represents the svg element.  This will be important to understand later when we get into the Java/JAXP DOM tree code that I used to represent the image.

Abbreviated defs element

Listing 2 shows an abbreviated version of the defs element with some of the content of the element deleted for clarity.

Listing 2. Abbreviated defs element.

<defs>
  <linearGradient id="gradientA">
    ...
  </linearGradient>

  <linearGradient id="gradientB">
    ...
  </linearGradient>
</defs>

As you can see from Listing 2, the defs element has two child elements, both of which are linearGradient elements.  At this point we are getting a little closer to something that describes what you see in Figure 1.

Identification attributes for linear gradient elements

The first linearGradient element has an attribute named id with a value of gradientA.  As you will see later, the definition of the ellipse element refers to this id value to cause the ellipse shown in Figure 1 to be filled with the color gradient that is defined in the first linearGradient element.

Similarly, the second linearGradient element shown in Listing 2 has an id attribute value of gradientB.  You will see later that the circle element refers to this id value to cause the circle shown in Figure 1 to be filled with the color gradient that is defined in the second linearGradient element.

One complete linearGradient element

Listing 3 shows the complete linearGradient element for the first linearGradient element in Listing 2.

Listing 3. One complete linearGradient element.

<linearGradient id="gradientA">
  <stop offset="0%" style="stop-color:yellow;"/>
  <stop offset="100%" style="stop-color:red;"/>
</linearGradient>

A different offset attribute value
For the image shown in Figure 2, the offset value for the first stop element was set to 25% resulting in the left one-fourth of the ellipse being solid yellow.  The offset value for the second stop element was set to 75%, causing the right one-fourth of the ellipse to be solid red.
The stop elements

As you can see, the linearGradient element shown in Listing 3 has two child elements, each of which is a stop element.

The offset attribute

The offset attribute of the first stop element defines the point on the left side of the image at which the color begins to change.  This point is defined as a percentage of the total width of the component being filled with a gradient color.  As you can see, I used a value of 0%, specifying that the color should begin changing immediately at the left edge of the ellipse. 

The style attribute

The value of the style attribute in the first stop element defines the beginning color at the left.  As you can see, I set this to yellow causing the left edge of the ellipse in Figure 1 to be yellow.

Attributes of the second stop element

The value of the offset attribute in the second stop element in Listing 3 defines the point at which the color finishes changing.  I set this to 100% causing the color to change all the way to the right edge of the ellipse in Figure 1.

The value of the style attribute in the second stop element defines the ending color.  I set this to red causing the right edge of the ellipse in Figure 1 to be red.

As a result of this definition for a linear gradient, the ellipse, which is filled with color according to this definition, makes a smooth transition from yellow on the left to red on the right in Figure 1.

Another complete linearGradient element

Listing 4 shows the complete version of the second linearGradient element from Listing 2.

Listing 4. Another complete linearGradient element.

<linearGradient id="gradientB">
  <stop offset="0%" style="stop-color:green;"/>
  <stop offset="100%" style="stop-color:blue;"/>
</linearGradient>

The circle in Figure 1 was filled using the definition of gradientB shown in Listing 4.  By now, you should be able to interpret the material in Listing 4 and understand how that definition causes the color of the circle in Figure 1 to transition smoothly from green on the left to blue on the right.

The ellipse and circle elements

Listing 5 shows the complete contents of the element named g from Listing 1.

Listing 5. The ellipse and circle elements.

<g>
  <ellipse cx="110" cy="100" rx="100" ry="40" 
    style="fill:url(#gradientA);
           stroke:rgb(0,0,100);
           stroke-width:2"/>

  <circle cx="110" cy="100" r="30" 
    style="fill:url(#gradientB)"/>
</g>

As you can see, the element named g has two child elements.  One is an ellipse element and the other is a circle element.

The circle element

I will begin the discussion with the circle element because it is the simpler of the two.  The appearance of the circle is determined by the values of the four attributes shown in Listing 5.  For example, the values of the attributes named cx and cy define the location coordinates of the center of the circle, given in pixels relative to the upper-left corner of the white area in Figure 1.

The value of the attribute named r defines the radius of the circle.

The value of the style attribute for the circle in Listing 5 specifies that the circle is to be filled according to the definition of the linearGradient with an id of gradientB shown in Listing 4.

The ellipse element

The ellipse element in Listing 5 is a little more complicated than the circle element.  To begin with, because it is not round, more information is required to define its shape.  The values of the attributes named cx and cy have the same meaning as for the circle.  However, the ellipse doesn't have a single radius attribute.  Rather, the value of the attribute named rx defines the distance from the center to either the left or right end of the ellipse.  Similarly, the value of the attribute named ry defines the distance from the center to either the top or the bottom of the ellipse.

The style attribute of the ellipse element

The style attribute is also more complicated.  The style element is subdivided into three parameters with the following names:

  • fill
  • stroke
  • stroke-width

Each parameter name is separated from its value by a colon.  The three parameters are separated from each other by semicolons.

The fill parameter

The fill parameter has the same meaning as for the circle.  In other words, the fill parameter specifies that the ellipse is to be filled according to the definition of the linearGradient with an id value of gradientA in Listing 4.

Style parameters that define the border on the ellipse

The other two style parameters define the visual characteristics of the border on the ellipse as shown in Figure 1.

Alternative ways to specify color.
I could also have specified the color in Listing 5 by its common name, but I wanted to illustrate that it is possible to mix red, green, and blue to produce custom colors for which there is no name.  In theory, it is possible to specify about sixteen million different colors using this approach.
The stroke parameter defines the color of the border to be blue, using percentage contributions of red, green, and blue in that order from left to right within the parentheses.  A value of 0 specifies no contribution of a particular color while a value of 100 specifies the maximum possible contribution of the color.  The result is a mixture of the contributions of red, green, and blue.  In this case, there was zero contribution for red, zero contribution for green, and 100 percent contribution for blue.

The stroke-width parameter specifies the thickness of the border.  In this case, I caused the border to have a thickness of two pixels.

Putting it all together

Putting all the pieces together, Listing 6 shows the complete contents of the SVG file used to render the image in Figure 1.

Listing 6. The complete contents of the SVG/XML file.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg height="100%" version="1.1" width="100%" 
  xmlns="http://www.w3.org/2000/svg">

<defs>
<linearGradient id="gradientA">
<stop offset="0%" style="stop-color:yellow;"/>
<stop offset="100%" style="stop-color:red;"/>
</linearGradient>

<linearGradient id="gradientB">
<stop offset="0%" style="stop-color:green;"/>
<stop offset="100%" style="stop-color:blue;"/>
</linearGradient>
</defs>

<g>
<ellipse cx="110" cy="100" rx="100" ry="40" 
  style="fill:url(#gradientA);
         stroke:rgb(0,0,100);
         stroke-width:2"/>

<circle cx="110" cy="100" r="30" 
  style="fill:url(#gradientB)"/>
</g>

</svg>

A plain text file

As you can see, an SVG file is a plain text file, which you could produce with a text editor if you had a reason to do so.  Also, if you knew what you were doing, you could use a text editor to modify the file and thus cause the modified file to render into a different image.

Just a bunch of characters

Unlike a JPEG or GIF bitmapped file, the contents of the SVG file shown in Listing 6 do not constitute an image.  Rather, those contents simply provide the instructions by which an SVG-capable rendering engine (such as Firefox 1.5) can produce an image.  Without the rendering engine, the contents of the SVG file are worthless.  For example, if you were to load the SVG file shown in Listing 6 into IE 6 without first installing the SVG plug-in, all you would see would be a very nice indented and color-coded listing of the XML text shown in Listing 6.  You would not see the image shown in Figure 1, which was produced by loading the SVG file into Firefox 1.5.

Loading the SVG file into IE 6

In fact, Figure 4 shows the result of loading the SVG/XML file into an IE 6 browser for which the SVG plug-in hasn't been installed.  Contrast the image in Figure 4 with the image in Figure 1, and you will understand what I mean by the importance of an SVG rendering engine.

Figure 4. Viewing the SVG/XML file in IE 6.

Now that you know all about the SVG/XML output produced by the program named Svg01, it's time to take a look at the program in order to understand how it produces that output.

Program description for Svg01

The purpose of this program is to create a DOM tree describing a specific graphic image in SVG format, to transform it into raw XML code, and to write that raw XML code out into an XML file named junk.svg.

Along the way, the DOM is displayed in XML format on the command-line screen.  Note, however that the output on the command-line screen is all on a single line with no line breaks or indentation.  Therefore, it is useful only for test and debug purposes.

Portions of this program were based on the earlier program named Xslt01, which I explained in lesson number 2202 titled "Getting Started with Java JAXP and XSL Transformations (XSLT)" (see Resources).

The output file produced by this program can be rendered by loading it into Firefox 1.5.  The program was tested using J2SE 5.0, Firefox 1.5.0.8, and WinXP.

I will explain this program in fragments.  A complete listing of the program is provided in Listing 26 near the end of the lesson.

Beginning of the class for Svg01

Listing 7 shows the beginning of the class named Svg01.

Listing 7. Beginning of the class for Svg01.

public class Svg01 {

  public static void main(String[] args){
    try{
      DocumentBuilderFactory factory = 
                     DocumentBuilderFactory.newInstance();

      DocumentBuilder builder = 
                             factory.newDocumentBuilder();
      Document document = builder.newDocument();
      document.setXmlStandalone(false);

Create a DOM tree

The purpose of the code in Listing 7 is to begin the process of creating a DOM tree that represents the XML code that will be used to render the image shown in Figure 1.  The code in Listing 7 was explained in my earlier lesson number 2200 titled "Java API for XML Processing (JAXP), Getting Started" (see Resources).  Therefore, I won't bore you by repeating that explanation here.  You should refer to the explanation in the earlier lesson if you don't understand the code in Listing 7.

Note that the code in Listing 7 ends up having created an object of the type Document, and having saved a reference to that object in a reference variable named document.  The Document object represents the entire XML document. Conceptually, it is the root of the document tree, and provides the primary access to the document's data.

Create root node named svg

Listing 8 creates the root node named svg and appends it to the document node.  Thus, svg is a child node of document.

Listing 8. Create root node named svg.

      Element svg = 
                   (Element)document.createElement("svg");
      document.appendChild(svg);

      //Set some attributes on the root node that are
      // required for proper rendering.
      svg.setAttribute("width","100%");
      svg.setAttribute("height","100%");
      svg.setAttribute("version","1.1");
      svg.setAttribute(
                    "xmlns","http://www.w3.org/2000/svg");

The node named svg in Listing 8 corresponds directly to the element named svg shown in Listing 1.  Later on, when the DOM tree is transformed to raw XML code, this node will cause the svg element to be contained in the output SVG/XML code.

Set node attribute values on the svg node

In addition to creating the svg node, the code in Listing 8 also sets some attribute values on the node that are required for proper rendering later.  These attribute values correspond directly to the element attributes shown in Listing 1.

Create the defs node

Listing 9 creates a node named defs that will eventually contain nodes that define two different color gradient schemes. The defs node corresponds directly to the element named defs shown in Listing 1, and is appended onto the svg node.  Therefore, defs is a child node of the node named svg.

Listing 9. Create the defs node.

      Element defs = 
                  (Element)document.createElement("defs");
      svg.appendChild(defs);

As you saw in Listing 2, a pair of linearGradient nodes will be created as child nodes of the defs node.  The two linearGradient nodes will be identified as gradientA and gradientB.  They will be referred to later to specify the fill colors for an ellipse node and a circle node.

Create a linearGradient node

Listing 10 creates the first of two linearGradient nodes (corresponding to the linearGradient elements shown in Listing 2), and appends the node to the defs node.

Listing 10. Create a linearGradient node.

      Element linearGradientA = 
        (Element)document.createElement("linearGradient");
      defs.appendChild(linearGradientA);

      linearGradientA.setAttribute("id","gradientA");

As explained earlier, this node is given an attribute node named id with a value of gradientA.

Create the first stop node

Listing 11 creates a stop node corresponding to the first stop element shown in Listing 3.  This stop node is appended to the linearGradient node, thus becoming a child node of the linearGradient node.

Listing 11. Create the first stop node.

      Element stopA = 
                  (Element)document.createElement("stop");
      stopA.setAttribute("offset","0%");
      stopA.setAttribute("style","stop-color:yellow;");

      linearGradientA.appendChild(stopA);

Listing 11 also sets two attribute values that belong to the stop node.  As you can see, the attribute values match the element attribute values for the first stop element shown in Listing 3.

This stop node, along with the stop node shown in Listing 12 causes the linearGradient node to provide a linear color gradient making a smooth transition from yellow to red, going from left to right as shown in Figure 1.

Create the second stop node

Listing 12 creates a stop node corresponding to the second stop element shown in Listing 3, and appends the stop node to the linearGradient node.

Listing 12. Create the second stop node.

      Element stopB = 
                  (Element)document.createElement("stop");
      stopB.setAttribute("offset","100%");
      stopB.setAttribute("style","stop-color:red;");

      linearGradientA.appendChild(stopB);

Create and populate the other linearGradient node

In similar fashion, the code in Listing 13 creates a linearGradient node corresponding to the linearGradient element shown in Listing 4.  The linearGradient node is given two stop nodes as child nodes, corresponding to the two stop elements shown in Listing 4.

Listing 13. Create and populate the other linearGradient node.

      //Now define linearGradientB, which provides a
      // linear color gradient from green to blue going
      // from left to right. Append it to the defs node.
      Element linearGradientB = 
        (Element)document.createElement("linearGradient");
      defs.appendChild(linearGradientB);
      linearGradientB.setAttribute("id","gradientB");
      
      Element stopC = 
                  (Element)document.createElement("stop");
      stopC.setAttribute("offset","0%");
      stopC.setAttribute("style","stop-color:green;");
      linearGradientB.appendChild(stopC);
      
      Element stopD = 
                  (Element)document.createElement("stop");
      stopD.setAttribute("offset","100%");
      stopD.setAttribute("style","stop-color:blue;");
      linearGradientB.appendChild(stopD);

Create the ellipse and circle nodes

Listing 14 creates a g node and makes it a child of the svg node.  This g node corresponds to the g element shown in Listing 5.

Also corresponding to Listing 5, the code in Listing 14 creates an ellipse node and a circle node and makes them child nodes of the g node.  These two nodes correspond to the ellipse and circle elements shown in Listing 5.

Listing 14. Create the g node, the ellipse node, and the circle node.

      //Create a node named g that contains an ellipse
      // and a circle.  Append it to the svg node.
      Element gNode = 
                     (Element)document.createElement("g");
      svg.appendChild(gNode);

      //Now create an ellipse with a blue border having
      // a thickness of two pixels. Color the ellipse in
      // the yellow-red style defined by linearGradientA.
      // Append the ellipse node to the g node.
      Element ellipseA  = 
               (Element)document.createElement("ellipse");
      gNode.appendChild(ellipseA);
      ellipseA.setAttribute("cx","110");
      ellipseA.setAttribute("cy","100");
      ellipseA.setAttribute("rx","100");
      ellipseA.setAttribute("ry","40");
      ellipseA.setAttribute("style",
                            "fill:url(#gradientA);"
                            + "stroke:rgb(0,0,100);"
                            + "stroke-width:2");
      
      //Now place a circle at a location that will make
      // it appear that the circle is physically inside
      // the ellipse.  Note however that the circle is
      // not a child node of the ellipse.  They simply
      // occupy the same space in the display.  Color the
      // circle with the green-blue style defined by
      // linearGradientB. Append the circle node to the
      // g node.
      Element circleA  = 
                (Element)document.createElement("circle");
      gNode.appendChild(circleA);
      circleA.setAttribute("cx","110");
      circleA.setAttribute("cy","100");
      circleA.setAttribute("r","30");
      circleA.setAttribute("style",
                            "fill:url(#gradientB)");

By now, the usage of the Java code to create the DOM tree should be sufficiently familiar to you that no explanation beyond the embedded comments in Listing 14 should be required.

The DOM tree is complete

At this point, the construction of the DOM tree representing the XML code required to produce the image shown in Figure 1 has been completed.  If you are new to this process, you may be wondering what the advantage of a DOM tree is, since more Java code is required to construct it that is reflected in the XML code that it will be used to produce.

Basically, a DOM tree is a generalized way to represent an XML document.  Once you have the tree, you can write code to perform a variety of modifications on the tree, such as moving child nodes among parents, etc.  You can also transform the DOM tree into a variety of different output formats, including raw XML, HTML, PDF, etc.  In this case, we will simply transform the DOM tree into a raw XML output file to be rendered by the SVG rendering engine in Firefox 1.5.  (For test and debug purposes, we will also transform the DOM tree into a screen output showing the raw XML.)

The remaining program code

The remaining program code is shown in Listing 15.  Most of the remaining code is used to transform the DOM tree into the raw XML screen display and raw XML output file described above.

Listing 15. The remaining program code.

      //Get a TransformerFactory object.
      TransformerFactory xformFactory = 
                         TransformerFactory.newInstance();
           
      //Get an XSL Transformer object.
      Transformer transformer = 
                            xformFactory.newTransformer();
      
      //This statement is new to this lesson.  It sets
      // the standalone property in the XML declaration,
      // which appears as the first line of the output
      // file.
      transformer.setOutputProperty(
                              OutputKeys.STANDALONE,"no");
      
      //Get a DOMSource object that represents the
      // Document object
      DOMSource source = new DOMSource(document);

      //Get a StreamResult object that points to the
      // screen. Then transform the DOM sending XML to
      // the screen.
      StreamResult scrResult = 
                             new StreamResult(System.out);
      transformer.transform(source, scrResult);

      //Get an output stream for the output file.
      PrintWriter outStream = new PrintWriter("junk.svg");

      //Get a StreamResult object that points to the
      // output file.  Then transform the DOM sending XML
      // to the file
      StreamResult fileResult = 
                              new StreamResult(outStream);
      transformer.transform(source,fileResult);
    }//end try block

    catch(Exception e){
      e.printStackTrace(System.err);
    }//end catch

  }// end main()
  //----------------------------------------------------//
  
}// class Svg01

Explained in an earlier lesson

Almost all of the code in Listing 15 was explained in my earlier lesson titled "Getting Started with Java JAXP and XSL Transformations (XSLT)" (see Resources) in conjunction with the program named Xslt01.  Therefore, I won't bore you with another explanation of the same code.

The end of the program

Listing 15 also signals the end of the main method and the end of the class named Svg01.  When the program terminates, it will have produced an output file in the current directory named junk.svg.  You can load that file into your Firefox 1.5 browser, and you should see a graphic output that matches the image in Figure 1.

Or, you should be able to load the file into any other SVG rendering engine, such as IE 6 with the SVG plug-in installed, and you should see a graphic output that matches the image shown in Figure 1.

The Svg02 program

A lot of programming was required

By now you have probably realized that a lot of programming was required to write the program named Svg01, simply to produce the small XML file shown in Listing 6.  You may have concluded that there must be an easier way.  Although it requires more up-front programming effort, there is an easier way.

An easier way

If you will be doing very much of this type of programming, one easier way is to create a reusable SVG graphics library that will alleviate most of the tedious programming effort required to produce the SVG files that represent your images.  I will use the program named Svg02 to illustrate the beginnings of just such an SVG graphics library of my own design.  The major elements in the graphics library correspond to the major graphic elements in the SVG specification.

I also want to point out that most of the code shown in Listing 7 and Listing 15 is completely reusable from one graphic image to the next.  Therefore, I also moved most of that code to methods in the library.  These methods can be used over and over again with no requirement to rewrite the code each time the SVG code for a new graphic image is required.

Much more work will be required

Quite a lot of effort will be required to finish the graphic library and to bring it into full compliance with the SVG specifications.  However, once the library is available it can be used to greatly reduce the amount of programming effort required to produce a new graphic image.  For example, as you will see later, exclusive of the code in the new graphics library, the program named Svg02 produces the same SVG/XML output file as the program named Svg01 with only the following nine method calls:

  1. getDocument part of required setup
  2. getRootNode to create the root node
  3. simpleElement for the node named defs
  4. makeLinearGradient for gradientA
  5. makeLinearGradient for gradientB
  6. simpleElement for the node named g
  7. svgEllipse to create the ellipse
  8. svgCircle to create the circle
  9. transformTheDom to write the output file

Of the nine methods, only seven are required for the purpose of creating nodes that describe the graphic image.  The remaining two are required to do some required setup and to write the output file.

Description of the program

This program is an update of the program named Svg01.  The purpose of this update is to move most of the difficult and tedious code into a small SVG graphics library class named SvgGraphics so that the application programmer can concentrate on the characteristics of the required graphic images rather than having to concentrate on the details of SVG and JAXP/DOM programming.

Also, for convenience, the library contains two methods that are used to execute code that is the same regardless of the graphic image being produced.

The library is not complete

As mentioned earlier, the SVG graphics library is far from complete.  In its current state, the library provides methods to produce the following types of DOM tree nodes:

  • A simple element with no attributes.
  • A linear gradient element.
  • An ellipse.
  • A circle.

Although a great deal more programming effort would be required to write a complete SVG graphics library, this program demonstrates proof of concept.  The program illustrates an approach that could be used to create a graphics library that supports most of the features of the SVG specification.

Create and transform a DOM tree

This program creates a DOM tree describing the graphic image shown in Figure 1 in SVG format.  Then it transforms the DOM tree into raw XML code and writes that code into an output XML file named junk.svg.  Along the way, the DOM is displayed in raw XML format on the command-line screen.

The output file produced by this program can be rendered by loading it into Firefox 1.5.

The program was tested using J2SE 5.0, Firefox v1.5.0.8, and WinXP.

Will discuss in fragments

As is my custom, I will explain this program by discussing it in fragments.  A complete listing of the program is provided in Listing 27 near the end of the lesson.

As before, the program begins by creating a DOM tree that represents the XML code that can be rendered to produce the image shown in Figure 1.  The program and the main method begin in Listing 16.

Listing 16. Beginning of the Svg02 class.

public class Svg02{

  public static void main(String[] args){
    //Get the Document object.
    Document document = SvgGraphics.getDocument();

Listing 16 calls a convenience method in the graphics library to get a reference to an object of type Document(You can view all of the methods in the graphics library in Listing 27.)  The code in the method is essentially the same as that used in the previous program.  If you understood the code in Listing 7, you should have no difficulty understanding the code in this new method.  Therefore, this code shouldn't require further explanation.

Create the root node named svg

Listing 17 calls the graphics library method named getRootNode to

  • Create the root node named svg
  • Set some attribute values on the new node
  • Make it a child node of the Document object

Listing 17. Create the root node named svg.

    //Create the root node named svg and append it
    // to the document.
    Element svg = SvgGraphics.getRootNode(document,
                                          "100%",
                                          "100%",
                                          "absolute",
                                          "0",
                                          "0");

If you understood the code in Listing 8, you should have no difficulty understanding the code for the method named getRootNode.  Therefore, I won't explain it further at this point in the lesson.

Create the node named defs

Listing 18 calls the graphics library method named simpleElement to create a node named defs.  This node will be the parent for a pair of linear gradient definition nodes.

Listing 18. Create the node named defs.

    Element defs = SvgGraphics.simpleElement(
                                   document,svg,"defs");

The method named simpleElement is shown in its entirety in Listing 27.  This method calls the createElement method to create an element node (having no attributes) of the type given by the third incoming parameter ("defs" in this case).  Then it appends the new node to the node specified by the second parameter (svg in this case) and returns a reference to the new node.

Create the first linearGradient node

Listing 19 calls the graphics library method named makeLinearGradient to create a new linearGradient node, which will be identified as gradientA.

Listing 19. Create the first linearGradient node.

    Element linearGradientA = 
               SvgGraphics.makeLinearGradient(
                 document,            //this document
                 defs,                 //parent
                 "gradientA",         //id
                 "0%",                //beginning point
                 "stop-color:yellow;",//beginning color
                 "100%",              //ending point
                 "stop-color:red;");  //ending color

This method call defines a linearGradient node that provides a linear color gradient that transitions from yellow to red going from left to right. The method call also establishes the beginning and ending points of the gradient along with the beginning and ending colors.

The method named makeLinearGradient is shown in its entirety in Listing 27.  I'm sure that by now you are getting tired of me saying this, but I will say it at least one more time.  If you understood the code in Listing 10, Listing 11, and Listing 12, you should have no difficulty understanding the code in the method named makeLinearGradient.  Therefore, I won't explain it further.

Create the second linearGradient node

Listing 20 calls the makeLinearGradient method to create the second linearGradient node.

Listing 20. Create the second linearGradient node.

    Element linearGradientB = 
                SvgGraphics.makeLinearGradient(
                  document,           //this document
                  defs,                //parent
                  "gradientB",        //id
                  "0%",               //beginning point
                  "stop-color:green;",//beginning color
                  "100%",             //ending point
                  "stop-color:blue;");//ending color

This method call corresponds to Listing 13 in the previous program, providing a linear gradient that transitions from green on the left to blue on the right.

Create the g node

Listing 21 makes another call to the simpleElement method to create the g node.  This will be the parent node for an ellipse node and a circle node, and corresponds to the first two executable statements in Listing 14 from the previous program.

Listing 21. Create the g node.

    Element g = SvgGraphics.simpleElement(
                                        document,svg,"g");

Create the ellipse node

Listing 22 calls the graphics library method named svgEllipse to create an ellipse node that represents the ellipse shown in Figure 1.

Listing 22. Create the ellipse node.

    //Create an ellipse with a blue border that is two
    // pixels thick. Fill the ellipse with the
    // yellow-red  gradient defined by linearGradientA.

    //Begin by defining the style for the ellipse
    String ellipseStyle = 
          "fill:url(#gradientA);" //Fill using gradientA
          + "stroke:rgb(0,0,100);"//Border and its color
          + "stroke-width:2";     //Border width

    SvgGraphics.svgEllipse(document,//This document
                           g,//Owner
                           110,//Center x-coordinate
                           100,//Center y-coordinate
                           100,//Width
                           40, //Height
                           ellipseStyle);

To make it somewhat easier to format the code to fit into this narrow publication format, the code in Listing 22 begins by defining a String that specifies the style for the ellipse.  A reference to that string is passed as the seventh parameter to the svgEllipse method that creates the node and causes it to become a child node of the g node.

Create a circle node

Listing 23 calls the graphics library method named svgCircle to create a node that represents the circle in Figure 1, and appends the new node to the g node.

Listing 23. Create a circle node.

    //Place a circle in a location that will make it
    // appear to be inside the ellipse. Specify a 
    // style that will fill it with the green-blue
    // gradient defined by linearGradientB.
    SvgGraphics.svgCircle(document,//This document
                          g,//Owner
                          110,//Center x-coordinate
                          100,//Center y-coordinate
                          30, //Radius
                          "fill:url(#gradientB)");

In this case, the string specifying the style was rather short, so I simply defined it as part of the parameter list in the method call.

Transform the DOM and write the output file

The DOM tree that represents the raw XML code required to produce the image shown in Figure 1 is now complete.  Listing 24 invokes the library method named transformTheDom to transform the DOM tree into raw XML code, write that code onto the command-line screen, and write that code into the output file named junk.svg.

Listing 24. Transform the DOM and write the output file.

    SvgGraphics.transformTheDom(document,"junk.svg");
  }// end main()
}// class Svg02

The code in the method named transformTheDom is essentially the same as the code in Listing 15 from the previous program.  If you understood that code, you should have no difficulty understanding the code in the method named transformTheDom.

Listing 24 also signals the end of the main method and the end of the class named Svg02.

Run the program

I encourage you to copy the code from Listing 26 and Listing 27 into your text editor, compile it, and execute it.  Then view the resulting SVG files in Firefox 1.5, or some other suitable SVG rendering engine.  Experiment with the code, making changes, and observing the results of your changes.

Above all, enjoy the process. Programming can be fun if you approach it with a positive attitude.

Summary

This lesson is part 1 of a two-part series designed to teach you how to write servlets to produce SVG code that will be rendered in graphic form by an SVG-compatible browser.

In this lesson, I showed you how to write Java code to produce the raw XML code necessary to produce images using an SVG rendering engine. 

First I showed you how to do it the hard way.  Then I introduced the beginnings of an SVG graphics library that can be used to eliminate (or at least alleviate) the requirement to write raw XML code or to write raw JAXP DOM code.  The SVG graphics library makes it possible to produce SVG output files simply by making typical Java method calls.

What's next?

Part 2 of the series will show you how to take what you have learned in this lesson and apply it to the generation of XHTML files containing in-line SVG/XML code.  Then it will teach you how to apply that knowledge to the writing of servlets that produce XHTML output containing in-line SVG/XML code.

A future lesson will teach you how to write servlets that produce XHTML output containing references to external SVG files in addition to in-line SVG/XML code.

Complete program listings

Complete listings of the programs discussed in this lesson are shown in Listing 25 through Listing 27 below.

Listing 25. Output XML file produced by both programs.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg height="100%" version="1.1" width="100%" 
  xmlns="http://www.w3.org/2000/svg">

<defs>
<linearGradient id="gradientA">
<stop offset="0%" style="stop-color:yellow;"/>
<stop offset="100%" style="stop-color:red;"/>
</linearGradient>

<linearGradient id="gradientB">
<stop offset="0%" style="stop-color:green;"/>
<stop offset="100%" style="stop-color:blue;"/>
</linearGradient>
</defs>

<g>
<ellipse cx="110" cy="100" rx="100" ry="40" 
  style="fill:url(#gradientA);
         stroke:rgb(0,0,100);
         stroke-width:2"/>

<circle cx="110" cy="100" r="30" 
  style="fill:url(#gradientB)"/>
</g>

</svg>

Listing 26. Java code for program Svg01.

/*File Svg01.java
Copyright 2006 R.G.Baldwin

The purpose of this program is to create a DOM tree 
describing a specific graphic image in SVG format and to 
write it out into an XML file named junk.svg. Along the 
way, the DOM is displayed in XML format on the 
command-line screen. Note, however that the output on the 
command-line screen is all on a single line with no line 
breaks or indentation. Therefore, it is useful only for 
test and debug purposes. 

Portions of this program are based on the earlier program 
named Xslt01.java, which was explained in lesson 
number 2202 named "Getting Started with Java JAXP and 
XSL Transformations (XSLT)".

The output file produced by this program can be rendered 
by loading it into Firefox 1.5.

Tested using J2SE 5.0, Firefox 1.5.0.8, and WinXP.
*********************************************************/

import javax.xml.parsers.*;
import org.w3c.dom.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;

public class Svg01 {

  public static void main(String[] args){
    try{
      //Begin by creating a DOM tree that represents
      // the XML code that will render to produce the
      // image of interest.
      DocumentBuilderFactory factory = 
                     DocumentBuilderFactory.newInstance();

      DocumentBuilder builder = 
                             factory.newDocumentBuilder();
      Document document = builder.newDocument();
      document.setXmlStandalone(false);

      //Create the root node named svg and append it to
      // the document.
      Element svg = 
                   (Element)document.createElement("svg");
      document.appendChild(svg);
      
      //Set some attributes on the root node that are
      // required for proper rendering.
      svg.setAttribute("width","100%");
      svg.setAttribute("height","100%");
      svg.setAttribute("version","1.1");
      svg.setAttribute(
                    "xmlns","http://www.w3.org/2000/svg");
      
      //Create a node named defs that contains the
      // definitions of two different gradient coloring
      // schemes. The definitions are identified as
      // linearGradientA and linearGradientB.  They will
      // be referred to later to specify the fill colors
      // for an ellipse and a circle.
      Element defs = 
                  (Element)document.createElement("defs");
      svg.appendChild(defs);
      
      //Now define linearGradientA, which provides a
      // linear gradient from yellow to red going from
      // left to right and append it to the defs node.
      Element linearGradientA = 
        (Element)document.createElement("linearGradient");
      defs.appendChild(linearGradientA);
      linearGradientA.setAttribute("id","gradientA");
      
      Element stopA = 
                  (Element)document.createElement("stop");
      stopA.setAttribute("offset","0%");
      stopA.setAttribute("style","stop-color:yellow;");
      linearGradientA.appendChild(stopA);
      
      Element stopB = 
                  (Element)document.createElement("stop");
      stopB.setAttribute("offset","100%");
      stopB.setAttribute("style","stop-color:red;");
      linearGradientA.appendChild(stopB);
      
      //Now define linearGradientB, which provides a
      // linear color gradient from green to blue going
      // from left to right. Append it to the defs node.
      Element linearGradientB = 
        (Element)document.createElement("linearGradient");
      defs.appendChild(linearGradientB);
      linearGradientB.setAttribute("id","gradientB");
      
      Element stopC = 
                  (Element)document.createElement("stop");
      stopC.setAttribute("offset","0%");
      stopC.setAttribute("style","stop-color:green;");
      linearGradientB.appendChild(stopC);
      
      Element stopD = 
                  (Element)document.createElement("stop");
      stopD.setAttribute("offset","100%");
      stopD.setAttribute("style","stop-color:blue;");
      linearGradientB.appendChild(stopD);
      
      //Create a node named g that contains an ellipse
      // and a circle.  Append it to the svg node.
      Element gNode = 
                     (Element)document.createElement("g");
      svg.appendChild(gNode);

      //Now create an ellipse with a blue border having
      // a thickness of two pixels. Color the ellipse in
      // the yellow-red style defined by linearGradientA.
      // Append the ellipse node to the g node.
      Element ellipseA  = 
               (Element)document.createElement("ellipse");
      gNode.appendChild(ellipseA);
      ellipseA.setAttribute("cx","110");
      ellipseA.setAttribute("cy","100");
      ellipseA.setAttribute("rx","100");
      ellipseA.setAttribute("ry","40");
      ellipseA.setAttribute("style",
                            "fill:url(#gradientA);"
                            + "stroke:rgb(0,0,100);"
                            + "stroke-width:2");
      
      //Now place a circle at a location that will make
      // it appear that the circle is physically inside
      // the ellipse.  Note however that the circle is
      // not a child node of the ellipse.  They simply
      // occupy the same space in the display.  Color the
      // circle with the green-blue style defined by
      // linearGradientB. Append the circle node to the
      // g node.
      Element circleA  = 
                (Element)document.createElement("circle");
      gNode.appendChild(circleA);
      circleA.setAttribute("cx","110");
      circleA.setAttribute("cy","100");
      circleA.setAttribute("r","30");
      circleA.setAttribute("style",
                            "fill:url(#gradientB)");
      
      //Most of the remaining code transforms the DOM
      // tree into a screen display and an output file.
      // This code was explained in the earlier lesson
      // named "Getting Started with Java JAXP and XSL 
      // Transformations (XSLT)" in conjunction with the
      // program named Xslt01.

      //Get a TransformerFactory object.
      TransformerFactory xformFactory = 
                         TransformerFactory.newInstance();
           
      //Get an XSL Transformer object.
      Transformer transformer = 
                            xformFactory.newTransformer();
      
      //This statement is new to this lesson.  It sets
      // the standalone property in the XML declaration,
      // which appears as the first line of the output
      // file.
      transformer.setOutputProperty(
                              OutputKeys.STANDALONE,"no");
      
      //Get a DOMSource object that represents the
      // Document object
      DOMSource source = new DOMSource(document);

      //Get a StreamResult object that points to the
      // screen. Then transform the DOM sending XML to
      // the screen.
      StreamResult scrResult = 
                             new StreamResult(System.out);
      transformer.transform(source, scrResult);

      //Get an output stream for the output file.
      PrintWriter outStream = new PrintWriter("junk.svg");

      //Get a StreamResult object that points to the
      // output file.  Then transform the DOM sending XML
      // to the file
      StreamResult fileResult = 
                              new StreamResult(outStream);
      transformer.transform(source,fileResult);
    }//end try block

    catch(Exception e){
      e.printStackTrace(System.err);
    }//end catch

  }// end main()
  //----------------------------------------------------//
  
}// class Svg01

Listing 27. Java code for program Svg02.

/*File Svg02.java
Copyright 2006 R.G.Baldwin

This program is an update of the program named Svg01.  The
purpose of this update is to move most of the difficult 
and tedious code into a small SVG graphics library class 
named SvgGraphics so that the application programmer can 
concentrate on the use of the graphics library rather than
having to concentrate on the details of SVG.

For convenience, the library also contains a couple of
methods that are used to execute code that is the same 
regardless of the graphic image being produced.

The SVG graphics library is far from complete.  In its
current state, the library provides methods to produce the
following DOM tree nodes.

  A simple element with no attributes.
  A linear gradient element.
  An ellipse
  A circle

Although a great deal more programming effort would be 
required to write a complete SVG graphics library, this
program serves its intended purpose of provides a proof of 
concept. The program illustrates an approach that could be
used to create a graphics library that supports most of 
the features of the SVG specification.

The program creates a DOM tree describing a specific 
graphic image in SVG format and writes it out into an XML 
file named junk.svg. Along the way, the DOM is displayed 
in raw XML format on the command-line screen. Note, 
however that the output on the command-line screen is all 
on a single line with no line breaks or indentation. 
Therefore, it is useful only for test and debug purposes. 

Portions of this program are based on the earlier program 
named Xslt01.java, which was explained in lesson 
number 2202 titled "Getting Started with Java JAXP and 
XSL Transformations (XSLT)".

The output file produced by this program can be rendered 
by loading it into Firefox 1.5.

Tested using J2SE 5.0, Firefox v1.5.0.8, and WinXP.
*********************************************************/

import javax.xml.parsers.*;
import org.w3c.dom.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;

public class Svg02{

  public static void main(String[] args){

    //Begin by creating a DOM tree that represents
    // the XML code that will render to produce the
    // image of interest.

    //Get the Document object.
    Document document = SvgGraphics.getDocument();

    //Create the root node named svg and append it
    // to the document.
    Element svg = SvgGraphics.getRootNode(document,
                                          "100%",
                                          "100%",
                                          "absolute",
                                          "0",
                                          "0");
  
    //Create a node named defs, which will be the parent
    // for a pair of linear gradient definitions.
    Element defs = SvgGraphics.simpleElement(
                                   document,svg,"defs");
  
    //Define linearGradientA, which provides a linear
    // gradient from yellow to red going from left to
    // right. Establish the beginning and ending points
    // along with the beginning and ending colors in
    // the process
    Element linearGradientA = 
               SvgGraphics.makeLinearGradient(
                 document,            //this document
                 defs,                 //parent
                 "gradientA",         //id
                 "0%",                //beginning point
                 "stop-color:yellow;",//beginning color
                 "100%",              //ending point
                 "stop-color:red;");  //ending color


    //Define linearGradientB, which provides a linear
    // gradient from green to blue going from left to
    // right.
    Element linearGradientB = 
                SvgGraphics.makeLinearGradient(
                  document,           //this document
                  defs,                //parent
                  "gradientB",        //id
                  "0%",               //beginning point
                  "stop-color:green;",//beginning color
                  "100%",             //ending point
                  "stop-color:blue;");//ending color
    
    //Create a node named g, which will be the parent
    // for an ellipse and a circle.
    Element g = SvgGraphics.simpleElement(
                                   document,svg,"g");

    //Create an ellipse with a blue border that is two
    // pixels thick. Fill the ellipse with the
    // yellow-red  gradient defined by linearGradientA.
    //Begin by defining the style for the ellipse
    String ellipseStyle = 
          "fill:url(#gradientA);" //Fill using gradientA
          + "stroke:rgb(0,0,100);"//Border and its color
          + "stroke-width:2";     //Border width
    SvgGraphics.svgEllipse(document,//This document
                           g,//Owner
                           110,//Center x-coordinate
                           100,//Center y-coordinate
                           100,//Width
                           40, //Height
                           ellipseStyle);

    //Place a circle in a location that will make it
    // appear to be inside the ellipse. Specify a 
    // style that will fill it with the green-blue
    // gradient defined by linearGradientB.
    SvgGraphics.svgCircle(document,//This document
                          g,//Owner
                          110,//Center x-coordinate
                          100,//Center y-coordinate
                          30, //Radius
                          "fill:url(#gradientB)");
    
    //Transform the DOM and write the output.
    SvgGraphics.transformTheDom(document,"junk.svg");

  }// end main()
  //----------------------------------------------------//
  
}// class Svg02
//======================================================//

//This is a small proof-of-concept graphics class that
// provides method calls for the creation of the following
// DOM tree nodes:
//  A simple element with no attributes.
//  A linear gradient element.
//  An ellipse
//  A circle

//Each method receives a reference to the overall document
// along with a reference to the parent for the new node.
//When the method returns, the new node has been appended
// to the parent node.
class SvgGraphics{

  //This method returns a reference to a simple XML
  // element node that has no attributes.
  static Element simpleElement(Document document,
                               Element parent,
                               String type){
    Element theElement = 
                    (Element)document.createElement(type);
    parent.appendChild(theElement);
    return theElement;
  }//end simpleElement
  //----------------------------------------------------//
  
  //This method returns a reference to a linear gradient
  // node for which the beginning and ending points and
  // the beginning and ending colors have been
  // established. The id value is the value by which the
  // gradient is referenced in order to apply it to 
  // a component.
  static Element makeLinearGradient(Document document,
                                    Element parent,
                                    String id,
                                    String beginningPoint,
                                    String beginningColor,
                                    String endingPoint,
                                    String endingColor){
    Element linearGradient = 
        (Element)document.createElement("linearGradient");
    parent.appendChild(linearGradient);
    linearGradient.setAttribute("id",id);
    
    //Establish the point at which the gradient begins
    // and the color at the beginning point.
    Element beginningElement  = 
                  (Element)document.createElement("stop");
    beginningElement.setAttribute(
                                 "offset",beginningPoint);
    beginningElement.setAttribute("style",beginningColor);
    linearGradient.appendChild(beginningElement);
    
    //Establish the point at which the gradient ends and
    // the color at that point.
    Element endingElement  = 
                  (Element)document.createElement("stop");
    endingElement.setAttribute("offset",endingPoint);
    endingElement.setAttribute("style",endingColor);
    linearGradient.appendChild(endingElement);
    
    return linearGradient;
  }//end makeLinearGradient
  //----------------------------------------------------//

  //This method returns a reference to an ellipse for 
  // which the style has already been established. Pass
  // an empty string for the style parameter if you don't
  // need to set the style. The xCoor and yCoor parameters
  // specify the center of the ellipse.  The xRadius and
  // yRadius parameters specify the width and height of
  // the  ellipse respectively.
  static Element svgEllipse(Document document,
                            Element parent,
                            int xCoor,
                            int yCoor,
                            int xRadius,
                            int yRadius,
                            String style){
    Element ellipseOut  = 
               (Element)document.createElement("ellipse");
    parent.appendChild(ellipseOut);
    ellipseOut.setAttribute("cx",""+xCoor);
    ellipseOut.setAttribute("cy",""+yCoor);
    ellipseOut.setAttribute("rx",""+xRadius);
    ellipseOut.setAttribute("ry",""+yRadius);
    if(!style.equals("")){
      ellipseOut.setAttribute("style",style);
    }//end if
    return ellipseOut;
  }//end svgEllipse
  //----------------------------------------------------//

  //This method returns a reference to a circle for 
  // which the style has already been established. Pass
  // an empty string for the style parameter if you don't
  // need to set the style. The xCoor and yCoor parameters
  // specify the center of the circle.  The radius
  // parameter specifies the radius of the circle.
  static Element svgCircle(Document document,
                           Element parent,
                           int xCoor,
                           int yCoor,
                           int radius,
                           String style){
    Element circleOut  = 
                (Element)document.createElement("circle");
    parent.appendChild(circleOut);
    circleOut.setAttribute("cx",""+xCoor);
    circleOut.setAttribute("cy",""+yCoor);
    circleOut.setAttribute("r",""+radius);
    if(!style.equals("")){
      circleOut.setAttribute("style",style);
    }//end if
    return circleOut;
  }//end svgCircle
  //----------------------------------------------------//
  
  //This method returns a reference to a root node that
  // has already been appended to the document.
  static Element getRootNode(Document document,
                 String width,
                 String height,
                 String position,
                 String top,
                 String left){
    //Create the root node named svg and append it to
    // the document.
    Element svg = 
                 (Element)document.createElement("svg");
    document.appendChild(svg);

    //Set some attributes on the root node that are
    // required for proper rendering. Note that the
    // approach used here is somewhat different from the
    // approach used in the earlier program named Svg01,
    // particularly with regard to the style.
    svg.setAttribute(
                  "xmlns","http://www.w3.org/2000/svg");
    svg.setAttribute("version","1.1");
    svg.setAttribute("style","width:" + width 
                   + ";height:" + height 
                   + ";position:" + position
                   + ";top:" + top
                   + ";left:" + left
                   + ";"");

    return svg;
  }//end getRootNode
  //----------------------------------------------------//
  
  //This is a utility method that is used to execute code
  // that is the same regardless of the graphic image
  // being produced.
  static Document getDocument(){
    Document document = null;
    try{
      DocumentBuilderFactory factory = 
                     DocumentBuilderFactory.newInstance();

      DocumentBuilder builder = 
                             factory.newDocumentBuilder();
      document = builder.newDocument();
      document.setXmlStandalone(false);
    }catch(Exception e){
      e.printStackTrace(System.err);
      System.exit(0);
    }//end catch
    return document;
  }//end getDocument
  //----------------------------------------------------//

  //This is a utility method that is used to execute code
  // that is the same regardless of the graphic image
  // being produced.  This method transforms the DOM into
  // raw XML code and writes that code into the output.
  static void transformTheDom(Document document,
                              String filename){
    try{
      //Get a TransformerFactory object.
      TransformerFactory xformFactory =
                         TransformerFactory.newInstance();
           
      //Get an XSL Transformer object.
      Transformer transformer = 
                            xformFactory.newTransformer();
      
      //Sets the standalone property in the first line of
      // the output file.
      transformer.setOutputProperty(
                              OutputKeys.STANDALONE,"no");
      
      //Get a DOMSource object that represents the
      // Document object
      DOMSource source = new DOMSource(document);

      //Get a StreamResult object that points to the
      // screen. Then transform the DOM sending XML to
      // the screen.
      StreamResult scrResult = 
                             new StreamResult(System.out);
      transformer.transform(source, scrResult);

      //Get an output stream for the output file.
      PrintWriter outStream = new PrintWriter(filename);

      //Get a StreamResult object that points to the
      // output file.  Then transform the DOM sending XML
      // code to the file
      StreamResult fileResult = 
                              new StreamResult(outStream);
      transformer.transform(source,fileResult);
    }//end try block

    catch(Exception e){
      e.printStackTrace(System.err);
    }//end catch
  }//end transformTheDom

  //----------------------------------------------------//
  
}//end class SvgGraphics


Copyright

Copyright 2007, Richard G. Baldwin.  Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.

Resources

Java 2D Graphics
Java 2D API
300 Java 2D Graphics, Nested Top-Level Classes and Interfaces 
302 Java 2D Graphics, The Point2D Class 
304 Java 2D Graphics, The Graphics2D Class 
306 Java 2D Graphics, Simple Affine Transforms 
308 Java 2D Graphics, The Shape Interface, Part 1 
310 Java 2D Graphics, The Shape Interface, Part 2 
312 Java 2D Graphics, Solid Color Fill 
314 Java 2D Graphics, Gradient Color Fill 
316 Java 2D Graphics, Texture Fill 
318 Java 2D Graphics, The Stroke Interface 
320 Java 2D Graphics, The Composite Interface and Transparency 
322 Java 2D Graphics, The Composite Interface, GradientPaint, and Transparency 
324 Java 2D Graphics, The Color Constructors and Transparency
Java 2D API Specification

Java API for XML Processing (JAXP)
2200 Java API for XML Processing (JAXP), Getting Started
2202 Getting Started with Java JAXP and XSL Transformations (XSLT)
2204 Java JAXP, Exposing a DOM Tree
2206 Java JAXP, Implementing Default XSLT Behavior in Java
2208 Java JAXP, Writing Java Code to Emulate an XSLT Transformation
2210 Java JAXP, Transforming XML to XHTML
Links to numerous XML tutorials by Richard G. Baldwin

Scalable Vector Graphics (SVG)
Scalable Vector Graphics (SVG) 1.1 Specification
Adobe SVG Viewer plug-in
Create vector graphics in the browser with SVG by Uche Ogbuji
SVG Tutorial
SVG Basics

Miscellaneous
High Performance JavaScript Vector Graphics Library at www.walterzorn.com

About the author

Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas.  He is the author of Baldwin's Programming Tutorials, which have gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.

In addition to his programming expertise, Richard has many years of practical experience in Digital Signal Processing (DSP).  His first job after he earned his Bachelor's degree was doing DSP in the Seismic Research Department of Texas Instruments.  (TI is still a world leader in DSP.)  In the following years, he applied his programming and DSP expertise to other interesting areas including sonar and underwater acoustics.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

Baldwin@DickBaldwin.com






Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel