【问题标题】:Refresh BufferedImage periodically定期刷新 BufferedImage
【发布时间】:2014-01-19 14:04:47
【问题描述】:

我在JFrame 中显示了BufferedImage,我想用通过Socket(byte[] buffer) 收到的原始R、G、B 数据定期刷新它。动作顺序应如下所示:

  1. 接收字节[1280 * 480] 纯 RGB 数据数组(每个组件一个字节)-> 这部分工作完美
  2. 遍历字节数组并为每个像素调用BufferedImage.setRgb(x, y, RGB)

我在接收和显示一帧时没有问题,但是当我包装执行步骤 1 和 2 的代码时。我定期接收数据但没有显示任何一帧。我的猜测是接收数据比显示图像要快得多,换句话说,我收到的图像会以某种方式被新图像等覆盖。 我的下一个想法是将带有图像的缓冲区移交给另一个后台线程并阻止进行网络通信的主线程,直到后台线程完成“显示”图像。 然后我听说可以在这里使用SwingWorker 轻松完成:Can a progress bar be used in a class outside main? 但它所做的事情就像我仍然在一个线程上做所有事情一样:没有显示任何图像。这是我的代码:

public class ConnectionManager {

public static final String serverIp = "192.168.1.10";
public static final int tcpPort = 7;
public static final int bufferSize = 1280;

private Socket client;
private BufferedInputStream networkReader;
private PrintStream printStream;

byte[] buffer;

public ConnectionManager(){}

public void connect() throws IOException{
    int dataRead;
    while(true){
        client = new Socket(serverIp, tcpPort);

        printStream = new PrintStream(client.getOutputStream());
        networkReader = new BufferedInputStream(client.getInputStream());

        dataRead = 0;
        buffer = new byte[1280 * 480];
        printStream.println(""); // CR is code to server to send data


        while(dataRead < (1280 * 480)){
            dataRead += networkReader.read(buffer, dataRead, (1280 * 480) - dataRead);
        }

        DrawBack d = new DrawBack();
        d.execute();
        try {
            d.get(); // here im trying to block main thread purposely
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } 

    }
}

private class DrawBack extends SwingWorker<Void, Void>{

    @Override
    protected Void doInBackground() throws Exception {
        byte Y, U, V;
        int R, G, B, RGB, Yi, Ui, Vi;
        boolean alternate = false;
        for(int i = 0; i < 480; ++i){
            for(int j = 1; j < 1280; j += 2){
                if(alternate){
                    Y = buffer[i * 1280 + j];
                    V = buffer[i * 1280 + j -1];
                    U = buffer[i * 1280 + j -3];
                } else {
                    Y = buffer[i * 1280 + j];
                    U = buffer[i * 1280 + j -1];
                    V = buffer[i * 1280 + j +1];
                }
                Yi = Y & 0xFF;
                Ui = U & 0xFF;
                Vi = V & 0xFF;

                R = (int)(Yi + 1.402 * (Vi - 128));
                G = (int)(Yi - 0.34414 * (Ui - 128) - 0.71414 * (Vi - 128));
                B = (int)(Yi + 1.772 * (Ui - 128));

                RGB = R;
                RGB = (RGB << 8) + G;
                RGB = (RGB << 8) + B;

                alternate = !alternate;

                Masapp.window.getImage().setRGB(j/2, i, RGB);// reference to buffered image on JFrame

                if((i == 100) && (j == 479)){
                    System.out.println(Yi + " " + Ui + " " + Vi);
                }
            }
        }
        return null;
    }
}
}

我什至尝试用 while 等待完成:

DrawBack d = new DrawBack(); // DrawBack extends SwingWorker<Void, Void>
d.execute();
while(!d.isDone());

但它没有任何改善。当我设置所有像素时,我尝试调用 BufferedImage.flush()JFrame.invalidate()

我的问题基本上是:如何定期刷新和显示缓冲图像?

【问题讨论】:

标签: java swing rgb bufferedimage swingworker


【解决方案1】:

您的实现不正确同步,因为它从工作人员的后台线程而不是 event dispatch thread 更新 GUI。由此产生的行为是不可预测的。相反,定义一个SwingWorker&lt;BufferedImage, BufferedImage&gt;publish() 图像,以便稍后在您的process() 实现中渲染。为了提高活跃度,请在准备就绪时发布部分图像,例如publish() BufferedImage 一次包含一行。将引用的 example 与相关的 example 进行比较以了解方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-13
    • 1970-01-01
    • 1970-01-01
    • 2012-07-02
    • 2020-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多