在java中的套接字上发送屏幕截图(bufferedImage) [英] Sending a screenshot (bufferedImage) over a socket in java

查看:249
本文介绍了在java中的套接字上发送屏幕截图(bufferedImage)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在通过套接字发送bufferedImage,我正在使用这个中的示例发布:

I am sending a bufferedImage over a socket and I am using the example found in this post:

发件人

   BufferedImage image = ....;
   ImageIO.write(image, "PNG", socket.getOutputStream());

接收方

   BufferedImage image = ImageIO.read(socket.getInputStream());

它可以工作 - 如果,只有在这一行之后关闭发送者的outputStream:

It works - IF, and ONLY IF, I close the sender's outputStream after this line:

 ImageIO.write(image, "PNG", socket.getOutputStream());

除了关闭outputStream之外我还能做些什么吗?

Is there anything I can do apart from closing the outputStream?

另外,我还能做些什么来避免使用ImageIO吗?似乎需要很长时间才能做任何事情。
另请注意,由于性能问题,应该不惜一切代价避免读取或写入硬盘。我需要尽可能快地进行此转移,(我正在尝试并尝试创建类似于VNC的客户端并将每个屏幕截图保存到硬盘上会大大减慢所有内容)..

Also, is there anything else I can do to avoid using ImageIO altogether? It seems to take ages to do anything. Also note that reading or writing to the hard disk in anyway should be avoided at all costs due to performance issues. I need to make this transfer as fast as possible, (I'm experimenting and trying to create a client similar to VNC and saving each screenshot to the hard disk would greatly slow down everything)..

@Jon Skeet

@Jon Skeet

编辑3:

发件人:(请注意,我发送的JPG图片不是PNG)。

Sender: (Note that I am sending a JPG image not a PNG).

                    int filesize;
                    OutputStream out = c.getClientSocket().getOutputStream();

                    ByteArrayOutputStream bScrn = new ByteArrayOutputStream();
                    ImageIO.write(screenshot, "JPG", bScrn);
                    byte[] imgByte = bScrn.toByteArray();
                    bScrn.flush();
                    bScrn.close();

                    filesize = bScrn.size();
                    out.write(new String("#FS " + filesize).getBytes()); //Send filesize
                    out.write(new String("#<IM> \n").getBytes());        //Notify start of image

                    out.write(imgByte); //Write file
                    System.out.println("Finished");                                 

收件人:(其中输入是套接字输入流)

Reciever: (where input is the socket input stream)

尝试#1:

String str = input.toString();
imageBytes = str.getBytes();

InputStream in = new ByteArrayInputStream(imageBytes);
BufferedImage image = ImageIO.read(in);
in.close();

System.out.println("width=" + image.getWidth());

(失败:getWidth()行的Nullpointer异常)
我理解这个错误意味着损坏的图像,因为它无法初始化它。正确?

(failed: Nullpointer exception on getWidth() line) I understand this error to mean "corrupt image" because it couldn't initialize it. correct?

尝试#2:

byte[] imageBytes = new byte[filesize];
for (int j = 0; i < filesize; i++)
{
    imageBytes[j] = (byte) input.read();
}

InputStream in = new ByteArrayInputStream(imageBytes);
BufferedImage image = ImageIO.read(in);
in.close();

System.out.println("width=" + image.getWidth());

(失败:getWidth()行上的Nullpointer异常)

尝试#3:

if (filesize > 0)
{

    int writtenBytes = 0;
    int bufferSize = client.getReceiveBufferSize();

    imageBytes = new byte[filesize];     //Create a byte array as large as the image
    byte[] buffer = new byte[bufferSize];//Create buffer


    do {
        writtenBytes += input.read(buffer); //Fill up buffer
        System.out.println(writtenBytes + "/" + filesize); //Show progress

        //Copy buffer to the byte array which will contain the full image
        System.arraycopy(buffer, 0, imageBytes, writtenBytes, client.getReceiveBufferSize());
        writtenBytes+=bufferSize;

    } while ((writtenBytes + bufferSize) < filesize);

    // Read the remaining bytes
    System.arraycopy(buffer, 0, imageBytes, writtenBytes-1, filesize-writtenBytes);
    writtenBytes += filesize-writtenBytes;
    System.out.println("Finished reading! Total read: " + writtenBytes + "/" + filesize);

}

InputStream in = new ByteArrayInputStream(imageBytes);
BufferedImage image = ImageIO.read(in);
in.close();

(失败:接收者给出:空指针异常)

尝试4:

   int readBytes = 0;
   imageBytes = new byte[filesize];     //Create a byte array as large as the image



    while (readBytes < filesize)
    {
        readBytes += input.read(imageBytes);
    }

    InputStream in = new ByteArrayInputStream(imageBytes);
    BufferedImage image = ImageIO.read(in);
    in.close();

    System.out.println("width=" + image.getWidth());

(失败:发送者给出:java.net.SocketException:连接由peer重置:socket写错误)

尝试#5:

使用Jon diaet的代码片段,图片到达,但只是部分。我将它保存到文件(1.jpg)中以查看发生了什么,它实际上发送了80%的图像,而文件的其余部分则填充了空白区域。这导致部分损坏的图像。这是我试过的代码:(请注意,captureImg()没有错,直接保存文件有效)

Using Jon skeet's code snippet, the image arrives, but only partially. I saved it to a file (1.jpg) to see what was going on, and it actually sends 80% of the image, while the rest of the file is filled with blank spaces. This results in a partially corrupt image. Here is the code I tried: (note that captureImg() is not at fault, saving the file directly works)

发件人:

    Socket s = new Socket("127.0.0.1", 1290);
    OutputStream out = s.getOutputStream();

    ByteArrayOutputStream bScrn = new ByteArrayOutputStream();
    ImageIO.write(captureImg(), "JPG", bScrn);
    byte imgBytes[] = bScrn.toByteArray();
    bScrn.close();

    out.write((Integer.toString(imgBytes.length)).getBytes());
    out.write(imgBytes,0,imgBytes.length);

收件人:

    InputStream in = clientSocket.getInputStream();
    long startTime = System.currentTimeMillis();

    byte[] b = new byte[30];
    int len = in.read(b);

    int filesize = Integer.parseInt(new String(b).substring(0, len));

    if (filesize > 0)
    {
        byte[] imgBytes = readExactly(in, filesize);
        FileOutputStream f = new FileOutputStream("C:\\Users\\Dan\\Desktop\\Pic\\1.jpg");
        f.write(imgBytes);
        f.close();

        System.out.println("done");

发送方仍然通过peer:socket写错误给出Connection重置。
点击此处查看完整尺寸的图片

The sender still gives a Connection reset by peer: socket write error. Click here for full sized image

推荐答案

一种选择是写将图像转换为 ByteArrayOutputStream ,这样您就可以确定长度,然后将该长度首先写入输出流。

One option would be to write the image to a ByteArrayOutputStream so you can determine the length, then write that length to the output stream first.

然后在接收端,你可以读取长度,然后将那么多字节读入一个字节数组,然后创建一个 ByteArrayInputStream 来包装数组并传递那个 ImageIO.read()

Then on the receiving end, you can read the length, then read that many bytes into a byte array, then create a ByteArrayInputStream to wrap the array and pass that to ImageIO.read().

我不觉得它不起作用直到输出套接字正常关闭 - 毕竟,包含有效PNG文件然后其他东西的文件本身实际上不是有效的PNG文件,是吗?因此,读者需要在流完成之前读取到流的末尾 - 并且只有在连接关闭时才会出现网络流的结束。

I'm not entirely surprised that it doesn't work until the output socket is closed normally - after all, a file which contains a valid PNG file and then something else isn't actually a valid PNG file in itself, is it? So the reader needs to read to the end of the stream before it can complete - and the "end" of a network stream only comes when the connection is closed.

编辑:这是一种将给定字节数读入新字节数组的方法。作为单独的实用程序方法很方便。

Here's a method to read the given number of bytes into a new byte array. It's handy to have as a separate "utility" method.

public static byte[] readExactly(InputStream input, int size) throws IOException
{
    byte[] data = new byte[size];
    int index = 0;
    while (index < size)
    {
        int bytesRead = input.read(data, index, size - index);
        if (bytesRead < 0)
        {
            throw new IOException("Insufficient data in stream");
        }
        index += size;
    }
    return data;
}

这篇关于在java中的套接字上发送屏幕截图(bufferedImage)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