1

我有一些繁重的系统资源图像处理(需要将图像缩放得很深)并将缩放图像的某些部分(我们称之为视口)绘制到画布上。

因为图像大小调整到如此大的尺寸会导致 UI 阻塞几秒钟,所以我制作了背景线程来调整图像大小并在图像准备好时使用它。在此之前,使用paintevent gcSWT 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);被注释掉,它会正常工作。

有人可以告诉我为什么会导致阻塞以及如何避免它吗?是的,我需要在高级模式下同时拥有两个线程(mainworker),因为我需要在main画线中使用抗锯齿,并gc.setInterpolation(SWT.HIGH);worker调整大小后获得合理的图像质量。

4

0 回答 0