我有一些繁重的系统资源图像处理(需要将图像缩放得很深)并将缩放图像的某些部分(我们称之为视口)绘制到画布上。
因为图像大小调整到如此大的尺寸会导致 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
调整大小后获得合理的图像质量。