3

我正在编写一个程序,其中包括一个图像文件夹(通常大约 2000 个 jpeg 图像)调整它们的大小,并将它们添加到图像时间轴中。结果如下:

在此处输入图像描述

这很好用,但是我这样做的方式似乎非常低效。处理这些图像的代码如下所示:

public void setTimeline(Vector<String> imagePaths){
    
    int numberOfImages = imagePaths.size();     
    
    JLabel [] TotalImages = new JLabel[numberOfImages];
    setGridPanel.setLayout(new GridLayout(1, numberOfImages, 10, 0));
    
    Dimension image = new Dimension(96, 72);

    if (imagePaths != null){
        for(int i = 0; i <numberOfImages; i++){
            TotalImages[i] = new JLabel("");
            TotalImages[i].setPreferredSize(image);
            
            ImageIcon tempicon = new ImageIcon(imagePaths.elementAt(i));
            Image tempimage = tempicon.getImage();
            
            Image newimg = tempimage.getScaledInstance(96, 72,  java.awt.Image.SCALE_SMOOTH);
            ImageIcon newIcon = new ImageIcon(newimg);
            TotalImages[i].setIcon(newIcon);

            setGridPanel.add(TotalImages[i]);
        }
    }
}

可以看出,此代码循环遍历每个图像路径,将其添加到标签并将其添加到面板 - 使用正确的输出完全按照应有的方式执行。

然而,这样做所花费的时间是巨大的。2000 张图像通常需要 5 分钟左右(取决于机器)。我想知道是否有任何方法可以通过使用不同的技术来提高这种性能?

任何帮助是极大的赞赏。

4

6 回答 6

4

保存您的扩展实例并直接加载它们。硬盘空间便宜。这不会绕过生成拇指的初始成本,但任何后续出现都将是闪电般的速度。

于 2012-05-29T21:44:36.340 回答
3

为了增加 mKorbel 的出色答案,我肯定会使用后台线程,例如 SwingWorker。这可能不会使程序更快,但它看起来会快很多,这可以使一切变得不同。就像是:

// use List<String> not Vector<String> so you can use Vector now, or change your 
// mind and use ArrayList later if desired
// pass dimensions and components in as parameters to be cleaner
public void setTimeLine2(List<String> imagePaths, Dimension imgSize,
     JComponent imgDisplayer) {

  if (imagePaths != null && imgSize != null && imgDisplayer != null) {

     // are you sure you want to set the layout in here?
     imgDisplayer.setLayout(new GridLayout(1, 0, 10, 0));

     // create your SwingWorker, passing in parameters that it will need
     ImageWorker imgWorker = new ImageWorker(imagePaths, imgSize,
           imgDisplayer);
     imgWorker.execute(); // then ask it to run doInBackground on a background thread
  } else {
     // TODO: throw exception
  }
}

private class ImageWorker extends SwingWorker<Void, ImageIcon> {
  private List<String> imagePaths;
  private JComponent imgDisplayer;
  private int imgWidth;
  private int imgHeight;

  public ImageWorker(List<String> imagePaths, Dimension imgSize,
        JComponent imgDisplayer) {
     this.imagePaths = imagePaths;
     this.imgDisplayer = imgDisplayer;
     imgWidth = imgSize.width;
     imgHeight = imgSize.height;
  }

  // do image creation in a background thread so as not to lock the Swing event thread
  @Override
  protected Void doInBackground() throws Exception {
     for (String imagePath : imagePaths) {
        BufferedImage bImg = ImageIO.read(new File(imagePath));
        Image scaledImg = bImg.getScaledInstance(imgWidth, imgHeight,
              Image.SCALE_SMOOTH);
        ImageIcon icon = new ImageIcon(scaledImg);
        publish(icon);
     }
     return null;
  }

  // but do all Swing manipulation on the event thread
  @Override
  protected void process(List<ImageIcon> chunks) {
     for (ImageIcon icon : chunks) {
        JLabel label = new JLabel(icon);
        imgDisplayer.add(label);
     }
  }
}
于 2012-05-29T22:13:43.303 回答
3

获取图像文件夹

通过使用过程tempimage.getScaledInstance(96, 72, java.awt.Image.SCALE_SMOOTH);

  • 使用,你也JTable可以使用减少的功能JList

2000 张图像通常需要 5 分钟左右

Image.getScaledInstance是简单的异步,没有保证快速和性能,那么你必须将图像的加载重定向到后台任务

  • 优势图像的第一部分立即可用

  • dis_advantage 需要为用户显示加载状态,非常了解SwingEvent Dispatch Thread

我建议查看Runnable#Thread, 并将输出放入DefaultTableModel, 请注意此输出必须包装到invokeLater

另一种最复杂的方法是使用,但也需要非常SwingWorker好的知识JavaSwing

于 2012-05-29T21:47:25.620 回答
2

使用瓷砖。这意味着不是对屏幕上未显示的图像进行操作,而是仅在必须在屏幕上显示图像时进行操作。

您需要保持时间线的逻辑位置以及显示的图像。当用户将光标移动到先前隐藏的位置时,您计算接下来需要显示哪些图像。如果图像尚未处理,则处理它们。这与网络浏览器用于性能的技术相同。

于 2012-05-29T21:39:09.580 回答
1
  • 您可以做的第一件事是异步添加图像,而不是尝试一次添加所有图像。像你一样循环它们,将它们添加到面板并每隔几张图像渲染一次,这样用户就不需要等待很长的初始化时间。

  • 重用图像对象。会想到享元模式,并且可能将屏幕重绘限制为仅在异步加载中添加新图像的部分。

  • 如果您将来可能会重新绘制相同的图像(或重新加载相同的文件夹),您可能需要考虑缓存一些图像对象,并可能将调整大小的缩略图保存到文件中(许多照片查看器会这样做并且将缩略图版本 - 和一些有用的元数据 - 存储在隐藏文件或文件夹中,以便他们下次可以更快地重新加载它们。

于 2012-05-29T21:39:59.067 回答
-1

您可以通过创建 4 个线程来使其更快,并让它们同时计算图像。我不知道虚拟机是否会将它们分布在多个 cpu 内核上。需要研究的东西,因为这会提高多核 pc 上的性能

于 2012-05-29T21:44:44.073 回答