Tuesday, March 15, 2011

JavaMe Tips: Where is FileConnection API writing my files when using Emulator?

Last weekend when working on a FileConnection API request I realized that I didn't know where in my PC were the emulator saving the files I was creating, so I made a little research...

I know there are different kind of emulators, some of them have their own way to simulate the behavior of the sd cards from mounting a user directory to the use of default directories in user's profile.

The Emulators I was using were WTK 2.5.2 and JavaMe sdk 3.0 and I was working on Netbeans 6.9.1 and here is what I found.

For WTK 2.5.2:
Try looking in 

<Documents and settings>/<UserName>/j2mewtk/2.5.2/appdb/<TempDir>/filesystem

Where <TempDir> is a temporal directory that is created to hold all the files in runtime. Be careful, everytime you close the emulator the dirs are deleted, so make any validation you need before closing your emulator.

For JavaMe sdk 3.0:
Try looking in

<DocumentsAndSettings>/<UserName>/javame-sdk/3.0/work/<EmNum>/appdb/filesystem

Where <EmNum> is a number representing the Emulator you are using, for example, DefaultCldcPhone1 emulator is number 6.

see ya soon!

References:

How to test file reading/writing and web server app in emulator? 2008. Forum.Nokia [online].
Available on Internet: http://discussion.forum.nokia.com/forum/showthread.php?143733-How-to-test-file-reading-writing-and-web-server-app-in-emulator
[accessed on March 13 2011].

Monday, March 14, 2011

Canvas ScreenShot in JavaMe

Due to the previous posts about image encoding and image's bytes, I found an interesting question about how to get a screenshot of a canvas in JavaMe and it turns out to be very simple. Just remember, once you get the mutable (changeable) Image you should encode it in some format (i.e. PNG, JPEG, etc...).

The following is a regular canvas class which paints a smily:

  
//imports...
public class MyCanvas extends Canvas {
    
    /**
     * Creates a mutable image representing a screenshot of the
     * canvas
     * @return Screenshot as a mutable image
     */
    public Image getScreenShot() {
      Image screenshot = Image.createImage(getWidth(), 
                         getHeight());
      Graphics g = screenshot.getGraphics();
      paint(g);
      return screenshot;
    }

    /**
     * Painting method
     * @param g Graphic object to which the painting is done
     */
    public void paint(Graphics g) {
      //change to black an paint the whole background
      g.setColor(0x000000);
      g.fillRect(0, 0, getWidth(), getHeight());

      //change to yellow
      g.setColor(0xFFFF00);
      //left|top position of the face so it seems centered
      int xCenter = (getWidth() - 80) / 2;
      int yCenter = (getHeight() - 80) / 2;
      //draw the face
      g.fillArc(xCenter, yCenter, 80, 80, 0, 360);
      //change to black color
      g.setColor(0x000000);
      //left eye
      g.fillArc(xCenter + 20, yCenter + 20, 10, 15, 0, 360);
      //right eye
      g.fillArc(xCenter + 50, yCenter + 20, 10, 15, 0, 360);
      //smile
      g.fillArc(xCenter + 15, yCenter + 50, 50, 10, 180, 180);

    }
  }

Notice that the +getScreenShot():Image method is creating a mutable image of the same width and height of the canvas. It also gets the Graphic object from that image so that the paint method can draw the smily on it.

What to do with the screenshot? As I told you before, it's up to you. You can convert it to bytes, save it using RMS or FileConnection API, send it over the network...etc. But whatever you choose to do, remember to encode it using PNG or JPEG encoders, otherwise your end user may not be able to see or manipulate the image.

see ya soon!

References:

A minimal PNG encoder for J2ME. 2009. [online].
Available on Internet: http://www.chrfr.de/software/midp_png.html
[accessed on March 12 2011].

J2ME Screenshot of a Canvas. March 2010. Forum.Nokia [online].
Available on Internet: http://discussion.forum.nokia.com/forum/showthread.php?191207-J2ME-Screenshot-of-a-Canvas
[accessed on March 12 2011].

PNG Encoding in Java ME. March 2010. Forum.Nokia [online].
Available on Internet: http://wiki.forum.nokia.com/index.php/PNG_Encoding_in_Java_ME
[accessed on March 12 2011].

Saturday, March 12, 2011

Convert image to byte array (byte[]) in JavaMe II

The Convert image to byte array (byte[]) in JavaMe post  showed how you can read an image from your jar file or from the sd card of your device and convert it to a byte array. Those images are called immutable (non-changeable) and when we read them we are reading bytes in some format (png, jpeg..) but, what happens when we are creating mutable (changeable) images in memory and we want to get their bytes?

For example, what if you can create a snapshot from what a canvas is showing? or what if you create an application that reads an image and apply some effects like blur, resizing, etc.?

You have to be very careful in these situations because you could, some how, get the bytes from the mutable image, but you certanly need to encode them (format them in png or jpeg...) in order to show them in your application or to write them to a file so the user can see it.

