我正在编写一个程序,其中包括一个图像文件夹(通常大约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分钟(取决于机器)。我想知道是否有任何方法可以通过使用不同的技术来改善这种性能?
非常感谢任何帮助。
答案 0 :(得分:4)
保存缩放的实例并直接加载它们。硬盘空间很便宜。这不会产生生成拇指的初始成本,但任何后续出现都会闪电般快。
答案 1 :(得分:3)
获取图像文件夹
使用tempimage.getScaledInstance(96, 72, java.awt.Image.SCALE_SMOOTH);
JTable
,功能减少,您也可以使用JList
2000张照片通常约为5分钟
Image.getScaledInstance
是简单的异步,确保快速和性能,然后你必须将图像加载到后台任务
优势第一部分图片可立即使用
dis_advantage需要为用户提供不正确的加载状态,非常了解Swing
和Event Dispatch Thread
我建议您查看Runnable#Thread
,并将输出结果输出到DefaultTableModel
,请注意此输出必须包含在invokeLater
另一种最复杂的方式是使用SwingWorker
,但需要非常了解Java
和Swing
答案 2 :(得分: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);
}
}
}
答案 3 :(得分:2)
使用瓷砖。这意味着,除了操作未在屏幕上显示的图像外,您只能在必须在屏幕上显示图像时进行操作。
您需要保持时间轴的逻辑位置以及显示的图像。 当用户将光标移动到先前隐藏的位置时,您可以计算下一个需要显示的图像。如果图像尚未处理,则处理它们。这与网络浏览器用于提高性能的技术相同。
答案 4 :(得分:1)
您可以做的第一件事是异步添加图像,而不是尝试一次添加所有图像。像你一样循环它们,将它们添加到面板并每隔几张图像渲染一次,这样用户就不需要等待很长的初始化时间。
重用图像对象。我们会想到一个flyweight模式,并且可能会将屏幕重绘限制为仅在异步加载中添加新图像的部分。
如果您将来可能会重绘相同的图像(或重新加载相同的文件夹),您可能需要考虑缓存某些图像对象,并可能保存为调整大小的缩略图(许多照片浏览者会这样做,并会将隐藏文件或文件夹中的缩略图版本和一些有用的元数据存储起来,这样他们就可以在下次更快地重新加载它们。
答案 5 :(得分:-1)
你可以做的更快,就是制作4个线程,让它们同时计算图像。我不知道vm是否会将它们分散在多个cpu核心上。需要研究的内容,因为这会增强多核PC上的穿孔效果