Saturday, February 26, 2011

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

Last post showed you how to take a picture using the device's camera and then send it to a servlet in Base64 format. But sometimes, you just need to send a picture that is either inside the application or in your memory card (sd card, etc.).

So in this post, we are going to convert images inside the application to byte arrays so you can use the methods showed in the last post in order to send thouse images to the servlet. Also, we will see how to get byte arrays from a file with the help of the FileConnection API, but we are not getting in details with this API. I will share some links that make a great work for getting started with it.

The following method takes a String as parameter and looks inside the application to get the bytes:

  
     //inside MIDlet class...

   /**
   * Reads the local image resource and returns an
   * array of bytes representing the image
   * @param imgPath path to the image inside the app
   * @return array of bytes representing the image
   */
  public byte[] loadFromApp(String imgPath) {

    byte[] imgBytes = null;
    ByteArrayOutputStream baos = null;
    InputStream in = null;
    try {

      baos = new ByteArrayOutputStream();
      //this image is inside my mobile application
      in = this.getClass().getResourceAsStream(imgPath);
      byte[] buffer = new byte[1024];
      int n = 0;
      while ((n = in.read(buffer)) != -1) {
        baos.write(buffer, 0, n);
      }

      imgBytes = baos.toByteArray();

    } catch (Exception ex) {
      ex.printStackTrace();
    } finally {
      //whatever happends close the streams
      if (baos != null) {
        try {
          baos.close();
        } catch (Exception ex) {
        }
      }
      if (in != null) {
        try {
          in.close();
        } catch (Exception ex) {
        }
      }
    }

    return imgBytes;
  }

So you see it's pretty straightforward, just get the resource as a stream and start passing the bytes from one stream to another, at the end the ByteArrayOutputStream let you get the byte array.

But, what if you just want to send a picture you just take and is saved in your memory card (sd card, micro sd card...etc.)? well you have to access the file with the help of the FileConnection API. Here are some great links to help you get started with this API:

For getting started right from oracle:

For some considerations when using the API in real devices:

OK, after you understand how the API works and can access the files, you can use the following method to get the byte arrays of the files. You will realize that this method is very similar to the previous one:

  
     //inside MIDlet class...

   /**
   * Reads the image and returns an array of bytes
   * @param imgPath Path to the image inside the Device or
   * the memory card
   * @return array of bytes representing the image
   */
  public byte[] loadFromDevice(String imgPath) {

    byte[] imgBytes = null;
    ByteArrayOutputStream baos = null;
    InputStream in = null;
    FileConnection file = null;
    try {
      //Access to the file
      file = (FileConnection) Connector.open(imgPath);
      //Checks whether the file exist
      if (!file.exists()) {
        return new byte[0];
      }
      baos = new ByteArrayOutputStream();
      in = file.openInputStream();
      byte[] buffer = new byte[1024];
      int n = 0;
      while ((n = in.read(buffer)) != -1) {
        baos.write(buffer, 0, n);
      }

      imgBytes = baos.toByteArray();

    } catch (Exception ex) {
      ex.printStackTrace();
    } finally {
      //whatever happends close the streams
      if (baos != null) {
        try {
          baos.close();
        } catch (Exception ex) {
        }
      }
      if (in != null) {
        try {
          in.close();
        } catch (Exception ex) {
        }
      }
      if (file != null) {
        try {
          file.close();
        } catch (Exception ex) {
        }
      }
    }

    return imgBytes;
  }

There's one important thing to keep in mind with this API... not all devices implement it, so you should check if the device supports it before using it. The following method lets you check the availability of the API:

  
     //inside MIDlet class...

  /**
   * Checks whether the device has support for
   * the FileConnection API
   * @return true if and only if the device
   * supports the API false otherwise
   */
  private boolean checkFileSupport() {
    if (System.getProperty
       ("microedition.io.file.FileConnection.version") != null) {
      return true;
    }

    return false;
  }

I hope you can use this methods in your applications and start sharing some images!

see ya soon!


References:

Getting Started with the FileConnection APIs. December 2004. Oracle [online].
Available on Internet: http://developers.sun.com/mobility/apis/articles/fileconnection/
[accessed on February 26 2011].

Working with the Java ME FileConnection API on Physical Devices. March 2007. Java.net[online].
Available on Internet: http://today.java.net/article/2007/03/27/working-java-me-fileconnection-api-physical-devices
[accessed on February 26 2011].