Using J2ME for Color Graphics

Rinitha KS

Creating graphics using MIDlets is a fascinating topic. Here is a detailed practical approach on how to go about it. Creating the Servlets and MIDlets form an important part of the discussion 

J2ME is a wonderful technology, which has the facility for creating applications with colorful graphics, which is not possible in WAP technology.

J2ME supports only images of PNG (Portable Network Graphics) format. As it uses a lossless compression algorithm, which creates images that are usually a bit smaller than GIF it can be used with low-color (256 or less), grayscale and true-color images.

PNG is not so popular as GIF and JPG, which are widespread. So you may feel that this is the weak point in J2ME. There is nothing to worry about it. Before starting programming with MIDlets, we should keep in mind that we are programming for MIDP (Mobile Information Device Profile) i.e., limited memory devices (128 KB ROM, 32 KB RAM) such as pagers, mobile phones, PDA (Personal Digital Assistant) etc. So, J2ME uses only limited set of packages as compared to J2SE. It specifies some subsets of J2SE APIs as well as additional APIs.

In this article, we are going to see three methods of creating Graphics in J2ME using MIDlet. They are as follows:

1. Creating color pie chart locally i.e., within MIDlets.
2. Creating color rectangle with text in the server-side and accessing from MIDlets.
3. Converting images of type GIF, JPG etc. to PNG format.     

Before dealing with these concepts, we should do the environment settings. This is the general procedure for developing Midlet applications. Assume that WTK104 (Wireless Toolkit 1.0.4) is installed in the c: drive (This software is available in Developer IQ Magazine’s CD). The following steps are followed:

1. Open Dos window and go to C:\WTK104\apps folder.
2. Create your own working directory in the path mentioned above, i.e.,
C:\WTK104\apps> md  lsns
C:\WTK104\apps> cd  lsns
3. Create a directory structure as given below:
C:\WTK104\apps\lsns> md bin
C:\WTK104\apps\lsns> md src
C:\WTK104\apps\lsns> md res
C:\WTK104\apps\lsns> md classes
C:\WTK104\apps\lsns> md tmpclasses

4. Create all the source files in ‘src’ folder and resource files in ‘res ‘ folder.
5. Next step is to start the Wireless Browser.

    Start Menu -> Programs -> J2ME WirelessToolKit1.0 -> KToolbar.

6. Create New Project and give Project Name as your working folder name i.e., 'lsns' and MIDlet class name as your source class filename. We can load more class files in     the same Project itself. For doing this, click 'Settings' and goto 'MIDlets' tab. Now we can add our midlet class files.

7. Compile MIDlet class files by clicking 'Build'.
8. Run the application by clicking 'Run'.

1. Creating color pie chart using MIDlets:
Create piechartMidlet.java in C:\WTK104\apps\lsns\src folder as given below: (Code 1)

piechartMidlet.java

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.io.*;

public class piechartMidlet extends MIDlet implements CommandListener
{
Display         display;
Form             form1;
TextField      text1, text2, text3, text4;
Command    button1, button2;

   public piechartMidlet()
{
display  =  Display.getDisplay(this);
form1    =  new Form("Type the angles");
text1      =  new TextField (null,"10",100,TextField.ANY);
text2      =  new TextField (null,"20",100,TextField.ANY);
text3      =  new TextField (null,"30",100,TextField.ANY);
text4      =  new TextField (null,"40",100,TextField.ANY);
form1.append(text1);
form1.append(text2);
form1.append(text3);
form1.append(text4);
button1 = new Command ("Show",Command.OK,1);
button2 = new Command("Exit",Command.EXIT,0);
form1.addCommand(button1);
form1.addCommand(button2);

      form1.setCommandListener(this);

   }
public void startApp()
{
display.setCurrent(form1);     
}
public void pauseApp() {  }
public void destroyApp (boolean b) {  }

public void commandAction(Command cmd, Displayable d)
{
if   (cmd==button1)
{
int n1 = Integer.parseInt (    text1.getString()   );
int n2 = Integer.parseInt(     text2.getString()   );
int n3 = Integer.parseInt(     text3.getString()   );
int n4 = Integer.parseInt(     text4.getString()   );

         display.setCurrent(new piecharttest(n1,n2,n3,n4));      
}
else if (cmd == button2)
{
text1.setString(" ");
text2.setString(" ");
text3.setString(" ");
text4.setString(" ");
display.setCurrent(form1);
}

   }

   class piecharttest extends Canvas
{
int a,b,c,d;
int n1,n2,n3,n4;
public piecharttest(int n1, int n2, int n3, int n4)
{
this.n1 = n1;
this.n2 = n2;
this.n3 = n3;
this.n4 = n4;
}

