我有一些繁重的系统资源图像处理(需要将图像放大得很深)并将缩放图像的一部分(让我们称之为视口)绘制到画布上。
因为调整到如此巨大尺寸的图像会导致阻塞UI几秒钟,所以我制作了背景线程来调整图像大小,当图像准备就绪时,它会被使用。在此之前,使用了paintevent gc
和SWT transformations
(它们很快,但比已经调整大小的图像的视口操作慢了大约10倍)。
但在我写完大小调整线程后,它仍会阻止UI。所以我让SSCCE证明了这一点。不幸的是,它完美无缺。经过几个小时的调试后,我发现gc.setAdvanced(true);
导致GC
上下文阻塞。
import java.net.URL;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class ImageResizeTest {
private Image bgImage;
private Image imgToResize;
private ImageResizeWorker worker;
private Display display = new Display();
private Shell shell = new Shell(display);
public ImageResizeTest() {
shell.setText("Image background resize test");
Rectangle rect = new Rectangle(0, 0, 500, 500);
bgImage = new Image(display, rect);
paintImage(bgImage);
shell.addPaintListener(new PaintListener() {
@Override
public void paintControl(PaintEvent e) {
System.out.println("redraw start");
e.gc.drawImage(bgImage, 0, 0);
e.gc.setAdvanced(true);
e.gc.fillRectangle(new Rectangle((int)(Math.random() * 100), (int)(Math.random() * 100), 20, 20));
System.out.println("redraw stop");
}
});
shell.addKeyListener(new KeyAdapter() {
/* (non-Javadoc)
* @see org.eclipse.swt.events.KeyAdapter#keyPressed(org.eclipse.swt.events.KeyEvent)
*/
@Override
public void keyPressed(KeyEvent e) {
worker = new ImageResizeWorker(new Image(display, imgToResize, SWT.IMAGE_COPY));
worker.start();
display.asyncExec(new Runnable() {
@Override
public void run() {
shell.redraw();
try {
Thread.sleep(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (worker.isAlive()) display.asyncExec(this);
}
});
}
});
try {
URL url = new URL("http://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Image_created_with_a_mobile_phone.png/1280px-Image_created_with_a_mobile_phone.png");
imgToResize = new Image(display, url.openStream());
paintImage(imgToResize);
} catch (Exception e) {
e.printStackTrace();
}
shell.setActive();
shell.setBounds(rect);
shell.setVisible(true);
while(!shell.isDisposed()) {
if(!display.readAndDispatch()) display.sleep();
}
shell.dispose();
}
private void paintImage(Image img) {
Rectangle rect = img.getBounds();
GC gc = new GC(img);
for (int i = 0; i < 20; i++) {
gc.drawLine((int)(Math.random() * rect.width), (int)(Math.random() * rect.height), (int)(Math.random() * rect.width), (int)(Math.random() * rect.height));
}
gc.dispose();
}
private class ImageResizeWorker extends Thread {
private Image srcImage;
public ImageResizeWorker(Image srcImage) {
this.srcImage = srcImage;
}
/* (non-Javadoc)
* @see java.lang.Thread#run()
*/
@Override
public void run() {
System.out.println("resizing started");
Image targetImage = new Image(new Display(), 31000, 15000);
long time = System.currentTimeMillis();
GC gc = new GC(targetImage);
gc.setAdvanced(true);
gc.setInterpolation(SWT.HIGH);
gc.drawImage(srcImage, 0, 0, srcImage.getBounds().width, srcImage.getBounds().height, 0, 0, 31000, 15000);
System.out.println("Took " + (System.currentTimeMillis() - time) + " ms");
gc.dispose();
bgImage = targetImage;
}
}
public static void main(String[] args) {
new ImageResizeTest();
}
}
如果两个gc.setAdvanced(true);
都被注释掉,它就会正常工作。
有人可以告诉我导致阻止的原因以及如何避免阻塞吗?是的,我需要在高级模式下同时拥有两个线程(main
和worker
) ,因为我需要在main
中使用抗锯齿进行线条绘制,并在gc.setInterpolation(SWT.HIGH);
中使用worker
以在调整大小后使用合理的图像质量。