私はいくつかの重いシステムリソースの画像操作(画像を非常に深くズームする必要があります)を持っており、ズームされた画像の一部(ビューポートと呼びましょう)をキャンバスに描画します。
このような巨大なサイズに画像のサイズを変更すると UI が数秒間ブロックされるため、画像のサイズを変更し、画像の準備ができたらそれを使用するバックグラウンド スレッドを作成しました。それまでは、paintevent gc
SWTtransformations
が使用されます (高速ですが、既にサイズ変更された画像のビューポート操作よりも約 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
、サイズ変更後に妥当な画質を得る必要があるからです。