      public void paint(Graphics g)
{
int   w = this.getWidth();
int   h = this.getHeight();

         g.fillRect(0, 0, w, h);

         int t = n1 + n2 + n3 + n4;
a = n1 * 360 / t;
b = n2 * 360 / t;
c = n3 * 360 / t;
d = n4 * 360 / t;

         int n = 3;   // edge
int dm;   // diameter
if ( w > h )
{
dm = h - n * 2;
}
else
{
dm = w - n * 2;
}

         g.setColor(255, 255, 255);
g.fillArc(n, n, dm, dm, 0, a);
g.setColor(255, 0, 0);
g.fillArc(n, n, dm, dm, a, b);
g.setColor(0, 255, 0);
g.fillArc(n, n, dm, dm, a+b, c);
g.setColor(0, 0, 255);
g.fillArc(n, n, dm, dm, a+b+c, d);

      }
}
}

We don't need to set path & classpath. It is taken care of by the toolkit itself. The toolkit I mentioned here is a wireless toolkit.
Once we created the source file, do the steps from (5) in the general procedure methodically and carefully. While building the project, the toolkit checks for the syntax and shows errors if any. Otherwise, it creates lsns.jar and lsns.jad (Java Archieve Descriptor) and save them in \bin directory. And the successfully created class files are stored in \classes and \tmpclasses. In piechartMidlet.java program, there are four text boxes for entering degree values for the pie chart. After giving the input, click the right hand side button ('Show'). You'll get the colorful pie chart depending on the degree values.

2. Creating color rectangle with text in Servlets and accessing from MIDlets
Delivering non-texual, i.e., binary data from Servlet is not so simple as one expected. J2SE doesn't have necessary packages for doing this. But many free and commercial packages are available in the market. In standard Servlets, this concept can be done by using ACME package, which supports images of type GIF/JPG. As far as J2ME is concerned, it also creates trouble as it has the limitation of accepting only PNG format as mentioned above.

After searching in the web, I came to know that there was a package called Sun's JIMI (Java Image Management Interface), which is free, downloadable, and 3.7 MB size. The essence of this package is 'JimiProClasses.zip' which is 448 KB only. This zip file is enough for creating dynamic image applications and conversion of one type of an image to other type from Servlets.

In order to download the JIMI package from http://java.sun.com/products/jimi/,
copy JimiProClasses.zip file to c:\jsdk2.0\src. I'm testing this servlet using servletrunner. Create your own working directory 'midletlsns' in C:\ for storing servlet files. Open Dos Window and go to your folder. Set path and classpath as given below.

C:\midletlsns> set path=c:\windows\command; c:\jdk1.3\bin;
C:\midletlsns>setclasspath=c:\jsdk2.0\src; c:\midletlsns;
c:\jsdk2.0\src\JimiProClasses.zip;
Create dynamicServlet.java in C:\midletlsns folder and compile it (Code 2).

 

dynamicServlet.java

import com.sun.jimi.core.*;
import com.sun.jimi.core.util.*;
import java.awt.*;
import java.io.*;
import java.net.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.awt.*;

public class dynamicServlet extends HttpServlet
{
public void doPost( HttpServletRequest    request,HttpServletResponse response )
throws IOException, ServletException
{
response.setContentType("image/png");

        Frame f1 = new Frame();
f1.addNotify();

        Image img1 = f1.createImage(100,100);
Graphics g = img1.getGraphics();

        g.setColor(Color.red);
g.fillRect(10,10,80,50);
g.setFont(new Font("Serif",Font.BOLD,12));
g.setColor(Color.black);
g.drawString("Welcome",20,20);

        ByteArrayOutputStream bout = new ByteArrayOutputStream();
try {

        Jimi.putImage( "image/png", img1, bout );

        }   catch( Exception e )   {   System.out.println(""+e);   }

 

        byte[] data = bout.toByteArray();
int n=data.length;
try{
DataOutputStreamdos   =  new
DataOutputStream(response.getOutputStream());
dos.write(data,0,n);
System.out.println("byte array formed");
}catch(Exception e)    {   System.out.println(""+e);       }
}
}

We just completed the servlet part. Next thing is to write the corresponding midlet to receive graphics image, which is created dynamically and delivered from servlet. For this create dynamicMidlet.java in C:\WTK104\apps\lsns\src folder (Code 3).

dynamicMidlet.java

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import java.io.*;

public class dynamicMidlet extends MIDlet implements CommandListener
{
Display        d;
Form            f1;
Command   c1, c2;
Item             item;

