×

Discussion Board

Results 1 to 15 of 15
  1. #1
    Registered User
    Join Date
    Apr 2010
    Location
    Croatia
    Posts
    10

    J2ME Scaling big JPEG files on S60 5th ed and CS001269

    Hi!


    I have searched forum for every side and angle but AFAIK there is no answer to this question. If there is, I humbly apologize!

    I'm trying to load and resize images taken by the Nokia 5800 camera. At the highest resolution JPEG files are about 400-600 KB, and equivalent memory object could be about 9MB (1536x2048 x 3 bytes = 9MB), so this is large.

    My question is simple, is there a way to load and resize images taken by the 5800 camera at the highest resolution using J2ME?

    Comment in the CS001269 suggests that one should use clipping and drawRegion, but I don't see how this could help, because it is not possible to load image of that size.

    This:

    Code:
    image = Image.createImage("/1536x2048.jpg");
    results in "Out of memory". I have tried the same thing with 768x1024 JPEG (2,25 MB), and it works fine.

    APIBridge for J2ME doesn't support raster image resizing. Is there a way out of this for J2ME? From current perspective this thing looks to me rather hopeless. I could write my own JPEG decoder and read image byte by byte, resize it on the fly, but this is too much work for just trying to load image form the mobile phone fileystem.

    LWUIT has Image class with scale() method, or something similar, can this be achieved using LWUIT? Or mybe some other free library? Possibly something from Nokia that I couldn’t find? Or should I use Qt?

  2. #2
    Super Contributor
    Join Date
    Jun 2003
    Location
    Cheshire, UK
    Posts
    7,395

    Re: J2ME Scaling big JPEG files on S60 5th ed and CS001269

    If you can't load the image in the first place, then there's not much you can do. LWUIT doesn't do magic, it's just written in Java.

    Yes, you could write code to resize the JPEG data, uncompressing it chunk by chunk and creating a compressed (smaller) JPEG at the same time. Yes, writing that would be a hideous experience. I'm pretty sure the writers of LWUIT didn't go to that length.

    Could you do it in C++? Maybe, though not if you can't load the image. I'm surprised you get an OutOfMemoryError loading the image, unless you have a lot of other stuff in memory at the same time.

    Unless, maybe, someone else has some advice that doesn't repeat my confirmation of your belief that you're doomed.

    Graham.

  3. #3
    Regular Contributor
    Join Date
    Nov 2008
    Posts
    75

    Re: J2ME Scaling big JPEG files on S60 5th ed and CS001269

    Hi,

    Two thoughts: first, if you are resizing images to see them on the phone, then why take them in such high resolution (the phone's display is only about 360x640).

    If you do have your heart set on resizing the high res. images, the only straightforward approach I can see is to write a little server (to do the resizing), send the image off the server, and get back the resized image.

    Cheers,
    Matt
    UnME2, Inc.
    Cheers,

    Matt Brenner
    UnME2, Inc.

  4. #4
    Registered User
    Join Date
    Apr 2010
    Location
    Croatia
    Posts
    10

    Re: J2ME Scaling big JPEG files on S60 5th ed and CS001269

    Hi graham! Thanx for your help!

    Quote Originally Posted by grahamhughes View Post
    If you can't load the image in the first place, then there's not much you can do. LWUIT doesn't do magic, it's just written in Java.

    Could you do it in C++? Maybe, though not if you can't load the image. I'm surprised you get an OutOfMemoryError loading the image, unless you have a lot of other stuff in memory at the same time.

    Graham.
    I'm also puzzled with OutOfMemoryError that I'm getting because CS001269 code can load my 1536x2048.jpg, and if I use this method below it can even resize loaded raster. Although image is not complete after resizing, there is big white area in the part of image that previously wasn't shown on the screen.

    Code:
        private Image createThumbnail(Image image) {
            int sourceWidth = image.getWidth();
            int sourceHeight = image.getHeight();
    
            int thumbWidth = 360;
            int thumbHeight = -1;
    
            if (thumbHeight == -1) {
                thumbHeight = thumbWidth * sourceHeight / sourceWidth;
            }
    
            Image thumb = Image.createImage(thumbWidth, thumbHeight);
            Graphics g = thumb.getGraphics();
    
            for (int y = 0; y < thumbHeight; y++) {
                for (int x = 0; x < thumbWidth; x++) {
                    g.setClip(x, y, 1, 1);
                    int dx = x * sourceWidth / thumbWidth;
                    int dy = y * sourceHeight / thumbHeight;
                    g.drawImage(image, x - dx, y - dy,
                            Graphics.LEFT | Graphics.TOP);
                }
            }
    
            Image immutableThumb = Image.createImage(thumb);
    
            return immutableThumb;
        }
    On the other hand, if I try to load image with intent to draw it on Canvas I immediately get OutOfMemory. Here is the code. Nothing much there, simple proof of concept.

    Code:
    import javax.microedition.lcdui.*;
    import javax.microedition.midlet.MIDlet;
    
    public class ScaleImageCanvas extends Canvas implements CommandListener {
    
        MIDlet parent;
        Command exitCommand = new Command("Exit", Command.EXIT, 0);
        Command c1 = new Command("Load", Command.SCREEN, 0);
        Command c2 = new Command("Resize", Command.SCREEN, 0);
        Image image;
    
        public ScaleImageCanvas() {
            try {
                setCommandListener(this);
                addCommand(exitCommand);
                addCommand(c1);
                addCommand(c2);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public void loadImage() {
    
            try {
    //             image = Image.createImage("/image.png");
                image = Image.createImage("/1536x2048.jpg");
    //            image = Image.createImage("/768x1024.jpg");
    //            image = Image.createImage("/480x640.jpg");
            } catch (Exception e) {
                e.printStackTrace();
            }
            repaint();
        }
    
        private Image createThumbnail(Image image) {
            int sourceWidth = image.getWidth();
            int sourceHeight = image.getHeight();
    
            int thumbWidth = 360;
            int thumbHeight = -1;
    
            if (thumbHeight == -1) {
                thumbHeight = thumbWidth * sourceHeight / sourceWidth;
            }
    
            Image thumb = Image.createImage(thumbWidth, thumbHeight);
            Graphics g = thumb.getGraphics();
    
            for (int y = 0; y < thumbHeight; y++) {
                for (int x = 0; x < thumbWidth; x++) {
                    g.setClip(x, y, 1, 1);
                    int dx = x * sourceWidth / thumbWidth;
                    int dy = y * sourceHeight / thumbHeight;
                    g.drawImage(image, x - dx, y - dy,
                            Graphics.LEFT | Graphics.TOP);
                }
            }
    
            Image immutableThumb = Image.createImage(thumb);
    
            return immutableThumb;
        }
    
        public void paint(Graphics g) {
            if (image != null) {
                g.drawImage(image, 0, 0, Graphics.TOP | Graphics.LEFT);
            }
        }
    
        public void commandAction(Command command, Displayable displayable) {
            if (command == exitCommand) {
                if (parent != null) {
                    parent.notifyDestroyed();
                } else {
                    throw new NullPointerException();
                }
            }
    
            if (command == c1) {
                loadImage();
            }
    
            if (command == c2) {
                image = createThumbnail(image);
                repaint();
            }
        }
    
        public void setParent(MIDlet parent) {
            this.parent = parent;
        }
    }
    Could it be that Canvas takes much more resources than Form? Nevertheless, I think J2ME is not the answer. I Hope someone could convince me wrong.

    Quote Originally Posted by mattbrenner View Post
    Hi,

    Two thoughts: first, if you are resizing images to see them on the phone, then why take them in such high resolution (the phone's display is only about 360x640).

    If you do have your heart set on resizing the high res. images, the only straightforward approach I can see is to write a little server (to do the resizing), send the image off the server, and get back the resized image.
    The idea is to create standalone application that would modify images in the phone, maximum resolution roughly twice the size of the screen (increase of memory usage by factor 4). So, i don't neew 1536x2048, 768x1024 is more than enough. I think that J2ME could handle that. The only possible way out if this is to allow user to take pictures with my application which would limit resolution. I must look into JSR 135 javadoc to see if this is possible. If I go that way than user would not be able to use application on images already on the phone which is awkward. You would have to say to the user "OK, yes this works, but because of the technology limitations you can only work with small images taken by our application and we do not know how to resize big images to smaller resolution". Not a good idea.

  5. #5
    Super Contributor
    Join Date
    Jun 2003
    Location
    Cheshire, UK
    Posts
    7,395

    Re: J2ME Scaling big JPEG files on S60 5th ed and CS001269

    Do you get the OutOfMemoryError in the loadImage() method, or in the paint() method?

    I'm wondering if the implementation doesn't fully load the image (perhaps especially images of this size) until they are needed.

    The image size might exceed some kind of limit, either in memory size, or in dimensions. Those native apps (like the image viewer) might do the kind of selective JPEG decoding you suggested in your original post, in order to get around these limits. (Doing this might also be faster.)

    Graham.

  6. #6
    Registered User
    Join Date
    Apr 2010
    Location
    Croatia
    Posts
    10

    Re: J2ME Scaling big JPEG files on S60 5th ed and CS001269

    Quote Originally Posted by grahamhughes View Post
    Do you get the OutOfMemoryError in the loadImage() method, or in the paint() method?
    This is the case:

    Code:
    Exception in handleDisplayableEvent. Reason: OutOfMemoryError
      source is : ScaleImageCanvas@34093409
      p0 is     : 12
      p1 is     : 0
      p2 is     : 0
    java.lang.OutOfMemoryError
            at com.symbian.util.NativeError.checkExplicitOnly(NativeError.java:74)
            at com.symbian.util.NativeError.check(NativeError.java:106)
            at javax.microedition.lcdui.Toolkit.checkHandle(Toolkit.java:647)
            at javax.microedition.lcdui.Image.<init>(Image.java:113)
            at javax.microedition.lcdui.Image.loadImage(Image.java:412)
            at javax.microedition.lcdui.Image.createImageFromStream(Image.java:378)
            at javax.microedition.lcdui.Image.createImage(Image.java:328)
            at ScaleImageCanvas.loadImage(Unknown Source)
            at ScaleImageCanvas.commandAction(Unknown Source)
            at javax.microedition.lcdui.Displayable.callCommandAction(Displayable.java:152)
            at javax.microedition.lcdui.Displayable.commandEvent(Displayable.java:125)
            at javax.microedition.lcdui.Displayable.handleEvent(Displayable.java:167)
            at javax.microedition.lcdui.Canvas.handleEvent(Canvas.java:644)
            at javax.microedition.lcdui.Toolkit.handleDisplayableEvent(Toolkit.java:483)
            at com.symbian.lcdjava.lang.SystemExtensions._dispatchCallbacks(Native Method)
            at com.symbian.lcdjava.lang.SystemExtensions.dispatchCallbacks(SystemExtensions.java:35)
            at com.symbian.midp.runtime.KVMEventProcessor.run(KVMEventProcessor.java:23)
    OutOfMemoryError comes from the loadImage method. Obviously implementation tries to load whole image right away. There must be something that I'm doing wrong. Can it be that implementation can't load images produced by device?

    Do you really think that native apps behave same as this and because of that they have this advanced/complicated way of loading images? I doubt it.

  7. #7
    Super Contributor
    Join Date
    Jun 2003
    Location
    Cheshire, UK
    Posts
    7,395

    Re: J2ME Scaling big JPEG files on S60 5th ed and CS001269

    I have no idea. It is obviously in some way unhappy about loading the image, even though I'd expect you to have enough memory.

  8. #8
    Registered User
    Join Date
    Apr 2010
    Location
    Croatia
    Posts
    10

    Re: J2ME Scaling big JPEG files on S60 5th ed and CS001269

    Being a Java programmer I never worried to much about amount of memory available to the application. Until now.

    I've investigated this matter further, using freeMemory() method of java.lang.Runtime. There is also the totalMemory() method. Just to mention, this is all done in S60 5th ed emulator and with 768x1024 JPEG file. I must repeat all of this on my 5800.

    totalMemory()

    Code:
    System.out.println("Total memory: " + java.lang.Runtime.getRuntime().totalMemory());
    returned value 131072. Although javadoc says this should be bytes, I think this number represents amount of free memory in kilobytes. 131072KB/1024 = 128 MB.

    Subsequent calls to the freeMemory() method have given some interesting numbers. I think numbers are kilobytes and not bytes.


    Code:
    Total memory: 131072
    Free  memory: 18992 in MIDlet constructor
    MIDlet: ScaleImage
    Free  memory: 10200 end of Canvas constructor
    Free  memory: 14464 end of Canvas constructor after GC
    Free  memory: 14348 after creating Canvas
    Free  memory: 14260 after creating Canvas after GC
    Free  memory: 11180 end of startup
    Free  memory: 12768 end of startup after gc
    Free  memory: 12300 in loadImage() before loading image
    Free  memory: 12184 in loadImage() before loading image after GC
    Free  memory: 7400 in loadImage() after loading image
    Free  memory: 10568 in loadImage() after loading image after GC
    There is about 18MB of free memory in the MIDlet constructor, and 14MB after creating Canvas and calling System.gc(). Before loading image there is about 12MB of available memory. Loading image cost is ~4MB. Raw image in 24bit color is 768x1024x3bytes = 2304 KB. After final GC, is seems that image size in the memory is no more than 12184-10568=1616 KB. (?)

    I don’t take this numbers to be absolute correct because of the way Java handles memory but if this number are roughly correct, there is no way javax.microedition.lcdui.Image can load 1536x2048 JPEG file.

    Well, you could modify epoc.ini and MegabytesOfFreeMemory but I wouldn't call this a solution

  9. #9
    Super Contributor
    Join Date
    Jun 2003
    Location
    Cheshire, UK
    Posts
    7,395

    Re: J2ME Scaling big JPEG files on S60 5th ed and CS001269

    No, these are bytes. On Series 60, the initial Java heap size is very small, and it expands automatically as required. So you have to monitor both total and free in order to see how much is being used (and you have to gc() before hand, because garbage objects use memory).

    Images are often held outside the Java heap, and so might not show in your figures (other than a "stub" object inside the Java heap). You might find this article useful.

    Graham.

  10. #10
    Registered User
    Join Date
    Apr 2010
    Location
    Croatia
    Posts
    10

    Post Re: J2ME Scaling big JPEG files on S60 5th ed and CS001269

    I have read document that you have sent me (Java Memory Management). I didn't know that there are three heaps, and not just one. Assumptions I have made in my previous post were wrong. Especially because values are bytes. But does Runtime.freeMemory() return added values form all three heaps? Apparently not if values are KB.

    I have monitored amount of free memory using emulator diagnostics (ecmt). There is about 20MB of free memory before application starts. Theoretically you could squeeze 1536x2048@32bit color in 20MB. On the other hand, here are specifications of Nokia 5800

    Code:
    Maximum User Storage - 81 MB  	
    NAND Memory - 256 MB 	
    SDRAM Memory - 128 MB 	
    Memory Card type - Micro SD 	
    Memory Card Features - Hot Swap 	
    Maximum Memory Card Size - 16 GB 	
    Maximum Heap Size - Unlimited 	
    Maximum JAR Size - Unlimited
    Theoretically, looking at these numbers and if Heap size is really unlimited to the extent of available memory, loading 1536x2048 raster shouldn't be a problem. In this context I would say that J2ME implementation must enable loading images taken by the device.

    Taking all of this into account, writing my own JPEG decoder doesn't seem as a bad idea. I only wonder if Qt (QImage, QPixMap, ...) can load and resize 1536x2048 raster without much fuss about it.

    In conclusion, for now, I say that S60 5th ed J2ME implementation and javax.microedition.lcdui.Image can't load 1536x2048 JPEG.

  11. #11
    Nokia Developer Champion
    Join Date
    Feb 2009
    Location
    Noida, India
    Posts
    3,085

    Re: J2ME Scaling big JPEG files on S60 5th ed and CS001269

    If you just want to show a small icon of the image after resizing it, you can get it by read thumbs.db from the file system directory where this file is kept.

    thanks,
    ~Amitabh

  12. #12
    Registered User
    Join Date
    Apr 2010
    Location
    Croatia
    Posts
    10

    Re: J2ME Scaling big JPEG files on S60 5th ed and CS001269

    The main functionality of the application would be modifying existing images on the phone file system, most probably taken with the phone camera. I don't need full 1536x2048 resolution, as I said previously, double screen resolution will be more than enough. As I see it now, only possible solution is to create custom decoder which can load compressed file format (JPEG) and resize it on the fly. Thumbs.db can help in the process of selecting image user wants to modify.

    IMHO, this is serious issue with J2ME. There is no J2ME application than can use javax.microedition.lcdui.Image class to load JPEGs produced by the phone. I state this exclusively for S60 5th ed. It might be true for other implementations but I have tested this issue solely on S60 5th ed emulator. Effectively you can't work with images on the phone because you cant load them. You can't even resize image to smaller resolution, because you can't load them (get them into memory). Situation is worse with maximum image resolution of 2592 x 1944 (N97, X6).

    How could I check size of image and big objects heap?

    It would be nice if someone from Nokia J2ME implementation team would look into this thread and shed some light on this topic.

    It might be that I'm doing something completely wrong, so please, help!
    Last edited by m1ha3l; 2010-04-05 at 14:32.

  13. #13
    Regular Contributor
    Join Date
    Nov 2008
    Posts
    75

    Re: J2ME Scaling big JPEG files on S60 5th ed and CS001269

    Hi,

    > It would be nice if someone from Nokia J2ME implementation team would look into this thread
    > and shed some light on this topic.

    Yes, but Nokia doesn't even address bugs reported through these discussion groups, though someone always points out that you are welcome to pay for technical support to address bugs.


    > Effectively you can't work with images on the phone because you can't load them.

    Unless, of course, your app takes the picture too.
    Cheers,

    Matt Brenner
    UnME2, Inc.

  14. #14
    Super Contributor
    Join Date
    Jun 2003
    Location
    Cheshire, UK
    Posts
    7,395

    Re: J2ME Scaling big JPEG files on S60 5th ed and CS001269

    totalMemory() gives you the total current size of the Java heap. For Series 60, the heap will expand (when an allocation request cannot be satisfied after garbage collecting), in my experience up to 16Mb (for 5th Edition devices).

    Historically, Series 60 Java has held the data for Image objects (at least, immutable Images) outside the Java heap, presumably as instances of the native class. So far as I know, this is still the case.

    On 5th Edition devices (and some 3rd Edition), you can use:

    Code:
    System.getProperty("com.nokia.memoryramfree")
    to determine the actual free memory on the device. It's not entirely clear to me how useful this is. It doesn't appear that the Java heap will expand without limit. Nor is it clear that you can use all this memory.

    While I'm not aware of specific limits on Series 60, many devices do have limits beyond simply the amount of memory available. Some have a limit to the maximum size of an object. Some have a limit to the maximum size an image may have in a specific direction. When these limits are small (such as a maximum object size of 64k or a maximum image width of 256 pixels), they are easily found! The fact that I've never encountered similar limits on Series 60s might simply mean that the limits are high (and that you might now be encountering them).

    Without knowing more about the implementation (both in the Java Runtime, and in whatever part of Series 60 itself underlies the Java implementation), we can only guess.

    If I remember right, the Series 60 image decoder class supports functionality for resizing images as they're loaded, so native applications can do what you're trying to do without having to load the full-size image first. Obviously, the Java implementation is restricted by the functionality defined by the API, which includes no method for resize-on-load.

    One problem in getting input from Nokia is likely to be one of finding someone in Nokia who actually knows the answer. It's a big company with a lot of developers and a lot of software, and a lot of the software isn't even developed inside Nokia.

    Graham.

  15. #15
    Registered User
    Join Date
    Apr 2010
    Location
    Croatia
    Posts
    10

    Re: J2ME Scaling big JPEG files on S60 5th ed and CS001269

    Graham, thank you for you insight!

    Quote Originally Posted by grahamhughes View Post
    If I remember right, the Series 60 image decoder class supports functionality for resizing images as they're loaded, so native applications can do what you're trying to do without having to load the full-size image first. Obviously, the Java implementation is restricted by the functionality defined by the API, which includes no method for resize-on-load.
    Although I can understand restrictions of the J2ME API framework it is most illogical to me that you can not use standard techniques and API to do one simple thing. If device can take images of maximum resolution of MxN then there should exist software/library/code for that device that will enable loading of MxN image in some way. J2ME is not so obscure and unknown platform. On the other side, one can choose native development environment or Qt.


    Reading big images in Qt

    Somebody was obviously aware of this. Is this discrete hint to forget about J2ME?
    Last edited by m1ha3l; 2010-04-06 at 07:43.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
×