So in this post we are going to use a very simple PNG encoder. You can get more information about it using the following link:


There are some other encoders that also use compression and formats like bmp, jpeg, etc. but for this post we are just showing you an example with PNG as it is the MIDP's standard image format. Download the PNG class and add it to your project so you can use it.

In this example we are going to create a mutable image and then we are going to use some methods to get the image's bytes and finally we are going to encode those bytes using the PNG Encoder. The image is very simple, just a smily.



  
   //inside a midlet...

   /**
   * Creates a mutable (changeable) Image with a smily.
   * @return Image mutable image with a smile face on it
   */
  public Image createImage() {
    Image img = Image.createImage(100, 100);
    //Get the graphics so you can paint the image
    Graphics g = img.getGraphics();
    //change to black an paint the whole background
    g.setColor(0x000000);
    g.fillRect(0, 0, 100, 100);

    //change to yellow
    g.setColor(0xFFFF00);
    //left|top position of the face so it seems centered
    int xCenter = (img.getWidth() - 80) / 2;
    int yCenter = (img.getHeight() - 80) / 2;
    //draw the face
    g.fillArc(xCenter, yCenter, 80, 80, 0, 360);
    //change to black color
    g.setColor(0x000000);
    //left eye
    g.fillArc(xCenter + 20, yCenter + 20, 10, 15, 0, 360);
    //right eye
    g.fillArc(xCenter + 50, yCenter + 20, 10, 15, 0, 360);
    //smile...well kind of
    g.fillArc(xCenter + 15, yCenter + 50, 50, 10, 180, 180);

    return img;
  }

OK, with the last piece of code you created a mutable image (changeable) but, in what format is it? PNG? JPEG? none? That's correct you don't know, so that's why you have to encode it. The PNG encoder that we are using in this post has a method called: +toPNG(int,int,byte[],byte[],byte[],byte[]):byte[]
That's the method we are going to use in order to get our image's bytes in PNG format. But before using it, we need to get the params we are going to send. The first ints are the width and height of the image, the byte arrays are in order: alpha, red, green and... blue.

The width and height are pretty straightforward: +getWidth():int and +getHeight():int from the Image object, but to get the byte arrays you will need to do some binary operations:

  
   //inside a midlet...

  /**
   * Gets the channels of the image passed as parameter.
   * @param img Image
   * @return matrix of byte array representing the channels:
   * [0] --> alpha channel
   * [1] --> red channel
   * [2] --> green channel
   * [3] --> blue channel
   */
  public byte[][] convertIntArrayToByteArrays(Image img) {
    int[] pixels = new int[img.getWidth() * img.getHeight()];
    img.getRGB(pixels, 0, img.getWidth(), 0, 0, img.getWidth(), 
               img.getHeight());
    
    // separate channels
    byte[] red = new byte[pixels.length];
    byte[] green = new byte[pixels.length];
    byte[] blue = new byte[pixels.length];
    byte[] alpha = new byte[pixels.length];

    for (int i = 0; i < pixels.length; i++) {
      int argb = pixels[i];
      //binary operations to separate the channels
      //alpha is the left most byte of the int (0xAARRGGBB)
      alpha[i] = (byte) (argb >> 24);
      red[i] = (byte) (argb >> 16);
      green[i] = (byte) (argb >> 8);
      blue[i] = (byte) (argb);
    }

    return new byte[][]{alpha, red, green, blue};
  }

Don't you worry if you don't understand immediatly the above code, just imagine a pixel as the following int 0xAARRGGBB, where AA = alpha channel, RR = red channel, GG = green channel and BB = blue channel, so if you want to separate the alpha channel byte you need to move it to the right, that's the binary operator >> doing... and remember 1 byte = 8 bits so in order to move AA (1 byte = 8 bits) to BB you have to move it 3 times or 24 bits and when you have it in the right most byte, you can cast it to byte and then you have separated the alpha channel, got it?

Finally we need to invoke +toPNG(int,int,byte[],byte[],byte[],byte[]):byte[]  method in order to get our bytes encoded as PNG format and that's it. What to do with the encoded bytes is up to you... send them over the network, write them to a file using FileConnection API, etc. You can also check my previous posts if you need more documentation.

see ya soon!


References:

A minimal PNG encoder for J2ME. 2009. [online].
Available on Internet: http://www.chrfr.de/software/midp_png.html
[accessed on March 12 2011].

J2ME Screenshot of a Canvas. March 2010. Forum.Nokia [online].
Available on Internet: http://discussion.forum.nokia.com/forum/showthread.php?191207-J2ME-Screenshot-of-a-Canvas
[accessed on March 12 2011].

PNG Encoding in Java ME. March 2010. Forum.Nokia [online].
Available on Internet: http://wiki.forum.nokia.com/index.php/PNG_Encoding_in_Java_ME
[accessed on March 12 2011].