|

Graphics, using Java and JDOM with SVG, Part 2
By Richard G. Baldwin
Java Programming Notes # 2224
Preface
Second of two
parts
This lesson is the second part of two-part tutorial on using Java and JDOM to
create SVG files.
What you have learned
In Part 1, you learned a little about JDOM as an alternative to Sun's JAXP
DOM API. You learned how to create an SVG file using raw JDOM commands,
and you learned how to write a Java/JDOM/SVG graphics library to reduce the
effort required to create SVG files using JDOM and Java.
What you will learn
In Part 2, you will expand the JDOM/SVG graphics library to include gradients, Bézier
curves, and elliptical arcs. You will learn the significance of the word
Scalable in Scalable Vector Graphics (SVG). You will learn how to use JDOM to write
XHTML output files containing SVG/XML code, and you will learn how to use JDOM to
write Java servlets that deliver XHTML output containing SVG/XML code.
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.
- Figure 1. Graphic output from Svg17.
- Figure 2. Graphic output from Svg18 and Svg19.
- Figure 3. Drawing with a Bezier curve and a
radial gradient.
- Figure 4. Bit mapped image enlarged by a factor
of four.
- Figure 5. SVG drawing enlarged by a factor of
four.
- Figure 6. Svg drawing enlarged by a factor of
sixteen.
- Figure 7. Svg drawing enlarged by a factor of
sixteen.
- Figure 8. Bit mapped image enlarged by a factor
of sixteen.
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.
See the link to Part 1 of this tutorial in Resources
for background information on JDOM. See numerous previous lessons in this
series for background information on SVG.
In this lesson, I will present and explain three programs named Svg17,
Svg18, and Svg19.
Svg17
Svg17 will teach you how to expand the Java/JDOM/SVG graphics library
from the earlier program named Svg16 to include the following new
methods:
- makeGridString - used with makePath to draw graph paper
- makePath - used for a variety of purposes including the drawing
of Bézier curves and elliptical arcs.
- makeNode - used to create a general node for which a specialized
method hasn't been written.
- makeLinearGradient - used to define a linear gradient.
- makeRadialGradient - used to define a radial gradient.
- makeGradientStop - used to control the behavior of linear and
radial gradients.
- makeText - used to add text to an SVG drawing.
The graphic output from Svg17
The output SVG/XML code from Svg17 is written into an SVG file, which
can be properly rendered by loading the file into Firefox 2.0.0.4. The graphic
output from Svg17 is shown in Figure 1.
Figure 1. Graphic output from Svg17.
Svg18
Svg18 will teach you how to use JDOM to write an output XHTML file
containing embedded SVG/XML code. The file can be rendered in Firefox
2.0.0.4
to produce a scaled down version of the same graphic that is produced by the SVG
file from Svg17 with some additional HTML text inserted into the output.
Svg19
Svg19 will teach you how to convert the JDOM program named Svg18
into a JDOM servlet that will deliver XHTML output with embedded SVG/XML code.
The servlet can be accessed by Firefox 2.0.0.4 to produce the same graphic that is
produced by Svg18.
The graphic output from Svg18 and Svg19
The output graphic produced by Svg18 and Svg19 is shown in
Figure 2. Note the overall size of this graphic as compared to the overall
size of the graphic produced by Svg17 in Figure 1. One of the
advantages of SVG (as compared to bit mapped graphics, for example) is
the ability to scale the size of the graphic up or down with no loss in the
quality of the graphic.
Figure 2. Graphic output from Svg18 and Svg19.
Also note the HTML text above and below the image in Figure 2, which is not
present in the output from Svg17 shown in Figure 1. One of the advantages of
embedding the SVG code in an XHTML file instead of writing it into an SVG file is
the ability to place the graphic in the
midst of other HTML elements, such as the HTML text shown in Figure 2.
Discussion
and sample code
|
|
Proper spelling of Bézier's name.
Although Bézier is the proper spelling of Pierre
Bézier's name, the use of the special character as the
second character in the name makes it very difficult to compose
text using a standard computer keyboard. Therefore, to make it
easier to compose the remainder of this tutorial, I will take
the liberty of spelling it Bezier. |
|
Description of the program
The program named Svg16 began the development of a Java/JDOM/SVG
graphics library of my own design named JdomSvg. The use of this
library can eliminate much of the effort involved in writing Java programs to
produce SVG files using JDOM as an alternative to Sun's JAXP DOM API. The
purpose of this program is to add the following methods to that graphics library
and to demonstrate their use.
- makeGridString - used with makePath to draw graph paper
- makePath - used for a variety of purposes including the drawing
of Bezier curves and elliptical arcs.
- makeNode - used to create a general node for which a specialized
method hasn't been written.
- makeLinearGradient - used to define a linear gradient.
- makeRadialGradient - used to define a radial gradient.
- makeGradientStop - used to control the behavior of linear and
radial gradients.
- makeText - used to add text to an SVG drawing.
The program draws the following graphics elements on a background that looks
like green graph paper (see Figure 1) and writes the output into an SVG
file that can be rendered using an SVG graphics engine such a Firefox 2.0.0.4:
- A rotated ellipse with a linear gradient that changes from yellow to red
and back to yellow.
- A rectangle with a radial gradient centered in the upper left corner of
the rectangle.
- A filled (blue) cubic Bezier curve with two Bezier segments
inside a filled (yellow) polygon.
- A filled (blue) quadratic Bezier curve with two Bezier segments
inside a filled (yellow) polyline that is partially transparent.
- A filled (red) elliptical arc with no rotation.
- A filled (red) elliptical arc with a rotation of 45 degrees.
Program testing
The output file validates at: http://validator.w3.org/
It was tested using J2SE 6.0, JDOM 1.0, and Firefox 2.0.0.4 running under WinXP.
Will discuss in fragments
As is my custom, I will present and explain this program in fragments.
You can view the program in its entirety in Listing 30 near the end of the
lesson.
Some of the code in this lesson is the same as the code that I explained Part
1 of this tutorial (see Resources).
Usually I won't repeat that explanation in this part of the tutorial.
The program and the main method begin in Listing 1. The code in the
early portions of the main method is essentially the same as code that I
have explained in previous lessons. Therefore, that code was deleted from
Listing 1 for brevity.
Controlling physical and virtual canvas dimensions
The expressions for computing the viewBoxWidth and viewBoxHeight
are useful for those cases where you need to make the height to width ratio of
the virtual canvas the same as the height to width ratio of the physical canvas.
Listing 1. Controlling physical and virtual canvas
dimensions.
public class Svg17{
public static void main(String[] args){
//Code deleted for brevity.
//Physical dimensions of the graphic on the screen.
int svgWidth = 460;
int svgHeight = 552;
//Virtual dimensions of the graphic in user units.
int viewBoxWidth = 500;
int viewBoxHeight = 500*svgHeight/svgWidth;
|
With this formulation, the virtual width will always be 500 regardless of the
physical width, and the virtual height will vary as the physical height varies.
Note however, that sometimes you may not want to keep these ratios equal.
For example, it is often desirable to expand the scale on the vertical axis when
plotting curves.
Create path data for the background graph paper
Listing 2 calls the makeGridString method to create the path data for
drawing the background graph paper in Figure 1.
Listing 2. Create path data for the background graph
paper.
//Code deleted for brevity
//Begin creating graphics elements.
//Draw light green grid lines every 10 user units on
// the basis of the virtual dimensions in user units.
//First create the path data.
String gridData = JdomSvg.makeGridString(
viewBoxWidth,viewBoxHeight,10);
|
There is nothing about the makeGridString method that is peculiar to
the use of JDOM. The method is essentially the same as a method having the
same name that I explained in the earlier lesson titled "Drawing grids, Bézier
curves and elliptical arcs using Java and SVG" (see
Resources).
Create the path element and add it to the root
Listing 3 calls the makePath method to create the JDOM element that
represents the background grid with the smallest squares in Figure 1. (The
grid size of 10 virtual units was established by passing a parameter with a
value of 10 to the makeGridString method in Listing 2.)
When the makePath method returns a reference to the path element, the
code in Listing 3 calls the setAttribute method on the path to set the
stroke color to the very light green that you see in Figure 1.
Listing 3. Create the path element and add it to the root.
//In main.
Element temp;
temp = JdomSvg.makePath(svg,ns,gridData);
//Set the color to a very light green.
temp.setAttribute("stroke","#ccffcc");
|
Switching back and forth
From this point forward, I will be switching back and forth between
statements in the main method and methods in the graphics library.
I will use the notation shown in the upper left corner of Listing 3 to indicate
those code fragments that are part of the main method.
The makePath method
The makePath method is shown in its entirety in Listing 4.
Listing 4. The makePath method.
static Element makePath(Element parent,
String namespace,
String d){
Element path = new Element("path",namespace);
parent.addContent(path);
//Set default attribute values.
path.setAttribute("stroke","black");
path.setAttribute("stroke-width","1");
path.setAttribute("fill","none");
//Set user specified default values.
path.setAttribute("d",d);
return path;
}//end makePath
|
The makePath method constructs and returns a reference to a path
element as a child of the specified parent node in the specified namespace.
By default, the stroke is set to black one pixel wide, and the fill is set to
none.
(See the method named makeGridString for a utility method that
is designed to create the data string for this method for the special case
of drawing grids that resemble graph paper. For other cases, simply
create a data string that is compatible with the SVG path element.)
As you will recall from the earlier lesson titled "Drawing grids, Bézier
curves and elliptical arcs using Java and SVG" (see
Resources) a variety of different paths including straight lines,
polylines, Bezier curves, elliptical arcs, etc., can be constructed depending on
the contents of the third incoming parameter of type String.
The makePath method is fairly typical of many of the methods in the
SVG graphic library. It begins by creating the new path element and
attaching it as a child to the specified parent. Then it calls the
setAttribute method several times in succession to set the default values
for some of the attributes. Then it calls the setAttribute method
again to set the user specified attribute values. In this case, there is
only one user specified attribute, but some of the methods in the library have
several user specified attribute values.
Create the defs element
Listing 5 calls the new makeNode method to create a defs element.
Recall from an earlier lesson that a defs element serves as a repository
for definitions in XML code that are referenced by other elements. In this
program, the defs element is used as a repository for gradient
definitions. Note for the purpose of a later discussion that Listing 5
passes null for the fourth parameter to the makeNode method.
Listing 5. Create the defs element.
//In main.
//Using the same procedure, draw darker green grid
// lines every 50 user units and draw them on top of
// the existing grid lines.
// Code deleted for brevity.
Element defs = JdomSvg.makeNode(svg,//parent
ns,//namespace
"defs",
null//no attributes
);
|
The makeNode method
The graphics library contains a number of specialized methods that are
designed to construct and return specific kinds of elements such as makeLine,
makeCircle, makeEllipse, etc.
In addition, the library contains the makeNode method, the purpose of
which is to create a general node having any name, and any number of attributes
with any attribute names and any String values for the attributes, or no
attributes at all.
The makeNode method is shown in its entirety in Listing 6.
Listing 6. The makeNode method.
static Element makeNode(Element parent,
String namespace,
String nodeType,
String[] data){
Element element = new Element(nodeType,namespace);
parent.addContent(element);
//Deal with elements that have no attributes.
if(data == null){
return element;
}//end if
//Extract the values from the array and construct
// each of the attributes and its value.
for(int cnt=0;cnt<data.length;cnt+=2){
String name = data[cnt];
String value = data[cnt+1];
element.setAttribute(name,value);
}//end for loop
return element;
}//end makeNode
|
The first parameter is a reference to the parent node to which this node is
to be attached so as to become a child of that node. The second parameter
is a String that specifies the namespace for the element represented by
the new node. The third parameter is a String that specifies the
type of the new node. (Looking back at Listing 5, you can see that for
the case at hand, the type of the new node is "defs.")
The fourth parameter must be a reference to an array object of type
String[]. This array must contain an even number of elements.
Each pair of elements specifies the name and the value of one attribute, in the
order name, value, name, value, etc. If there are no attributes, the value
of this parameter should be null. (Once again, looking back at Listing
5, the value of the fourth parameter is null for the case at hand.)
The method begins by constructing the new element of the specified type in
the specified namespace and attaching it as a child to the specified parent.
Then the method tests to determine if the value of the fourth parameter is
null. If so, it simply returns the element that was just constructed.
If the value of the fourth parameter is not null, the method extracts the
String values from the referenced array object in pairs, using the two
values as parameters in a call to the setAttribute method to set the
value of the specified attribute to the specified value.
The makeNode method is intended to be used primarily to construct
elements for which there is no corresponding specialized method in the library.
However, it can be used to construct any of the SVG elements.
Create a linear gradient element
Listing 7 calls the new makeLinearGradient method to create a linear
gradient element that is a child of the defs element and identified for
later reference purposes as gradientA.
Listing 7. Create a linear gradient element.
//In main.
Element gradientA = JdomSvg.makeLinearGradient(
defs,//parent
ns,//namespace
"gradientA");//id
|
Although it won't be determined until later in the program, this gradient
starts with yellow, changes to red, and then changes back to yellow going from
left to right. This is the gradient that was used to fill the ellipse in
the upper left of Figure 1.
The makeLinearGradient method
The makeLinearGradient method is shown in it entirety in Listing 8.
Listing 8. The makeLinearGradient method.
static Element makeLinearGradient(Element parent,
String namespace,
String id){
Element gradient =
new Element("linearGradient",namespace);
parent.addContent(gradient);
gradient.setAttribute("id",id);
return gradient;
}//End makeLinearGradient
|
This method creates a linear gradient node to which stop elements must
be appended to specify the behavior of the gradient. There are no default
attribute values and only one user specified attribute named id.
The id attribute is used to differentiate this gradient node from other gradient
nodes in the same program scope. The id provides a handle by which
other elements can reference this gradient.
Create the first of three stop nodes
The code in Listing 9 calls the makeGradientStop method to create the
first of three stop nodes that identify the colors used to produce gradientA
and specify where the colors begin and end
Listing 9. Create the first of three stop nodes.
//In main.
JdomSvg.makeGradientStop(gradientA,//parent
ns,
"4%",//start here
"yellow");//color
|
The makeGradientStop method
The makeGradientStop method is shown in its entirety in Listing 10.
Listing 10. The makeGradientStop method.
static Element makeGradientStop(Element parent,
String namespace,
String offset,
String color){
Element stopElement = new Element("stop",namespace);
parent.addContent(stopElement);
stopElement.setAttribute("offset",offset);
stopElement.setAttribute("stop-color",color);
return stopElement;
}//End makeGradientStop
|
The makeGradientStop method creates a gradient stop node in a
specified namespace and attaches it as a child to a specified parent.
(The node must be attached as a child to a linear gradient node or a radial
gradient node to be useful.) There are two user specified parameters
in Listing 10 that specify the color and specify where the color changes in the
shape being filled with the gradient.
|
|
Could have called makeEllipse.
Note that I could have called the makeEllipse method, but I wanted to
demonstrate the use of the more general makeNode method for a graphics element
that has several attributes. |
|
Call the makeNode method to draw an ellipse
Listing 11 calls the makeNode method to draw an ellipse. The
ellipse is filled with linear gradientA and rotated by 30 degrees.
This is the ellipse that appears in the upper left of Figure 1. Note the
boldface syntax used to specify a gradient as the value for the fill
attribute.
Listing 11. Call the makeNode method to draw an
ellipse.
// In main.
//Code to create two more stop nodes deleted for
// brevity.
JdomSvg.makeNode(
svg,//parent
ns,
"ellipse",//node type
new String[]{"cx","150",
"cy","80",
"rx","100",
"ry","40",
"fill","url(#gradientA)",
"stroke","blue",
"stroke-width","3",
"opacity","0.5",
"transform","translate(150,80) "
+ "rotate(-30) "
+ "translate(-150,-80)"
}//end array definition
);//end makeNode method
|
A comment regarding opacity and gradients
Setting the opacity attribute value to 0.6 in Listing 11 is of no
consequence when the output file is rendered using Firefox 1.5 as shown in
Figure 1. In
that case, the gradient continues to be totally opaque. However, this is a
weakness in the Firefox 1.5 rendering engine and is not a limitation of SVG.
When the file is rendered using an Adobe rendering engine, the gradient is
partially transparent as it should be for an opacity attribute value of
0.6.
(This problem has been fixed in Firefox 2.0.0.4. If you run this
program and render the resulting output file in Firefox 2.0.0.4, the grid on the
graph paper will show through the gradient fill inside the ellipse.)
Define a radial gradient and save it as a child of defs
Listing 12 calls the makeRadialGradient method to define a gradient
identified as gradientB. This gradient element provides a radial
gradient that goes through yellow, red, green, and blue. It is used to fill the
rectangle in the upper right of Figure 1.
Listing 12. Define a radial gradient and save it as
a child of defs.
//In main.
int rectCornerX = 300;
int rectCornerY = 10;
int rectWidth = 150;
int rectHeight = 150;
Element gradientB = JdomSvg.makeRadialGradient(
defs,//parent
ns,//namespace
"gradientB",//ID
"userSpaceOnUse",
rectCornerX,//cx
rectCornerY,//cy
((int)(rectWidth*1.2)));//r
|
The makeRadialGradient method
The makeRadialGradient method is shown in its entirety in Listing 13.
Listing 13. The makeRadialGradient method.
static Element makeRadialGradient(Element parent,
String namespace,
String id,
String gradientUnits,
int cx,//center
int cy,//center
int r //radius
){
Element gradient =
new Element("radialGradient",namespace);
parent.addContent(gradient);
gradient.setAttribute("id",id);
gradient.setAttribute("gradientUnits",gradientUnits);
gradient.setAttribute("cx",""+cx);
gradient.setAttribute("cy",""+cy);
gradient.setAttribute("r",""+r);
return gradient;
}//End makeRadialGradient
|
With the exception of the fourth parameter identified as gradientUnits,
the code in Listing 13 is straightforward and shouldn't require further
explanation.
I recommend that you consult the SVG documentation (see
Resources) for more information on the various
attributes of the radial gradient element.
Draw a cubic Bezier curve
Listing 14 calls the makePath method to draw the cubic Bezier curve
shown at the middle left in Figure 1.
Listing 14. Draw a cubic Bezier curve.
//In main.
//Code for four calls to the makeGradientStop
// method deleted for brevity.
//Draw the rectangle and fill it with gradientB.
//Call to the makeRect method and the setAttribute
// method deleted for brevity.
//Draw a cubic Bezier curve consisting of two Bezier
// segments. First draw a polygon that shows the
// start points, the end points, and the control
// points for the segments. Fill the polygon with
// yellow to provide a background color for the
// Bezier curve.
//Call to the makePolygon method deleted for brevity.
//Draw the cubic curve. Note the use of absolute
// coordinate values only and also the use of the S
// command. Stroke the curve with red and fill it with
// blue.
temp = JdomSvg.makePath(svg,ns,"M180,290 C50,250,"
+ "150,200,150,300 S250,350,120,310");
temp.setAttribute("stroke","red");
temp.setAttribute("fill","blue");
|
Recall from the earlier lesson titled "Drawing grids, Bézier curves and
elliptical arcs using Java and SVG" (see Resources)
that a Bezier curve (either cubic or quadratic) is drawn by drawing a
path with the correct value for the String parameter named d
(see Listing 4). The string value that produced the cubic Bezier
curve at the middle left in Figure 1 is shown highlighted in boldface near the
bottom of Listing 14.
Draw an elliptical arc with no rotation
Listing 15 calls the makePath method to draw a red elliptical arc with
no rotation shown at the bottom left in Figure 1.
Listing 15. Draw an elliptical arc with no rotation.
//In main.
//Draw a quadratic Bezier curve consisting of two
// Bezier segments. First draw a polyline that shows
// the start points, the end points, and the control
// points. Fill the polyline with yellow color with
// an opacity attribute value of 0.5. This allows
// the grid to show through the filled polyline.
//Call to the makePolyline method deleted for brevity.
//Call to the makePath method to draw the quadratic
// Bezier curve deleted for brevity.
//Draw an elliptical arc to illustrate the appearance
// of such an arc with no rotation. Stroke it with
// yellow and fill it with red.
temp = JdomSvg.makePath(svg,ns,
"M100,500 a70,30 0 1,0 50,-50 z");
temp.setAttribute("stroke","yellow");
temp.setAttribute("stroke-width","2");
temp.setAttribute("fill","red");
|
Recall from the earlier lesson titled "Drawing grids, Bézier curves and
elliptical arcs using Java and SVG" (see Resources)
that an elliptical arc is drawn by drawing a path with the correct value
for the String parameter named d (see Listing 4). The
string value that produced the elliptical arc at the bottom left in Figure 1 is
shown highlighted in boldface near the bottom of Listing 15.
Label the vertical lines of the grid
Listing 16 calls the new makeText method several times in succession
(inside a for loop) to create and position the text labels at the
bottom of the vertical lines in Figure 1.
Listing 16. Label the vertical lines of the grid.
//Draw an elliptical arc to illustrate the appearance
// of such an arc with a rotation of 45 degrees.
// Stroke it with yellow and fill it with red.
//Call to makePath to draw the elliptical arc at
// the bottom right in Figure 1 deleted for brevity.
for(int cnt = 0;cnt < viewBoxWidth;cnt += 50){
JdomSvg.makeText(
svg,ns,cnt,viewBoxHeight - 4,""+cnt);
}//end for loop
|
The makeText method
The makeText method is shown in its entirety in Listing 17.
Listing 17. The makeText method.
static Element makeText(Element parent,
String namespace,
int x,
int y,
String text){
Element textNode = new Element("text",namespace);
parent.addContent(textNode);
textNode.setAttribute("x",""+x);
textNode.setAttribute("y",""+y);
textNode.addContent(text);
return textNode;
}//end makeText
|
The code in Listing 17 is reasonably straightforward. The only thing
that may be unusual is the interpretation of the values for x and y relative to
the location of the text. It appears from experiments that the bottom left
corner of the first character in the text string is located at coordinates (x,y)
when the text is drawn.
Label the graphics elements
Listing 18 calls the makeText method to place the label underneath the
ellipse in the upper left corner of Figure 1. The code to label the
remaining five graphics elements was deleted from Listing 18 for brevity.
Listing 18. Label the graphics elements.
//In main.
//Now label the horizontal lines.
//Code to label the horizontal lines deleted for
// brevity.
//Label each of the graphics elements
JdomSvg.makeText(svg,ns,50,180,
"Ellipse with linear gradient");
//Code to draw labels under each of the remaining five
// graphics elements deleted for brevity.
|
Write the output file
Listing 19 calls the writePrettyFile method to write the SVG/XML code
into the output file named Svg17.svg.
Listing 19. Write the output file.
//Write the output file.
JdomSvg.writePrettyFile("Svg17.svg",doc);
//JdomSvg.writeCompactFile("Svg17.svg",doc);
}//end main
|
The writePrettyFile method was explained in Part 1 of this tutorial
(see Resources).
The end of the program
Listing 19 also signals the end of the main method and the end of the
explanation of the program named Svg17.
Description of the program
The intended primary purpose of this program was to use JDOM to embed SVG
code into what would otherwise be a valid XHTML file.
A secondary purpose of this program, in comparison with the earlier program
named Svg017, was to demonstrate the significance of the use of the word
Scalable in the name Scalable Vector Graphics (SVG).
The secondary purpose was achieved. However, for the reasons explained
below, the primary purpose was not completely achieved, because the output XHTML
file is not valid.
Embedding graphics between HTML elements
One of the advantages of embedding SVG code in an XHTML document is that it
then becomes possible to place the graphic in and among other HTML elements.
That is not possible when creating an SVG file. That capability is
demonstrated by the program output shown in Figure 2. Figure 2 shows HTML
text inserted above and below the graphic image that was created by rendering
the SVG code that was embedded in the XHTML code.
Not a valid XHTML file
My attempt to create a valid XHTML file using JDOM was not successful because
the JDOM Element constructor insists on creating an xmlns
attribute for each child of the root html node. This is true
regardless of the name of the child node, and even when the constructor version
is used that doesn't take a namespace as a parameter. Regardless of
whether that version is used, or the version that takes a namespace as a
parameter is used by passing null for the namespace, the resulting XML code
contains the following attribute declaration in all child nodes of the root
html node:
xmlns=""
The DTD for XHTML doesn't allow for attributes named xmlns on the
head and body elements. (Note that the xmlns attribute
is created even if I change the name of the child node from head to joe.)
This may be a bug in the version of the Element
constructor that doesn't take a namespace parameter. The behavior of that
version seems to be the same as passing null for the namespace to the version
that does take a namespace parameter. Therefore, the output file produced
by this program is not a valid XHTML file. (Apparently there is
something about this that I don't understand.) Nonetheless, the output
file renders very
successfully in Firefox 2.0.0.4.
The Java/JDOM/SVG graphics library
The program named Svg16 began the development of a Java/JDOM/SVG
graphics library of my own design named JdomSvg. The use of this
library eliminates much of
the effort involved in writing Java programs to produce SVG files using JDOM as
an alternative to the standard Sun JAXP DOM API.
Several new methods were added to the library in the program named Svg017. Those
methods were all associated with the creation of SVG/XML code. I added the
following method to the graphics library in this program:
makeXhtmlRoot
This method is used to create an ordinary XML root node that doesn't necessarily have
anything to do with graphics, but rather is required for the creation of an
XHTML file.
Create some text content
This program begins by placing the following text content in a paragraph
element at the beginning of the body element:
There is a graphic below here.
That text appears above the image in Figure 2.
Create some graphic content
Then the program draws the following graphics elements on a background that
looks like graph paper (going from left to right, top to bottom in Figure 2).
- A rotated ellipse with a linear gradient.
- A rectangle with a radial gradient.
- A filled cubic Bezier curve with two Bezier segments inside a filled
polygon.
- A filled quadratic Bezier curve with two Bezier segments inside a filled
polyline that is partially transparent.
- A filled elliptical arc with no rotation.
- A filled elliptical arc with a rotation of 45 degrees.
Some more text content
After drawing the graphic elements, the program places the following text
content in a paragraph element below the graphic elements at the end of the body
element.
There is a graphic above here.
Finally, the program writes the output into an XHTML file named
Svg18.xhtml that can be rendered using an SVG graphics engine such a Firefox
2.0.0.4.
The significance of Scalable in Scalable
Vector Graphics
You will notice that the output from Svg18 shown in Figure 2 is a
scaled down version of the output from Svg17 shown in Figure 1, with HTML
text inserted before and after the graphic image. The fact
that the SVG graphic image can be scaled with no loss in quality illustrates the
significance of the word Scalable in the name Scalable Vector Graphics
(SVG).
At this point, I am going to take a short side trip and show you some other
examples that illustrate the significance of the word Scalable,
particularly in contrast with bit mapped graphics.
Figure 3 shows a small graphic image containing a blue cubic Bezier curve and
in a yellow background and a radial gradient in a rectangle. This drawing
was produced using a program similar to Svg17.
Figure 3. Drawing with a Bezier curve and a radial
gradient.
Enlarge the bit mapped image
I captured the image shown in Figure 3 as a bit mapped JPEG image using a standard screen
capture program. Then I enlarged the bit mapped image by a factor of four,
producing the result shown in Figure 4.
Figure 4. Bit mapped image enlarged by a factor of
four.
As you would expect (if you are familiar with the limitations of bit
mapped images) the results aren't very pleasing. To make a long story
short, bit mapped images aren't very scalable, at least insofar as enlargement
is concerned.
Enlarge the SVG drawing by a factor of four
Figure 5 shows the result of increasing the size of the SVG drawing by the
same factor of four. This result shows the significance of the word
Scalable in the name Scalable Vector Graphics (SVG).
Figure 5. SVG drawing enlarged by a factor of four.
|
|
Import degradation.
There is a small amount of degradation showing in Figure 5. That
degradation was introduced by the process of capturing the image from the screen
as a JPEG image and importing it into this document. That degradation did
not exist in the original rendered version of the drawing in the Firefox
2.0.0.4
browser window. |
|
The quality of the scaled image in Figure 5 is excellent. No
degradation in image quality was introduced by enlarging the SVG drawing.
Enlarge the SVG drawing by a factor of sixteen
To drive home the point that scaling the SVG drawing does not degrade the
quality of the drawing, Figure 6 and Figure 7 show captured portions of the
drawing produced by enlarging the original drawing shown in Figure 3 by a factor of sixteen.
Figure 6. Svg drawing enlarged by a factor of
sixteen.
Note that because I am limited as to the width of images that I can publish
on this web site, I was unable to publish the entire enlarged drawing.
Therefore, it was necessary for me to capture and publish portions of the
drawing that was enlarged by a factor of sixteen.
Figure 7. Svg drawing enlarged by a factor of
sixteen.
Once again, the small amount of degradation that you can see in Figure 6 and
Figure 7 did not exist in the original rendering of the drawing in the Firefox
2.0.0.4 browser window. That degradation was introduced by the process of
capturing the image from the screen as a JPEG image and importing it into this
document.
Could continue to enlarge indefinitely
I could continue this process of enlarging the SVG drawing indefinitely and
no degradation would be introduced into the drawing. That is the true
significance of the word Scalable in the name Scalable Vector Graphics
(SVG).
What about the bit mapped image?
To drive home the point that bit mapped images are not scalable, Figure 8 shows the result of enlarging the original bit mapped image
from Figure 3 by a factor of sixteen and capturing a portion of the enlarged
image for publication in this lesson.
Figure 8. Bit mapped image enlarged by a factor of
sixteen.
The image shown in Figure 8 is approximately the same portion of the enlarged
image as that shown in Figure 6. However, because of the poor quality of
the enlarged bit mapped image, it was not possible for me to identify and capture the exact same
portion.
As you can see, bit mapped images are not scalable in the same way that SVG
drawings are scalable.
Program Testing
The program was tested using J2SE 6.0, JDOM 1.0, and Firefox 2.0.0.4 running
under WinXP.
Will discuss in fragments
I will present and explain this program in fragments. You can view the
program in its entirety in Listing 31 near the end of the lesson. Much of
the code in this program is the same as, or very similar to code that I have
explained in this or other lessons. I will skip over that code and won't
repeat those explanations here.
The namespace URI
The program class and the main method both begin in Listing 20.
This class begins pretty much like the class for the programs named Svg17
(see the listing for Svg17 in Listing 30 near the end of the lesson).
Both programs begin by creating a String variable that contains a
namespace URI.
Listing 20. The namespace URI.
public class Svg18{
public static void main(String[] args){
String xns = "http://www.w3.org/1999/xhtml";
|
There is one major difference, however. The namespace URI for the
program named Svg17 is as follows:
http://www.w3.org/2000/svg
This is different from the namespace URI shown in Listing 20 above. The
difference is that the namespace for the program named Svg17 is
appropriate for an SVG file, but is not correct for an XHTML file. The
namespace URI shown in Listing 20 is the correct namespace for an XHTML file.
(In fact, the SVG namespace URI
will also show up later in this
program, because this program produces an XHTML file that contains SVG code.)
Specify DTD information
The program named Svg18 continues in Listing 21 by specifying the name of
the element that is constrained by the DTD (the html root element), the Public ID of the DTD, and the System ID of the DTD.
Listing 21. Specify DTD information.
//For clarity, create strings containing the name of
// the element that is constrained by the DTD (the
// html root element), the Public ID of the DTD, and
// the System ID of the DTD.
String dtdConstrainedElement = "html";
String dtdPublicID =
"-//W3C//DTD XHTML 1.0 Transitional//EN";
String dtdSystemID = "http://www.w3.org/TR/xhtml1/"
+ "DTD/xhtml1-transitional.dtd";
|
Once again, the approach is the same, but the three values are different from
the corresponding values for the SVG file that was created in Listing 30.
The root node for an SVG file is named svg, whereas the root node for an
XHTML file is named html. Similarly, the DTD information for an
XHTML file is different from the DTD information for an SVG file.
Create the Document node
Following this, the code in Listing 22:
- Creates the DocType node based on the correct DTD information for
an XHTML file.
- Creates the root node named html, which is the required name for
the root node in an XHTML document.
- Creates the Document node on the basis of the root node and the
DocType node that are correct for an XHTML document.
Listing 22. Create the Document node.
//Create the DTD declaration node.
DocType docType = new DocType(
dtdConstrainedElement,dtdPublicID,dtdSystemID);
//Create the XHTML root node named html.
Element html = JdomSvg.makeXhtmlRoot(xns);
//Create the document node.
Document doc = new Document(html,docType);
|
Note that Listing 22 calls the new makeXhtmlRoot method to create the
XHTML root node named html. This method is very similar to the
method named makeSvg, so it shouldn't require any explanation beyond the
embedded comments.
Create optional and required elements
The root node for an XHTML document must be named html. The
html element must have a child element named body. The html
element may also have a child element named head, which in turn may have
a child element named title. (I believe, but am not certain,
that these latter two elements are optional.)
Listing 23 calls the makeNode method that I explained earlier in this
lesson to create these head, title, and body nodes.
Listing 23. Create optional and required elements.
Element head = JdomSvg.makeNode(html,xns,"head",null);
Element title = JdomSvg.makeNode(
head,xns,"title",null);
title.setText("XHTML/SVG Graphic Demo.");
Element body = JdomSvg.makeNode(html,xns,"body",null);
|
Listing 23 also calls the setText method to populate the title
element with text content that describes the program.
Create a paragraph node
Listing 24 calls the makeNode method to create a paragraph (p)
node and attach it to the body node.
Listing 24. Create a paragraph node.
Element temp = JdomSvg.makeNode(body,xns,"p",null);
temp.setText("There is a graphic below here.");
|
Then Listing 24 calls the setText method to add text content to the
p node. This is the text that appears above the graphic in Figure 2.
Switch your thinking into graphics mode
Now you need to switch your thinking into graphics mode. At this point,
the program creates a complete SVG graphic sub-tree with a root named svg
and attaches it as a child of the body node. In the end, the
body node will have three child nodes. One of them is the p
node that was created and populated in Listing 24. A second one is another
p node that |