    public dynamicMidlet()
{
d = Display.getDisplay(this);
f1 = new Form(" ");
c1 = new Command( "Show",Command.OK,1);
c2 = new Command("Exit",Command.EXIT,0);
f1.addCommand(c1);
f1.addCommand(c2);
f1.setCommandListener(this);
}
public void startApp()
{
d.setCurrent(f1);
}
public void pauseApp()  {  }
public void destroyApp(boolean b) { }

public void commandAction(Command c,             Displayable ds)
{
if (c == c1)
{
try{
String url =   "http://localhost:8080/servlet/dynamicServlet";
System.out.println(url);

            HttpConnection hc = (HttpConnection)   Connector.open(url);
hc.setRequestMethod(HttpConnection.POST);
System.out.println("Connected");

int l = (int)hc.getLength();
byte[] data = new byte[l];

                         try{
DataInputStream in = new DataInputStream  (hc.openInputStream());
in.readFully(data);                    

        }catch(IOException e )  {  System.out.println(""+e);  }

 Image img = Image.createImage  (data,0,data.length);

             item = new ImageItem(null,img,0,null);
f1.append(item);
}catch (IOException e) { }
}
if (c == c2)
notifyDestroyed();
}
}   

Start the servletrunner (Code 4)

C:\jsdk2.0\bin>set   path=c:\windows\command;  c:\jdk1.3\bin;
C:\jsdk2.0\bin>set   classpath=c:\jsdk2.0\src\JimiProClasses.zip;
C:\jsdk2.0\bin>servletrunner -d c:\midletlsns

This will start the server now
.
Refer the general procedure for running the midlet application. You'll get a rectangle filled with red color and a text "Welcome" over the image.

3. Converting GIF/JPG Images into PNG format
When MIDP are used with internet, most of the images are in GIF/JPG or others. Since it is not possible to access GIF/JPG image from Midlets, there is a necessity for converting such images to PNG format. JIMI package makes this concept very simple and allows size reduction, color reduction etc. In this part, we are trying to convert any GIF/JPG file stored in the server into PNG format and send the converted image to Midlets so that we can access any image from the internet.

Create convertServlet.java under C:\midletlsns and compile it. The Set path and classpath are as given before (Code 5).

convertServlet.java

import com.sun.jimi.core.*;
import com.sun.jimi.core.util.*;
import java.awt.*;
import java.io.*;
import java.net.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class convertServlet extends HttpServlet
{
public void doPost( HttpServletRequest request, HttpServletResponse response )
throws IOException, ServletException
{
String imgurl  = file:///c://images/mathew.gif;
int colors=256;
int minw= 75;
int maxw= 75;
int minh= 75;
int maxh= 75;
boolean reduce = false;

        URL url= new URL( imgurl );

      Image img = Jimi.getImage(url, Jimi.SYNCHRONOUS |Jimi.IN_MEMORY );
System.out.println("Got Image");

        int     width = img.getWidth( null );
int     height = img.getHeight( null );
boolean scale = false;

        if( width < minw )
{
width = minw;
scale = true;
}
else if( width > maxw)
{
width = maxw;
scale = true;
}
if( height < minh )
{
height = minh;
scale = true;
}
else if( height > maxh )
{
height = maxh;
scale = true;
}
// Adjust height and width
if( scale )
{
img = img.getScaledInstance( width, height, Image.SCALE_SMOOTH );
GraphicsUtils.waitForImage( img );
}
// Now adjust the color depth...
if( reduce )
{
try
{
ColorReducer reducer = new   ColorReducer ( colors, true );
img = reducer.getColorReducedImage( img );
GraphicsUtils.waitForImage( img );
} catch(Exception e) { }
}
Frame f1 = new Frame();
f1.addNotify();
Image img1 =f1.createImage(100,100);

      Graphics g = img1.getGraphics();
g.drawImage(img,0,0,75,75,f1);
g.setFont(new Font("Serif",Font.BOLD,12));
g.setColor(Color.black);
g.drawString("Mathew",20,30);

ByteArrayOutputStream bout = new ByteArrayOutputStream();
try {

 Jimi.putImage( "image/png", img1, bout );

} catch( JimiException e )  {   System.out.println(""+e);     }
System.out.println("Byte Array formed");

        byte[] data = bout.toByteArray();

        // Send it out!
response.setContentType("image/png" );
response.setContentLength( data.length );
DataOutputStream dos = new
DataOutputStream ( response.getOutputStream() );
        dos.write( data,0,data.length );
System.out.println("Image sent");
}
}

Start the servletrunner as before. Midlet Program for this servlet is same as dynamicMidlet.java. But change the URL as

"http://localhost:8080/servlet/convertServlet.java"

and save the midlet file as convertMidlet.java under C:\WTK104\apps\lsns\src. Refer the general procedure for running midlet application.








}