gamelan
Search EarthWeb
CodeGuru | Gamelan | Jars | Wireless | Discussions
Navigate developer.com
Architecture & Design  
Database  
Java
Languages & Tools
Microsoft & .NET
Open Source  
Project Management  
Security  
Techniques  
Voice  
Web Services  
Wireless/Mobile
XML  
Technology Jobs  

   Developer.com Webcasts:
  The Impact of Coding Standards and Code Reviews

  Project Management for the Developer

  Defining Your Own Software Development Methodology

  more Webcasts...




See the Winners!


Developer Jobs

Be a Commerce Partner
Televisions
Disney World Tickets
Home Improvement
Online Shopping
Compare Prices
PDA Phones & Cases
KVM Switch over IP
Web Design
Online Education
Dental Insurance
Computer Hardware
Promote Your Website
Prepaid Phone Card
Shop

 



  And Enter to Win a Sony Blu-Ray Player.

Click here to register for your free
Internet.com membership.
Valid email and mailing addresses must
be provided to qualify for this contest.
Agree to the contest rules after registering/ logging in by checking the "I agree to the rules of this contest" box and hitting "Submit". You will then be entered for a chance to win a free Sony Blu-Ray player.

Membership provides access to exclusive content on
our networks, including:
eBook Library Whitepapers Newsletters Webcasts

Existing Internet.com members are also welcome to participate. Simply log in here and check your profile.
Your profile data must be accurate to be eligible to win!

Contest Rules
Related Article -
Graphics, using Java and JDOM with SVG, Part 1
Drawing grids, Bézier Curves and Elliptical Arcs Using Java and SVG
Using the Java 2D BandCombineOp Filter Class to Process Images
Writing Java Servlets to Produce XHTML Code That References External SVG Files
Using the Java 2D LookupOp Filter Class to Scramble and Unscramble Images
Using Java to Produce SVG Code in XHTML Data
An Improved Approach for Creating SVG/XML Code and SVG/XML DOM Nodes using Java
Java JAXP, Creating Graphics Using Java and SVG
Processing Image Pixels, Creating Visible Watermarks in Java
Developer News -
SaaS Tool Offers Custom Database Development    May 9, 2008
Microsoft’s Automated Agent: Can We Talk?    May 7, 2008
Borland Finally Sells CodeGear    May 7, 2008
Red Hat Heads For The JON 2.0    May 7, 2008
Free Tech Newsletter -

Project Management Guide: Developing a Web Site. Best Practices, Tips and Strategies. Download Exclusive eBook Now.

Graphics, using Java and JDOM with SVG, Part 2
By Richard G. Baldwin

Java Programming Notes # 2224


Preface

General

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.

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.

Figures

  • 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.

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.

General background information

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.

Preview

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

The program named Svg17

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.

The program named Svg18

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