Sending a screenshot (bufferedImage) through a socket in java

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

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 output stream after this line:

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

Is there anything I can do except close the output stream?

Also, is there anything else not to use ImageIO at all? It seems that the time has come to do something. Also note that reading or writing to the hard drive should in any case be avoided at all costs due to performance issues. I need to make this transfer as quickly as possible (I am experimenting and trying to create a client similar to VNC, and saving each screenshot to the hard drive will greatly slow down everything).

@Jon Skeet

Edit 3:

Sender: (Please 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 input stream of the socket)

Attempt # 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 in getWidth () line) I understand that this error means “damaged image” because it cannot initialize it. correctly?

Attempt number 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)

Attempt number 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:

  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 error: socket write error)

Attempt number 5:

Using the Jon skeet code snippet, the image comes in, but only partially. I saved it in a file (1.jpg) to see what happens, and it actually sends 80% of the image, and the rest of the file is filled with empty space. This results in a partially damaged image. Here is the code I tried: (note that captureImg () is not wrong, saving the file directly works)

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); 

Receiver:

  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 receives the message Connection reset by peer: socket write. Click here for full size image. Problemm

+8
java sockets bufferedimage
source share
3 answers

One option is to write the image to ByteArrayOutputStream so that you can determine the length, and then first write that length to the output stream.

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

I am not completely surprised that it does not work until the output socket is closed normally - after all, a file that contains a valid PNG file and then something else is not really a valid PNG file in itself , It? Therefore, the reader needs to read to the end of the stream before it ends - and the "end" of the network stream appears only when the connection is closed.

EDIT: Here you can read the specified number of bytes into a new byte array. This is convenient for use 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; } 
+8
source share

for other StackOverflow users like me.

The answer is "John Skeet." Change the following line of the readExactly method.

  <<original Line>> index += size; <<modified Line>> index += bytesRead; 

Get full image data.

+1
source share
 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(); } } } 

On 192.168.1.48:8000, the python machine server is running, and I received the stream in Java code

0
source share

All Articles