繁体   English   中英

Java内存不足异常加载图像文件

[英]Outofmemory exception loading image files in Java

我在加载图像文件时遇到问题。 我已经测试了2种情况。 该问题仅在第一个中发生。 在这两种情况下,JDialog窗口都会显示缩小的图像。 300毫秒后,此窗口自动关闭(ImageDialog和CardPrinter的构造函数中有一个计时器;仅用于调试)。 在生产版本中,程序必须能够在JDialog中加载30-40个图像(一张一张)。 用户键入一些文本,然后单击按钮以显示下一张图像。 为了加载图像,我在两种情况下都使用ImageIO.read()。 或者,我使用了CMYKJPEGImage( http://www.randelshofer.ch/blog/2011/08/reading-cmyk-jpeg-images-with-java-imageio/ ),但它也会产生异常。 在Main中,有一个myTimer,它用一个图像文件连续打开JDialog(应该通过设置变量pathtofiles用绝对路径调用listFilesRecurse())。

情况1)使用叠加布局管理器(Main.java,CardPrinter.java,IDCardLayout.java)在JDialog中加载图像。 为此,来自“ CardPrinter cp = null;”的行 到“ cp.dispose();” Main.java中的注释必须不加注释。 棘手的部分在addIDCard()@ CardPrinter中。 这将是建立的布局。 如果应该实现对话框窗口的内容,则会调用此paintComponent()@ IDCardLayout。 看起来,加载的图像不会被破坏,并且内存已满(可以在Window的Taskmanager中看到内存使用情况)。

情况2)在没有布局管理器(Main.java,ImageDialog.java)的JDialog中加载图像。 (取消注释'mn.showDialog(mn.frame,file);'行)。 完美的作品。 没有例外!

ImageIO.read()函数应该可以,因为在这种情况下2.没有错误(即使代码运行了20分钟)。 奇怪,在第一种情况下,layoutmanager阻止GC卸载未使用的图像...
1.case中的问题应该在CTR @ CardPrinter和addIDCard()@ CardPrinter中。 在点击率中,我使用OverlayLayout。 在2.case中,根本没有Layoutmanager。
Java版本是:Windows7 SP1上的1.7.0_80。
有人可以帮我吗?

提前谢谢你,丹尼尔

例外:

线程“ AWT-EventQueue-0”中的异常java.lang.OutOfMemoryError:java.awt.image.ComponentSampleModel.createDataBuffer(ComponentSampleModel.java:java.awt.image.DataBufferByte。(DataBufferByte.java:92)上的Java堆空间: 415)在java.awt.image.Raster.createWritableRaster(Raster.java:941)在javax.imageio.ImageTypeSpecifier.createBufferedImage(ImageTypeSpecifier.java:1073)在javax.imageio.ImageReader.getDestination(ImageReader.java:2896)在com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:1034)处的com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:1066)(javax.imageio.ImageIO.read(在测试中javax.imageio.ImageIO.read(ImageIO.java:1308)的ImageIO.java:1448)在测试中IDCardLayout.loadPicture(IDCardLayout.java:128)的Test.CardPrinter.addIDCard(CardPrinter.java:142) CardPrinter。(CardPrinter.java:62)在测试中.CardPrinter.createDialog(CardPrinter.java:91)在测试中.Main $ 1.actionPerformed(Main.java:69)在javax.swing.Timer.fireActionPerformed( 在javax.swing.Timer $ DoPostEvent.run(Timer.java:244)在java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:312)在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),位于java.security.ProtectionDomain $ 1.doIntersectionPrivilege(ProtectionDomain.java:76),位于java.security.AccessController.doPrivileged(Native Method),位于java.awt,位于java.awt.EventQueue.dispatchEvent(EventQueue.java:715) .EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)at java.awt.EventDispatch java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)的EventDispatchThread.java:146)java.awt.EventDispatchThread.run(Event DispatchThread.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);
    }
}

问题已经解决了。 我不再使用类OverlayLayout。 布局看起来完全不同,但现在可以使用了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM