YOU can do some jazzy stuff with images using the Game API, but images have some significant shortcomings on small devices:
Images cannot be resized in MIDP. Your application is likely to run on devices with different screen sizes. While it is possible to construct resizable screens at runtime from a handful of images, it’s a little tricky.
Images cannot be rotated by arbitrary amounts. Although you can mirror images and rotate them in increments of 90 degrees, MIDP does not offer anything fancier. This limitation makes sense, because small devices are not usually equipped with the memory and processing power to perform these types of transformations on images.
Images are not an efficient representation of some pictures. For some pictures, it makes more sense to describe the picture (a vector format) than to describe every pixel in an image (a raster format).
Images do not allow for the easy manipulation of the elements of a picture.
These shortcomings are addressed by JSR 226, the Scalable 2D Vector Graphics API for J2ME. Scalable Vector Graphics (SVG) is a kind of XML for describing pictures. Because it is essentially a programming language, SVG can also describe animations and user interactions. JSR 226 is a standard API for displaying and manipulating SVG documents.
The JSR 226 SVG API applies to a specific subset of SVG called SVG Tiny. SVG and SVG Tiny are both defined by the World Wide Web Consortium. This chapter is not about SVG itself. For more information, consult the specifications:
http://www.w3.org/TR/SVG11/
http://www.w3.org/TR/SVGMobile/
In most cases, a graphic artist will create SVG documents. You probably will not have to know anything about SVG documents except for the IDs of different pieces of the document. Some information about authoring tools is available here:
https://meapplicationdevelopers.dev.java.net/uiLabs/Tools.html
As of September 2007, 28 devices are shipping with JSR 226. As part of the MSA subset, however, JSR 226 should become much more widely distributed in the near future. A list of JSR 226 devices is here:
http://svg.org/special/226_phones
The SVG API is relatively small. A half dozen classes and interfaces in javax.microedition.m2g
supply tools for rendering and manipulating SVG documents. The rest of the API, in org.w3c.dom
and two subpackages, represents the structure of an SVG document.
The simplest possible case is that you just want to display an SVG file. Your graphic artist generates the file and all you want to do is stick it on the screen.
In this case, your best friend is SVGAnimator
. SVGAnimator
takes care of a lot of details for you and just hands you a Canvas
that you can put on the device’s display.
Before you can create an SVGAnimator
, you must first load an SVG document with SVGImage
. SVGImage
inherits two static creation methods from its parent class, ScalableImage
.
The ExternalResourceHandler
knows how to retrieve any content that is referenced from within the document. You can supply null
, in which case the device tries to do something reasonable to locate external resources.
If you plan to use SVG documents that reference external resources that are part of your MIDlet suite JAR file, you must supply an implementation of ExternalResourceHandler
that retrieves the external resources from the JAR file. You have to supply a requestResource()
method that obtains an InputStream
for a given URI. The InputStream
should be passed back to the image’s requestCompleted()
method.
If you point one of the createImage()
methods at an SVG document, the returned object will of course be an SVGImage
. To load an SVG document from the MIDlet suite JAR file, you could do something like this:
The image has a viewport, which is simply the size in pixels that is used to display the image. In general, you will want to fill the available screen space, but you don’t know how much that is until later when you get a Canvas
.
Once you’ve got the image, creating an SVGAnimator
is easy.
To get the Canvas
that shows the image, call getTargetComponent()
and cast the result to Canvas
. The SVG API is designed to be flexible enough to run on Connected, Limited Device Configuration (CLDC) devices as well as on Connected Device Configuration (CDC) devices, so the return type of getTargetComponent()
is deliberately vague. This means that the SVG API can be used in a variety of GUI environments. In the MIDP world, though, the return value will always be a Canvas
.
If the SVG document you are displaying contains animation, you can tell the SVGAnimator
to show it by calling play()
. The animation runs until you call pause()
or stop()
. The example in the next section demonstrates how to correctly handle animations.
Here is a complete example that loads an SVG document and displays it.
Figure 12.1 shows the result in Sun’s emulator. The document is a picture of Duke, the Java platform mascot.
Figure 12.1. The SimplePlayerMIDlet
example
The previous MIDlet is fine for showing static content, but part of the fun about SVG is documents that move. The thumbsUp-spin.svg
document from the previous example includes an animation, but SimplerPlayerMIDlet
just shows a single still frame.
You need to kick off SVGAnimator
with the play()
method. That’s easy enough, but finding the right place to call play()
is a challenge. Ideally, you would call play()
from the showNotify()
method of the Canvas
. The problem is that the Canvas
comes from the SVGAnimator
and you can’t override the showNotify()
method.
Fortunately, you can supply an SVGEventListener
to the SVGAnimator
. This listener receives the usual Canvas
-like event notifications, such as key events, pointer events, showNotify()
, and hideNotify()
.
The next example, SimpleAnimatorMIDlet
, demonstrates this technique. The MIDlet
itself is an SVGEventListener
. When the associated Canvas
is shown, the animation is played, and when the Canvas
is hidden, the animation is paused.
Furthermore, SVGAnimatorMIDlet
makes the Canvas
full-screen and removes the Exit command. Instead, hit any key to exit the MIDlet
.
On Sun’s emulator, Duke will spin around jauntily (see Figure 12.2). Just hit a key to exit the application.
SVG documents can be accessed and manipulated using the org.w3c.dom.svg
package. For the most part, its interfaces extend the standard DOM interfaces in org.w3c.dom
and org.w3c.dom.event
.
The fundamental interface for SVG documents is SVGElement
. It contains methods for getting and setting traits, which means you can make modifications to an SVG document on the fly. SVGAnimator
is smart enough to detect changes to a document and update the screen.
Once you’ve loaded an SVGImage
, call getDocument()
to retrieve the document. You can then retrieve the top-level element (an instance of SVGSVGElement
) with getDocumentElement()
, or search for a specific element with getElementById()
.
For example, the SVG document in the previous example contains one element that defines the trademark symbol (TM). Here is the beginning of the element definition for the trademark symbol.
To find the SVGElement
for the trademark symbol, all you have to do is this:
Once you’ve got an interesting SVGElement
, you can have all sorts of fun. You can retrieve traits as text. This example retrieves the current transformation of the element:
You can also retrieve traits into more specific data types. The org.w3c.dom.svg
package includes five handy data type classes: SVGMatrix
, SVGPath
, SVGPoint
, SVGRect
, and SVGRGBColor
. If you wanted to deal with the element’s transformation as a matrix rather than a string, you could do this:
SVGElement
has a corresponding set of set
methods so that you can assign element traits using either strings or the more complex data types.
To rotate the trademark symbol around the point 182, 172, do this:
TMTweakerMIDlet
is identical to SimplePlayerMIDlet
except for showSVGImage()
, which contains extra code to rotate the trademark symbol:
On Sun’s emulator, the result looks like Figure 12.3.
Figure 12.3. TMTweakerMIDlet
rotates the trademark symbol.
If you plan to modify an SVG document while the SVGAnimator
is playing, you should take care to make those modifications in the animator’s thread. Use invokeLater()
and invokeAndWait()
for this purpose. Each method takes a Runnable
object whose run()
method is called by the animator’s thread. invokeLater()
returns immediately, while invokeAndWait()
will not return until the Runnable
has been run.
SVGAnimator
creates a Canvas
whose sole purpose in life is to display an SVG document. If you’d prefer, you can create your own Canvas
and use part of it to display the SVG document.
The magic that makes it possible is ScalableGraphics
, which knows how to render an SVGImage
on a Graphics
object. To get one, call the static factory method createInstance()
.
Inside your paint()
method, you have to bind the ScalableGraphics
to the Graphics
you are using.
Then render as many SVGImage
s as you wish. You have to specify where you want the image. The width and height of the image are determined by its viewport width and height.
When you’re finished, let the ScalableGraphics
know that it doesn’t need the Graphics
any more.
It’s prudent to place releaseTarget()
inside a finally
clause. Even if something goes wrong in render()
, you must release the ScalableGraphics
.
Here is a canvas that frames an SVGImage
with a border of blue diamonds (see Figure 12.4).
Figure 12.4. It’s easy to show SVG documents in your own canvas.
The code having to do with showing an SVG document is minimal, just one line in the constructor and three in paint()
.
To add new elements to a document, first obtain the document element and the root element as SVGSVGElement
.
Now you can create an element with the Document
’s createElementNS()
method. Set attributes on the new element with the setTrait()
methods.
To add the newly created element into the document, use appendChild()
or insertBefore()
on the root element.
Updates to a playing document should be made in the SVG document update thread. SVGAnimator
includes invokeAndWait()
and invokeLater()
methods for this purpose. You have to create a Runnable
to do some work, then pass the Runnable
to invokeAndWait()
or invokeLater()
to get the job done in the correct thread.
It is also possible to create an entirely new SVG document. If you want to explore this topic further, take a look at CreateEmptyImageDemo
, one of the MIDlets in SVGDemo
, an example bundled with the Sun Java Wireless Toolkit.
The following example, BubblesMIDlet
, shows how to add new elements to an existing image. It is an adaptation of SimpleAnimatorMIDlet
, so it uses a full-screen Canvas
. Hit any key to exit the application.
When run on Sun’s emulator, it looks like Figure 12.5.
Figure 12.5. Adding new elements to an SVG document
You have already seen how to capture Canvas
-related events in your application by using an SVGEventListener
. In addition, SVG documents themselves can respond to a few kinds of events. The SVGImage
class contains corresponding methods.
activate()
delivers a DOMActivate
event to the document.
dispatchMouseEvent()
tells the document that a pointer event has occurred.
focusOn()
delivers a DOMFocusIn
event to the specified SVGElement
. It also delivers a DOMFocusOut
event to the element that previously had the focus.
incrementTime()
sets the time used for animations.
If you are displaying an SVG document with a playing SVGAnimator
, incrementTime()
is automatically called, so a document with animations will play automatically. If you are displaying an SVG document using ScalableGraphics
, you must call incrementTime()
yourself to animate the document.
You must call the other event methods yourself if you need the SVG document to respond to them. Because few MIDP devices support pointer events, you might need to provide an alternate method for simulating pointer events. The only type of pointer event you can deliver to SVGImage
is a click with x and y coordinates, like this:
The x and y coordinates are in the viewport coordinate system, which might not be the same as the Canvas
’s coordinate system.
The next example shows one way to move focus in a document. Hitting keys toggles the focus between the trademark symbol and Duke. The example document, thumbsUp-enhanced.svg
, defines some behavior that swells up the trademark symbol when it has focus and shrinks it back down when it loses focus.
When you run this example, you’ll see the SVG document of Duke as usual. Hit any arrow key, or the select key, to change the focus. As the trademark symbol gains and loses focus, you’ll see it grow and shrink. When Duke gains focus, he jumps up, and when he loses focus, he falls back down. In the screen shot, the MIDlet has just called focusOn()
for the trademark symbol (see Figure 12.6). Hit any other key to exit.
Figure 12.6. Triggering focus events in a document
SVG is a way of describing pictures using XML. It is good for small devices because images can be easily scaled and transformed to fit the available space, and the document files can be compact. The JSR 226 SVG API provides classes for displaying and manipulating SVG documents. SVGImage
can be used to load an SVG document. SVGAnimator
knows how to display and animate an SVGImage
. The SVG API also includes a DOM API that you can use to examine and modify SVG documents. In addition, SVGImage
includes methods that allow your application to deliver events to an SVG document. For interactive animations that scale easily to different screen sizes, SVG is hard to beat. The JSR 226 SVG API includes everything you need to work with SVG Tiny documents.
3.128.205.21