Solved

J2ME displaying an image file

Posted on 2004-11-02
438 Views
Last Modified: 2008-01-09
Hello,

Anyone can help me to create a program that can display a jpeg file ? As simplest as possible :)

Thank you
0
Question by:tambun
    13 Comments
     
    LVL 9

    Expert Comment

    by:OBCT
    It's against the EE regulations to write code for you however you should look into javax.microedition.lcdui.Image and javax.microedition.lcdui.ImageItem.
    At the moment the only images supported are of a PNG format...hopfully there will be more support in the furture. More information is in the documentation.
    For your application you'll need a form to hold the ImageItem or the other option is to display the Image in a canvas.

    If you have any other questions, let me know. :-)

    Cheers

    -OBCT
    0
     

    Author Comment

    by:tambun
    Thanks for your information. Is that true that the only image format supported is PNG ? Because I run the "photoalbum" demo application from J2ME Wireless Toolkit 2.1, it can display JPEG without any problem.

    My case is, I would like to display an image from http. This image will be changed periodically by the web server.
    So, as long as I can grab and display http://127.0.0.1:11001/image.jpg, problem solved.

    Here is my code, but it does not produce anything :( Maybe you could see if I made some mistakes.

    package jpgmidlet;

    import javax.microedition.midlet.*;
    import javax.microedition.lcdui.*;
    import java.util.Vector;
    import java.io.IOException;
    import java.io.DataInputStream;
    import javax.microedition.io.HttpConnection;
    import javax.microedition.io.ContentConnection;
    import javax.microedition.io.Connector;

    public class JpgMidlet extends MIDlet implements Runnable
    {
       private Display display;
       private Thread thread;
       private Frame frame;

       public JpgMidlet() {  
          display = Display.getDisplay(this);

          frame = new Frame();
       }

       protected void startApp() {
          run();
       }

       protected void pauseApp() {
       }

       protected void destroyApp(boolean unconditional) {
       }

       private Image createImage(String name) throws IOException {

           // Load from a ContentConnection
           HttpConnection c = null;
           DataInputStream is = null;
               
           try {
              c = (HttpConnection)Connector.open(name);
              int status = c.getResponseCode();
           
              if (status != 200) {
                 throw new IOException("HTTP Response Code = " + status);
              }

              int len = (int)c.getLength();
              String type = c.getType();

              if (len > 0) {
                  is = c.openDataInputStream();
                  byte[] data = new byte[len];
                  is.readFully(data);
                  return Image.createImage(data, 0, len);
              } else {
                  throw new IOException("Content length is missing");
              }

          } finally {
                if (is != null)
                 is.close();

              if (c != null)
                 c.close();
           }

       }


       public void run() {
          Image theimage = null;

          String name = "http://127.0.0.1:11001/image.jpg";  
          try {
             theimage = Image.createImage(name);
          } catch (IOException err) {
          }

          frame.setImages(theimage);
          display.setCurrent(frame);

       }
    }

    class Frame extends Canvas {

        private Image image;

        Frame() {
           image = Image.createImage(getWidth(), getHeight());
        }

        void setImages(Image theimage) {
           Image image = theimage;  
        }

        protected void paint(Graphics g) {
           g.drawImage(image, 0, 0, Graphics.LEFT|Graphics.TOP);
        }

    }
    0
     
    LVL 9

    Expert Comment

    by:OBCT
    Just taking a quick look at the code, I can only see one problem and it's a common one so no need to feel silly :-).

    You have implemented the Runnable interface and added the Run method which is all fine.
    In the startApp() method you've called the run() method directly. By doing this, the startApp() method will not return until the run() method has returned rather than letting the thread run while the MIDlet continues to execute.

    The correct way to do this is to use the instance of Thread (which you have in your class variables), then specify the Runnable target.
    Seeing as the MIDlet has implemented the Runnable interface, you can use "this" as the target because the current instance implements Runnable.

    e.g. thread = new Thread(this);

    What this is doing is telling the Thread class that there is a run() method in your MIDlet and when the thread runs, the run() method will be called.
    To start the thread, you MUST call thread.start().
    This registers the Thread with the ThreadMonitor inside the VM which will take care of the rest for you.

    I hope this makes sense.

    http://java.sun.com/docs/books/tutorial/essential/threads/
    Here is a much more detailed explanation of Java and Threads. It will cover just about everything you will ever need to know about them.

    http://developers.sun.com/techtopics/mobility/midp/articles/threading2/
    This article is more relevant to the platform you are working with.

    As for the PNG format for Images, I tripple checked the documentation and MIDP will only support PNG.
    Here's what the doc says...

    PNG Image Format
    Implementations are required to support images stored in the PNG format, as specified by the PNG (Portable Network Graphics) Specification, Version 1.0. All conforming MIDP implementations are also conformant to the minimum set of requirements given by the PNG Specification. MIDP implementations also must conform to additional requirements given here with respect to handling of PNG images. Note that the requirements listed here take precedence over any conflicting recommendations given in the PNG Specification.

    createImage
    public static Image createImage(byte[] imageData, int imageOffset, int imageLength)
    Creates an immutable image which is decoded from the data stored in the specified byte array at the specified offset and length. The data must be in a self-identifying image file format supported by the implementation, such as PNG.

    So the image being in a JPG format is bound to cause problems.
    Although the WTK may load JPG images, a real phone may cause totally different results.
    Emulators a great, however MIDP applications will always perform differently on real phones.

    Cheers :-)

    -OBCT
    0
     

    Author Comment

    by:tambun
    I tried to do that in the startApp() :

       thread = new Thread(this);
       thread.start();

    But still, it does not produce anything. I made this source code based on the "photoalbum" demo of WTK2.1 which is run perfect.

    Is there any way to display a message for debugging purposes ?

    Displaying thing in the J2ME is difficult concept for me :(
    0
     
    LVL 9

    Expert Comment

    by:OBCT
    Change your run() method to the following...

    public void run()
    {
        Image theimage = null;
        String name = "http://127.0.0.1:11001/image.jpg";  
       
        try
        {
            theimage = Image.createImage(name);
        }
        catch (IOException err)
        {
            err.printStackTrace();
        }

        frame.setImages(theimage);
        display.setCurrent(frame);
    }

    The method is very similar except if an exception occurs, the stack will be dumped into the console so you can track down the error.
    If an exception is thrown, post the stack trace.

    Apart from all I have specified, I can't really see any problem at all.
    Have you tried this on a real phone? If so, did the MIDlet display anything?
    0
     

    Author Comment

    by:tambun
    Here is the stack report

    java.io.IOException
          at javax.microedition.lcdui.ImmutableImage.getImageFromStream(+15)
          at javax.microedition.lcdui.ImmutableImage.<init>(+20)
          at javax.microedition.lcdui.Image.createImage(+8)
          at jpgmidlet.JpgMidlet.run(+31)
    0
     
    LVL 9

    Accepted Solution

    by:
    Ahhh I seemed to have missed this one...

    In your run() method, you've made a call directly to the Image classes createImage() rather than your own implementation.
    The Image.createImage() method attempts to load an image from the application's resources rather than from a HttpConnection.

    Try this as your run method, then we'll take it from there.

    public void run()
    {
        Image theimage = null;
        String name = "http://127.0.0.1:11001/image.jpg";  
       
        try
        {
            theimage = createImage(name); // Call createImage from this class to load the image via a HttpConnection
        }
        catch (IOException err)
        {
            err.printStackTrace();
        }

        frame.setImages(theimage);
        display.setCurrent(frame);
    }
    0
     

    Author Comment

    by:tambun
    I still got the exception :

    java.io.IOException
         at javax.microedition.lcdui.ImmutableImage.getImageFromStream(+15)
         at javax.microedition.lcdui.ImmutableImage.<init>(+20)
         at javax.microedition.lcdui.Image.createImage(+8)
         at jpgmidlet.JpgMidlet.run(+33)  
    0
     

    Author Comment

    by:tambun
    Ok my mistake, sorry.

    I dont get any exception.

    But still no display ...

    I think the problem is now displaying theimage.
    0
     

    Author Comment

    by:tambun
    Finally, I got the display !

    By changing to this in the Frame() class :

        void setImages(Image theimage) {
           image = theimage;  
        }

    But I think the thread only run once ....
    0
     
    LVL 9

    Expert Comment

    by:OBCT
    Ohhhh nicley spotted :-p

    Yes, threads are only meant to run the run() method once, then they go into the 'dead' state.
    Seeing as your application doesn't really have a need for a thread, you can use everything in the run method, in your startApp() method.
    Unless you have a process that you want to run in the background, theres no need for a thread.
    You can remove the Runnable interface and the Thread instance. This will also improve the performance of your app because now there isn't any thread overhead.

    Are there any other problems or questions?
    0
     

    Author Comment

    by:tambun
    It works !!!!!

    Thanks ! here is the final code.

    package jpgmidlet;

    import javax.microedition.midlet.*;
    import javax.microedition.lcdui.*;
    import java.util.Vector;
    import java.io.IOException;
    import java.io.DataInputStream;
    import javax.microedition.io.HttpConnection;
    import javax.microedition.io.ContentConnection;
    import javax.microedition.io.Connector;

    public class JpgMidlet extends MIDlet implements Runnable
    {
       private Display display;
       private Thread thread;
       private Frame frame;

       public JpgMidlet() {  
       }

       protected void startApp() {
          display = Display.getDisplay(this);
          frame = new Frame();

          Thread thread = new Thread(this);
          thread.start();
       }

       protected void pauseApp() {
       }

       protected void destroyApp(boolean unconditional) {
       }

       private Image createImage(String name) throws IOException {

           HttpConnection c = null;
           DataInputStream is = null;
               
           try {
              c = (HttpConnection)Connector.open(name);
              int status = c.getResponseCode();
           
              if (status != 200) {
                 throw new IOException("HTTP Response Code = " + status);
              }

              int len = (int)c.getLength();
              String type = c.getType();

              if (len > 0) {
                 is = c.openDataInputStream();
                 byte[] data = new byte[len];
                 is.readFully(data);
                 return Image.createImage(data, 0, len);
              } else {
                 throw new IOException("Content length is missing");
              }

           } finally {
              if (is != null)
                 is.close();

              if (c != null)
                 c.close();
           }

       }


       public void run() {
          Image theimage = null;

          String name = "http://127.0.0.1:11001/image.jpg";  
         
          while(true) {
            try {
               theimage = createImage(name);
            } catch (IOException e) {
              e.printStackTrace();
            }

            frame.setImages(theimage);
            display.setCurrent(frame);

          }
       }
    }

    class Frame extends Canvas {

        private Image image;
        private Thread tr;

        Frame() {
           image = Image.createImage(getWidth(), getHeight());    
        }

        void setImages(Image theimage) {
           image = theimage;  
           repaint();
           serviceRepaints();
        }

        protected void paint(Graphics g) {
           g.drawImage(image, 10, 50, Graphics.LEFT|Graphics.TOP);
        }

    }
    0
     
    LVL 9

    Expert Comment

    by:OBCT
    Glad to have helped :-)
    Good luck with your future J2ME apps!

    Cheers

    -OBCT
    0

    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone.

    Featured Post

    Product Review - Android Remix

    Come along for the ride with our Senior Product Manager, Brian Matis, as he reviews the Android Remix.

    Coaxial cable bending There are several factors that govern the selection of coaxial cable for your Machine to Machine (M2M) application: the location of cable runs, either indoor or outdoor, inside or outside an enclosure, maximum bending and the…
    Multi-source agreements are important because they set standards that all manufacturers should follow to ensure that devices are compatible with multiple vendors. The multi-source agreement (MSA) is an agreement that establishes how multiple vendors…
    This Micro Tutorial will show you how to maximize your wireless card to its maximum capability. This will be demonstrated using Intel(R) Centrino(R) Wireless-N 2230 wireless card on Windows 8 operating system.
    Viewers will learn how to connect to a wireless network using the network security key. They will also learn how to access the IP address and DNS server for connections that must be done manually. After setting up a router, find the network security…

    846 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    12 Experts available now in Live!

    Get 1:1 Help Now