5 Replies Latest reply on Mar 22, 2016 12:54 PM by Max8090-JavaNet

    Outofmemory exception loading images

    Max8090-JavaNet

      Dear community,

       

      i have a problem loading image files.

      There are 2 cases, i've tested. The problem occures only in the first one. In both cases a JDialog-window apears that displays a

      downscaled image. After 300ms this window closes automatically (there is a timer in the constructor of ImageDialog and CardPrinter; this is only for debugging).

      In the production version, the programm must be able to load 30-40 images (one by one) in a JDialog. The user types some text, and clicks on a button to show the next image.

      To load the images i use ImageIO.read() in both cases. Alternatively i used CMYKJPEGImage (http://www.randelshofer.ch/blog/2011/08/reading-cmyk-jpeg-images-with-java-imageio/)

      but it also produces the exception.

      In Main there is  myTimer  that continusly opens the JDialog with an image-file (listFilesRecurse() should be called with an absolute path by setting the variable  pathtofiles).

       

       

      Case 1) loading images in JDialog with overlay layout manager (Main.java,  CardPrinter.java,  IDCardLayout.java).

      For this, the lines from  'CardPrinter cp=null;'  to  'cp.dispose();'  in Main.java must be uncommented. The tricky part is in addIDCard()@CardPrinter.

      Here will be the layout built up. After this  paintComponent()@IDCardLayout will be called, if the content of the dialog-window should be actualised.

      It seems, that the loaded images won't be destroyed, and the memory gets full (in Window's Taskmanager the memory usage can be seen).

       

       

      Case 2) loading images in a JDialog with no layout manager (Main.java,  ImageDialog.java).

      (Uncomment the line  'mn.showDialog(mn.frame, file);').

      Works perfect. No exceptions!

       

       

      The function ImageIO.read() should be ok, because in the 2. case, there was no errors (even if the code runs for 20 minutes).

      It's strange, it seems in the first case the layoutmanager prevents GC to unload the unused images...

      The Java version is: 1.7.0_80  on  Windows7 SP1.

      Can somebody help me please?

       

       

      Thank you in advance,

      Daniel

       

       

       

      The exception:

      Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space

          at java.awt.image.DataBufferByte.<init>(DataBufferByte.java:92)

          at java.awt.image.ComponentSampleModel.createDataBuffer(ComponentSampleModel.java:415)

          at java.awt.image.Raster.createWritableRaster(Raster.java:941)

          at javax.imageio.ImageTypeSpecifier.createBufferedImage(ImageTypeSpecifier.java:1073)

          at javax.imageio.ImageReader.getDestination(ImageReader.java:2896)

          at com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:1066)

          at com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:1034)

          at javax.imageio.ImageIO.read(ImageIO.java:1448)

          at javax.imageio.ImageIO.read(ImageIO.java:1308)

          at test.IDCardLayout.loadPicture(IDCardLayout.java:128)

          at test.CardPrinter.addIDCard(CardPrinter.java:142)

          at test.CardPrinter.<init>(CardPrinter.java:62)

          at test.CardPrinter.createDialog(CardPrinter.java:91)

          at test.Main$1.actionPerformed(Main.java:69)

          at javax.swing.Timer.fireActionPerformed(Timer.java:312)

          at javax.swing.Timer$DoPostEvent.run(Timer.java:244)

          at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:312)

          at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:745)

          at java.awt.EventQueue.access$300(EventQueue.java:103)

          at java.awt.EventQueue$3.run(EventQueue.java:706)

          at java.awt.EventQueue$3.run(EventQueue.java:704)

          at java.security.AccessController.doPrivileged(Native Method)

          at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)

          at java.awt.EventQueue.dispatchEvent(EventQueue.java:715)

          at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)

          at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)

          at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)

          at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)

          at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)

          at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

       

         

      -------

          package test;

          /*Main.java*/

         

         

          import java.awt.FlowLayout;

          import java.awt.event.ActionEvent;

          import java.awt.event.ActionListener;

          import java.io.File;

          import java.io.IOException;

          import java.util.Vector;

         

          import javax.swing.JButton;

          import javax.swing.JFrame;

          import javax.swing.JLabel;

          import javax.swing.JPanel;

          import javax.swing.Timer;

         

         

          public class Main {

              JFrame frame;

             

             

              //list files recursively, using a filter (pattern). If pattern=*, all files will be listed.

              public static void listFilesRecurse(String fullpath, String pattern[], Vector<File> foundFiles) throws IOException {

                  File dir = new File(fullpath);

                  File list[] = dir.listFiles();

                  for(File f: list) {

                      if( !f.isDirectory() ) {

                          for(String pt: pattern) {

                              if(pt.equals("*")) {

                                  foundFiles.add(f);

                                  break;

                              }

                              else if( f.getAbsolutePath().toUpperCase().endsWith(pt.toUpperCase()) ) {

                                  foundFiles.add(f);

                                  break;

                              }

                          }

                      } else {

                          listFilesRecurse(f.getAbsolutePath(), pattern, foundFiles);

                      }

                  }

              }

             

         

          public static void main(String[] args) {

              final Main mn = new Main();

              final String pathtofiles = "\\path\\to\\files\\";

             

              ActionListener task = new ActionListener() {

                  public void actionPerformed(ActionEvent evt) {

                      Vector<File> list = new Vector<File>();

                      System.out.println("\nListing files ...");

                      try {

                          listFilesRecurse(pathtofiles, new String[]{"jpg", "png", "jpeg"}, list);

                      } catch (IOException e) {

                          e.printStackTrace();

                      }

                      for(int index=0; index<list.size(); index++) {

                          String file = list.get(index).getAbsolutePath();

                          System.out.println("\nLoading image - " + index + ": " + file);

                         

                          //mn.showDialog(mn.frame, file);

                         

                         

                          CardPrinter cp=null;

                          try {

                              cp = CardPrinter.createDialog(mn.frame, "Max",

                                                            "Muster", "1122", "12345678", "01/2018", file);

                          } catch (Exception e) {

                              e.printStackTrace();

                              continue; //break;  //return;

                          }

                          cp.setVisible(true);

                          cp.dispose();

                      }

                  }

              };

              final Timer myTimer = new Timer(100,  task);

              myTimer.setRepeats(true);

             

             

              JFrame frame = new JFrame("JFrame Example");

              mn.frame = frame;

         

              JPanel panel = new JPanel();

              panel.setLayout(new FlowLayout());

         

              JLabel label = new JLabel("This is a label!");

              JButton button = new JButton();

         

              button.setText("Press me");

              button.addActionListener( new ActionListener() {

                  public void actionPerformed(ActionEvent actionEvent) {

                      myTimer.start();

                  }

              });

         

              panel.add(label);

              panel.add(button);

              frame.add(panel);

              frame.setSize(300, 300);

              frame.setLocationRelativeTo(null);

              frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

              frame.setVisible(true);

          }

         

         

          //opens the dialog that display an image (file).

          public void showDialog(JFrame fr, String file) {

              ImageDialog imgd = new ImageDialog(fr, "Testdialog", file);

              imgd.setSize(300, 300);

              imgd.setModal(true);

              imgd.setLocation(250, 250);

              imgd.setVisible(true);

          }

         

          }

       

         

         

      ------

          package test;

          /*ImageDialog.java*/

         

          import java.awt.Color;

          import java.awt.Graphics;

          import java.awt.Graphics2D;

          import java.awt.RenderingHints;

          import java.awt.event.ActionEvent;

          import java.awt.event.ActionListener;

          import java.awt.image.BufferedImage;

          import java.io.File;

          import java.io.IOException;

         

          import javax.imageio.ImageIO;

          import javax.swing.JDialog;

          import javax.swing.JFrame;

          import javax.swing.Timer;

         

          import org.monte.cmykdemo.CMYKJPEGImage;

         

         

          public class ImageDialog extends JDialog {

              String file;

             

             

              public ImageDialog(JFrame frame, String title, String file) {

                  super(frame, title);

                  this.file = file;

                 

                  //######For debugging only. This will close the dialog window after 300 ms (by calling ImageDialog.this.setVisible(false);).

                  ActionListener task = new ActionListener() {

                      public void actionPerformed(ActionEvent evt) {

                          ImageDialog.this.dispose();

                      }

                  };

                  Timer cl = new Timer(300, task);

                  cl.start();

                  //#######

              }

             

             

              //renders the picture on screen.

              @Override

              public void paint(Graphics g) {

                  Graphics2D g2d = (Graphics2D) g;

                  setRenderingHints(g2d);

                 

                  BufferedImage img=null;

                  try {

                      img = loadPicture(this.file);

                  } catch (IOException e) {

                      e.printStackTrace();

                  }

         

                  g2d.setColor(Color.BLUE);

                  g2d.drawRect(0, 0, this.getWidth(), this.getHeight());

                  g2d.drawImage(img, 10, 10,  80,  80,  null, null);

              }

             

             

              void setRenderingHints(Graphics2D g2) {

                  g2.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));

                  g2.addRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));

                  g2.addRenderingHints(new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON));

              }

             

              public static BufferedImage loadPicture(String fullpath) throws IOException {

                  System.out.println("\nloadPicture(): " + fullpath);

                  //BufferedImage img = (BufferedImage) CMYKJPEGImage.loadImage( fullpath );

                  BufferedImage img = (BufferedImage) ImageIO.read( new File(fullpath) );

                  return img;

              }

          }

       

         

         

      ------

          package test;

          /*CardPrinter.java*/

         

          import java.awt.Color;

          import java.awt.Dimension;

          import java.awt.Window;

          import java.awt.event.ActionEvent;

          import java.awt.event.ActionListener;

          import java.awt.print.PageFormat;

          import javax.swing.JDialog;

          import javax.swing.JFrame;

          import javax.swing.JLabel;

          import javax.swing.OverlayLayout;

          import javax.swing.Timer;

          import javax.swing.border.Border;

          import javax.swing.border.LineBorder;

          import java.awt.image.BufferedImage;

          import java.io.IOException;

          import javax.swing.JPanel;

          import javax.swing.JTextField;

          import javax.swing.BorderFactory;

          import javax.swing.JButton;

         

         

          public class CardPrinter extends JDialog /*implements Printable*/ {

            protected JPanel jp;

            protected JTextField tx;

            protected JLabel lblCounter;

            protected IDCardLayout idcard;

            protected String vorname, nachname, id, gueltig, bild;

           

            protected String chipid;

           

           

            protected CardPrinter(Window owner, String vorname, String nachname, String id, String chipid,

                                    String gueltig, String bild /*, DataReceiver drv*/) throws IOException {

                super((Window)owner, "Assign_ChipID_DialogObject");

                this.bild = bild;

                //this.datareceiver = drv;

                setTitle("Assign ID");

                setModalityType(JDialog.DEFAULT_MODALITY_TYPE);

                setResizable(false);

               

                jp = new JPanel();

                jp.setLayout(null);

                jp.setOpaque(false);

               

                addIDCard();

                //setupButtons();

               

                //setSize(this.getPreferredSize().width, this.getPreferredSize().height);

                setSize(250, 250); //+++

                setLocation(300, 300); //+++

               

                //Overlay components: tx overlaps idcard

                JPanel cnt = new JPanel();

                cnt.setLayout(new OverlayLayout(cnt));

                cnt.add(jp);

                getContentPane().add(cnt);

               

                setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);

               

               

                //######For debugging only. This will close the dialog window after 300 ms (by calling CardPrinter.this.setVisible(false);).

                ActionListener task = new ActionListener() {

                    public void actionPerformed(ActionEvent evt) {

                        CardPrinter.this.setVisible(false);

                    }

                };

                Timer closeWnd = new Timer(300, task);

                closeWnd.start();

                //######

            }

           

         

            //use this to create an instance of this class.

            public static CardPrinter createDialog(Window owner, String vorname,

                            String nachname, String id, String chipid, String gueltig, String bild  /*, DataReceiver drv*/) throws IOException {

                return new CardPrinter(owner, vorname, nachname, id, chipid, gueltig, bild  /*, drv*/);

            }

             

           

            protected void addIDCard() throws IOException {

                int idcard_move_vert=15, idcard_move_hor=76;

                tx = new JTextField(this.chipid, 8);

                jp.add(tx);

                tx.setBounds(idcard_move_hor+130, idcard_move_vert+6, 70, 20);

                Border border = BorderFactory.createLineBorder(Color.RED);

                tx.setBorder(border);

                tx.requestFocus();

               

                lblCounter = new JLabel("");

                lblCounter.setBounds(idcard_move_hor+270, idcard_move_vert-6, 40, 30);

                jp.add(lblCounter);

                lblCounter.requestFocus();

               

                System.out.println("\naddIDCard() ...");

               

                BufferedImage picture = IDCardLayout.loadPicture(this.bild);

                idcard = new IDCardLayout(/*this.vorname, this.nachname, this.id,*/ picture, this.bild  /*, this.gueltig*/);

               

                idcard.setLayout(null);

                //idcard.setBounds(idcard_move_hor, idcard_move_vert, idcard.getPreferredSize().width, idcard.getPreferredSize().height);

                idcard.setBounds(idcard_move_hor, idcard_move_vert, 50, 60);

                idcard.setBorder( new LineBorder(Color.BLACK) );

                jp.add(idcard);

               

                //repaint();

            }

          }

       

         

      ------

          package test;

          /*IDCardLayout.java*/

         

          import java.awt.Dimension;

          import java.awt.Font;

          import java.awt.Graphics;

          import java.awt.Graphics2D;

          import java.awt.RenderingHints;

          import java.awt.font.FontRenderContext;

          import java.awt.image.BufferedImage;

          import java.io.File;

          import java.io.FilenameFilter;

          import java.io.IOException;

         

          import javax.imageio.ImageIO;

          import javax.swing.JPanel;

         

          import org.monte.cmykdemo.CMYKJPEGImage;

         

         

          public class IDCardLayout extends JPanel {

              private BufferedImage bild;

              private String bildfile;

             

             

              public IDCardLayout(BufferedImage photo, String bildfile) {

                  this.bild = photo;

                  this.bildfile = bildfile;

              }

             

             

              /**

               * Render graphics to the screen.

               */

              protected void paintComponent(Graphics g) {

                  Graphics2D g2d = (Graphics2D) g;

                  System.out.println("\npaintComponent() ...");

                  prepareGraphics(g2d);

              }

             

             

              public static BufferedImage loadPicture(String fullpath) throws IOException {

                  //BufferedImage img = (BufferedImage) CMYKJPEGImage.loadImage( f.getAbsolutePath() );

                  BufferedImage img = (BufferedImage) ImageIO.read( new File(fullpath) );

                 

                  return img;

              }

                 

         

              //changing the rendering hints has no effect on Outofmemory-exception.

              protected void setRenderingHints(Graphics2D g2, boolean normalText) {

                  if(true) {

                      g2.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));

                      g2.addRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));

                      g2.addRenderingHints(new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON));

                  }

              }

             

         

              /**

               * Renders graphics to the screen.

               */

              protected void prepareGraphics(Graphics2D g2) {

                  setRenderingHints(g2, true);

         

                  double newHeight = 60;

                  double scwidth = ( ((double)newHeight / (double)this.bild.getHeight()) ) * (double)this.bild.getWidth();

                  System.out.println("\nprepareGraphics() ..." + this.bildfile);

                  g2.drawImage(this.bild,  5,  5,

                              (int)scwidth,

                              (int)newHeight,

                              null, null);

              }

          }