java 在java中通过套接字发送屏幕截图(bufferedImage)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6973848/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Sending a screenshot (bufferedImage) over a socket in java
提问by David
I am sending a bufferedImage over a socket and I am using the example found in thispost:
我正在通过套接字发送一个 bufferedImage 并且我正在使用这篇文章中的示例:
Sender
发件人
BufferedImage image = ....;
ImageIO.write(image, "PNG", socket.getOutputStream());
Receiver
接收者
BufferedImage image = ImageIO.read(socket.getInputStream());
It works - IF, and ONLY IF, I close the sender's outputStream after this line:
它有效 - 如果,并且仅当,我在此行之后关闭发件人的 outputStream:
ImageIO.write(image, "PNG", socket.getOutputStream());
Is there anything I can do apart from closing the outputStream?
除了关闭 outputStream 之外,我还能做些什么吗?
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)..
另外,我还能做些什么来完全避免使用 ImageIO?做任何事情似乎都需要很长时间。另请注意,由于性能问题,应不惜一切代价避免以任何方式读取或写入硬盘。我需要尽可能快地进行这种传输,(我正在试验并尝试创建一个类似于 VNC 的客户端,并将每个屏幕截图保存到硬盘会大大减慢一切)。
@Jon Skeet
@乔恩斯基特
Edit 3:
编辑3:
Sender:(Note that I am sending a JPG image not a PNG).
发件人:(请注意,我发送的是 JPG 图像而不是 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)
接收者:(input
套接字输入流在哪里)
Attempt #1:
尝试#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());
(failed: Nullpointer exception on getWidth() line)I understand this error to mean "corrupt image" because it couldn't initialize it. correct?
(失败:getWidth() 行上的 Nullpointer 异常)我理解这个错误意味着“损坏的图像”,因为它无法初始化它。正确的?
Attempt #2:
尝试#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());
(failed: Nullpointer exception on getWidth() line)
(失败:getWidth() 行上的空指针异常)
Attempt #3:
尝试#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();
(failed: Reciever gives: Null pointer exception)
(失败:接收者给出:空指针异常)
Attempt 4:
尝试 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());
(failed: sender gives: java.net.SocketException: Connection reset by peer: socket write error)
(失败:发件人给出:java.net.SocketException:对等方重置连接:套接字写入错误)
Attempt #5:
尝试#5:
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)
使用 Jon skeet 的代码片段,图像到达,但只是部分到达。我将它保存到一个文件 (1.jpg) 中以查看发生了什么,它实际上发送了 80% 的图像,而文件的其余部分用空格填充。这会导致部分损坏的图像。这是我试过的代码:(注意 captureImg() 没有错,直接保存文件有效)
Sender:
发件人:
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);
Reciever:
接收器:
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");
The sender still gives a Connection reset by peer: socket write error.
Click here for full sized image
发送方仍然通过对等方重置连接:套接字写入错误。
单击此处查看全尺寸图像
采纳答案by Jon Skeet
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.
一种选择是将图像写入 aByteArrayOutputStream
以便您可以确定长度,然后首先将该长度写入输出流。
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 thatto ImageIO.read()
.
然后在接收端,可以读取的长度,则读取多个字节到字节数组,然后创建一个ByteArrayInputStream
包阵列,并通过该对ImageIO.read()
。
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 elseisn'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.
我并不完全惊讶它在输出套接字正常关闭之前不起作用 - 毕竟,一个文件包含一个有效的 PNG 文件,然后其他文件本身实际上并不是一个有效的 PNG 文件,是吗?因此,阅读器需要在完成之前读取到流的末尾 - 并且网络流的“结束”仅在连接关闭时才会出现。
EDIT: 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;
}
回答by SHS
for other StackOverflow users like me.
对于像我这样的其他 StackOverflow 用户。
In "Jon Skeet's" answer. Modify the following line of readExactly method.
在“乔恩斯基特”的回答中。修改 readExactly 方法的以下行。
<<original Line>>
index += size;
<<modified Line>>
index += bytesRead;
To get the full image data.
获取完整的图像数据。
回答by Raj
public static void main(String[] args) {
Socket socket = null;
try {
DataInputStream dis;
socket = new Socket("192.168.1.48",8000);
while (true) {
dis = new DataInputStream(socket.getInputStream());
int len = dis.readInt();
byte[] buffer = new byte[len];
dis.readFully(buffer, 0, len);
BufferedImage im = ImageIO.read(new ByteArrayInputStream(buffer));
jlb.setIcon(new ImageIcon(im));
jfr.add(jlb);
jfr.pack();
jfr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jfr.setVisible(true);
System.gc();
}
} catch (Exception e) {
e.printStackTrace();
}
finally {
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
In 192.168.1.48:8000 machine python server running and i got stream in java code
在 192.168.1.48:8000 机器 python 服务器运行中,我得到了 java 代码中的流