In my application, I have to draw 25 images of 700*500 pixels. I am trying to use ImageIO.read() method, which is called by creating another Thread. Its taking too much time to read images. I thought since i am calling the image read functions by creating another thread my another code, i.e. my GUI, should run without waiting for ImageIO.read() to complete. But my GUI being in a different thread still waits till ImageIO.read() is complete.
Is there an another way to read images in less time other than Image.read()
Can we somehow reduce the time taken by ImageIO.read() to read the images

Recommended Answers

All 15 Replies

How long is it taking? Can you post your code re the thread you set up - if that's done right it won't hold up the GUI.

Its taking more than 3-4 sec, and during that time my UI is hanged.

I am posting some relevant part of my code

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package hsi;

import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 *
 * @author gunjan
 */
public class Example extends JPanel 
{
    int originX,originY,radii;
    float heading,headingBug;
    float range;
    float currentLat, currentLon;
    BasicStroke dashed;

    float minRange;
    
    String mapImage,oldMapImage="/images/map/mumbai/NA.png";
    int screenWidth,screenHeight;
    ArrayList<ArrayList<BufferedImage>> imageList;
    public Example()
    {
        try {
            JFrame frame = new JFrame();
            screenWidth = (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth();
            screenHeight = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight();
            frame.setSize(screenWidth,screenHeight);
            frame.setUndecorated(true);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setBackground(Color.black);
            frame.getContentPane().add(this);
            originX = screenWidth / 2;
            originY = screenHeight - 150;
            radii = originX - 100;
            heading = 90;
            headingBug = 0;
            //repaint();
            imageList = createImageBuffer(oldMapImage);
            range = 4;
            minRange = 0.1f;
            currentLat =18.92f;
            currentLon = 72.780f;
            
            
            new UDPClient(this).start();
            //addMouseListener(this);
            mapImage = "/images/map/NA.png";
           
            frame.setVisible(true);

        }catch (Exception ex) {
            Logger.getLogger(Example.class.getName()).log(Level.SEVERE, null, ex);
        } 
    }
    public static void main(String[] args)
    {
        new Example();
    }
    public void paint(Graphics g)
    {
        try {
            Graphics2D g2d = (Graphics2D) g;
            Composite origComposite = g2d.getComposite();
            NumberFormat formatter = new DecimalFormat("000");
            String str = formatter.format(heading);
            
            g2d.setColor(Color.black);
            g2d.fillRect(0, 0, screenWidth, screenHeight);
            double translateY = (19.2983446067557 - currentLat) % 0.0202768935753;
            double translateX = (currentLon - 72.7742958068848) % 0.0300407409668;
            int translateImageX = (int) (700*translateX/0.0300407409668);
            int translateImageY = (int) (500*translateY/0.0202768935753);
            /* Draw the image, applying the filter */
            AffineTransform transform1 = AffineTransform.getRotateInstance(Math.toRadians(-heading), originX, originY);
            AffineTransform origTransform = g2d.getTransform();
            g2d.setTransform(transform1);

           
           
            
            for(int i=0;i<=4;i++)
            {
                ArrayList<BufferedImage> rowList = imageList.get(i);
                for(int j=0;j<=4;j++)
                {
                        BufferedImage mapImg = rowList.get(j);
                    
                        
                        //System.out.println(temp+"\t"+imageName);
                        //BufferedImage mapImg = ImageIO.read(getClass().getResource(imageName));//loadTranslucentImage(imageName, 0.5f);
                        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
                        g2d.drawImage(mapImg, originX - translateImageX+(i-2)*700, originY - translateImageY+(j-2)*500, null);
                        g2d.setComposite(origComposite);
                    

                }
            }
            
            
            g2d.setTransform(origTransform);
            
        } catch (Exception ex) {
            Logger.getLogger(Example.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
        

   
    public ArrayList<ArrayList<BufferedImage>> createImageBuffer(String currentUrl)
    {
        String[] imageMapArray = currentUrl.split("_");
        ArrayList<ArrayList<BufferedImage>> returnList = new ArrayList<ArrayList<BufferedImage>>();
        BufferedImage mapImg=null;
        for(int i=-2;i<=2;i++)
        {
            ArrayList<BufferedImage> rowList = new ArrayList<BufferedImage>();
            for(int j=-2;j<=2;j++)
            {
                if(imageMapArray.length==3)
                {
                    try {
                        int tempY = Integer.parseInt(imageMapArray[2].substring(0, imageMapArray[2].length() - 4)) + j;
                        int tempX = Integer.parseInt(imageMapArray[1]) + i;
                        String imageName;
                        if (tempY <= 19 && tempY >= 0 && tempX <= 6 && tempX >= 0) {
                            imageName = imageMapArray[0] + "_" + tempX + "_" + tempY + ".png";
                        } else {
                            imageName = "/images/map/NA.png";
                        }
                        //RenderedOp rImage = JAI.create("url", getClass().getResource(imageName));
                        //mapImg = rImage.getAsBufferedImage();
                        mapImg = ImageIO.read(getClass().getResource(imageName));
                    } catch (Exception ex) {
                        Logger.getLogger(Example.class.getName()).log(Level.SEVERE, null, ex);
                    }

                }
                else
                {
                    try {
                        mapImg = ImageIO.read(getClass().getResource("/images/map/NA.png"));
                    } catch (IOException ex) {
                        Logger.getLogger(Example.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
                rowList.add(mapImg);
            }
            returnList.add(rowList);
        }
        return returnList;
    }
    
public class ImageLoader extends Thread
{
    public void run()
    {
        imageList = createImageBuffer(oldMapImage);
        
    }
}
public class UDPClient extends Thread
{
JPanel panel;
ArrayList placeInRange;
ImageLoader il;
float oldLat=0, oldLon=0;

    public UDPClient(JPanel panel)
    {
        this.panel = panel;
        il = new ImageLoader();
        //ilb.start();
        placeInRange = new ArrayList();
    }
    
    public String getImage(double lat, double lon)
    {   
        
        double latDiff = 19.2983446067557-lat;
        double lonDiff = lon - 72.7742958068848;
        int latImageNo = (int) Math.ceil(latDiff/0.0202768935753);
        int lonImageNo = (int) Math.ceil(lonDiff/0.0300407409668);
        String mapImageName = "/images/map/mumbai_" + lonImageNo + "_" + latImageNo + ".png";
                //System.out.println(mapImageName);
            
        return mapImageName;
    }
    public void run()
    {
        DatagramPacket packet;
        DatagramSocket socket = null;
        byte[] buff = new byte[256];
        packet = new DatagramPacket(buff,buff.length);
        try {
             socket = new DatagramSocket(5001);
             socket.setSoTimeout(5000);

        } catch (SocketException ex) {
            ex.printStackTrace();
        }catch (IOException ex) {
            ex.printStackTrace();
        }
        
        while(true)
        {
            try {
                socket.receive(packet);
            } catch (IOException ex) {
               ex.printStackTrace();
            }
                        String received = new String(packet.getData(), 0, packet.getLength());
                        //System.out.println("RECEIVED: " + received);
                        if(received.startsWith("$INS"))
                        {
                            String[] strArray = received.split(";");

                            if(strArray.length==7)
                            {
                                float lat=Float.parseFloat(strArray[4]);
                                float lon = Float.parseFloat(strArray[5]);
                                //heading = Float.parseFloat(strArray[3]);
                                //System.out.println((oldLat-lat)*110+"\t"+(oldLon-lon)*110);
                                
                                currentLat=lat;
                                currentLon = lon;
                                mapImage = getImage(lat,lon);
                                if(mapImage.compareToIgnoreCase(oldMapImage)!=0)
                                {
                                    System.out.println("IN: "+System.currentTimeMillis());
                                    oldMapImage = mapImage;
                                    il.run();
                                    System.out.println("OUT: "+System.currentTimeMillis());
                                }
                                
                                panel.repaint(0);
                                
                            }
                        }


        }
    }
    }
}

Have a look at it help me out to solve out the problem

Add some printlns to the code to see where it is spending its time.
Print out the value of System.currentTimeMillis at each print

What does createImageBuffer do? That code appears to be called on the starting thread.

Its spending the time in reading images from disk. createImageBuffer creates a buffer of 25 images and in this code it taking 4 sec of time in Image.read(). That code is called each time my centerimage change, i.e. after approximately 25 sec.
So after each 25 sec I call createImageBuffer() and then my GUI with other code is stuck for 4 sec approximately till the ImageIO.read is not complete

after each 25 sec I call createImageBuffer() and then my GUI with other code is stuck for 4 sec approximately till the ImageIO.read is not complete

Are you calling the method on the GUI's thread?
Try creating a new thread.

Running a seperate thread doesn't gaurentee that the images would be loaded by the time repaint(); is called.
My speculation is that the JRE is putting on some kind of locking mechanism to the ArrayList until the il (ImageLoader) thread completes its job. thereby paint() of your main GUI would be waiting for the resource to be freed by your thread.

So, a good option would be to run multiple threads (provided your CPU usage levels are nominal during execution )where-in each Thread tries to load , one image out of the 25.

I'm not sure. But I think this is whats happening.

One thread for all would be sufficient. Too many threads will actually take longer unless your PC has that many extra cores.

@Norm: Is it possible that paint is forced to wait for some resources that the other thread is using?
AFAIK that seems to be the case.

Does the code call createImageBuffer when it needs the images and wait until they are loaded to proceed and so freeze the GUI by doing the call on the GUI's thread?
Can the loading of the images be done in the background on another thread while the user is interacting with the GUI so that when the need for the next batch of images comes, they will already have been loaded?

AFAIK, The Main thread is completely different from the other thread that calls createImageBuffer. But the thread is started just a few seconds before the paint() method is called by main Thread. By doing this, the main Thread is having to wait until the createImageBuffer() method is processed before continuing.

Impossible to test without the images.
To debug this, I'd add more printlns to see the how the code flow goes.
When does the 4 second wait occur?
What causes the next load of the images to be done?

Running a seperate thread doesn't gaurentee that the images would be loaded by the time repaint(); is called.
My speculation is that the JRE is putting on some kind of locking mechanism to the ArrayList until the il (ImageLoader) thread completes its job. thereby paint() of your main GUI would be waiting for the resource to be freed by your thread.

So, a good option would be to run multiple threads (provided your CPU usage levels are nominal during execution )where-in each Thread tries to load , one image out of the 25.

I'm not sure. But I think this is whats happening.

Yaa, that is what is currently happening. I will try to use multiple threads.

One thread for all would be sufficient. Too many threads will actually take longer unless your PC has that many extra cores.

My PC has four cores. I will try to use multiple threads and will see what's the esult

Does the code call createImageBuffer when it needs the images and wait until they are loaded to proceed and so freeze the GUI by doing the call on the GUI's thread?

Can the loading of the images be done in the background on another thread while the user is interacting with the GUI so that when the need for the next batch of images comes, they will already have been loaded?

AFAIK, The Main thread is completely different from the other thread that calls createImageBuffer. But the thread is started just a few seconds before the paint() method is called by main Thread. By doing this, the main Thread is having to wait until the createImageBuffer() method is processed before continuing.

@Norm In the code I have called another thread which will call createImageBuffer to create the buffer of images. So I suppose both my GUI and buffer creation should run independently.
But that's not what's happening. As per my requirement the code should not wait for the images to load and freeze my GUI. But that's happening.
I do want the loading to be done in another thread and I did code for it but that's not happening. How should I correct that?

@Sky Diploma So should I call my paint method before currentImageBuffer so that is should not wait for createImageBuffer. Well I did tried that and same result, the main thread waits for the thread to complete createImageBuffer() before processing further

Well my guess is that it might be becuase of ImageIO.read method which might be blocking other processes to continue before its finished. Is any such thing possible?

Impossible to test without the images. To debug this, I'd add more printlns to see the how the code flow goes. When does the 4 second wait occur? What causes the next load of the images to be done?

The four second wait occurs when the image is read from the hard disk and loaded into a buffer. This four seconds wait is called in about every 20 sec. The GUI should work with old images and after new images are loaded in next buffer in the next paint call if will draw new images.
I have attached my two codes here which I use
Example.java

UDPBroadCastServer.java


I am not able to attach the images with zip file. I am attaching a URL where I have uploaded my zip file of images. Images

How does your app work? Which programs do you execute when?

What are the events and the times of the events?
For example:When do you see the delay? Does the user press a button somewhere and the GUI freezes for 4 seconds before something happens?

there are lots of mistakes in this thread, there are problems with Concurency in the Swing, redirecting hardiest and longiest code to the Background Thread (open Connection, basic I/O, unknow paint() instead of paintCompoentn(), close connection ....)

for diplaying images in the Java GUI is better look for JLabel, because very simply implements Icon/ImageIcon


why not use SwingWoker, link to the example on the 1st.line

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.