2015-03-31 130 views
1

我试图用Java创建一个程序,它会截取用户的屏幕截图,压缩图像并通过套接字将其发送到服务器。 由于某种原因,图像最终保存损坏(无法读取)。你能帮我找出问题所在吗?通过套接字发送压缩的JPG图像

CLIENT:(截图输入为一个BufferedImage,然后返回的字节数组被返回到它发送到服务器的第二功能)

public static byte[] compressImage(BufferedImage image) throws IOException { 
    System.out.println("starting compression"); 

    ByteArrayOutputStream os = new ByteArrayOutputStream(37628); 

    float quality = 0.16f; 

    // create a BufferedImage as the result of decoding the supplied InputStream 

    // get all image writers for JPG format 
    Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg"); 
    //Iterator iter = ImageIO.getImageWritersByFormatName("jpeg"); 

    if (!writers.hasNext()) 
     throw new IllegalStateException("No writers found"); 

    ImageWriter writer = (ImageWriter) writers.next(); 
    ImageOutputStream ios = ImageIO.createImageOutputStream(os); 
    writer.setOutput(ios); 

    ImageWriteParam param = writer.getDefaultWriteParam(); 

    // compress to a given quality 
    param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); 
    param.setCompressionQuality(quality); 

    // appends a complete image stream containing a single image and 
    //associated stream and image metadata and thumbnails to the output 
    writer.write(null, new IIOImage(image, null, null), param); 
    os.flush(); 

    return os.toByteArray(); 
} 

    public void uploadShot(byte[] imgData, String nickname) { 

    try { 
     /* Try to connect to the server on localhost, port 5555 */ 

     Socket sk = new Socket("localhost", 23232); 
     OutputStream output = sk.getOutputStream(); 

     /* Send filename to server */ 

     OutputStreamWriter outputStream = new OutputStreamWriter(sk.getOutputStream()); 
     outputStream.write(nickname + "\n"); 
     outputStream.flush(); 

     /* Get response from server */ 

     BufferedReader inReader = new BufferedReader(new InputStreamReader(sk.getInputStream())); 

     String serverStatus = inReader.readLine(); // Read the first line 

     /* If server is ready, send the file */ 

     if (serverStatus.equals("READY")){ 
      int len = imgData.length; 
      int start = 0; 

      if (len < 0) 
       throw new IllegalArgumentException("Negative length not allowed"); 
      if (start < 0 || start >= imgData.length) 
       throw new IndexOutOfBoundsException("Out of bounds: " + start); 
      // Other checks if needed. 

      // May be better to save the streams in the support class; 
      // just like the socket variable. 
      OutputStream out = sk.getOutputStream(); 
      DataOutputStream dos = new DataOutputStream(out); 

      dos.writeInt(len); 
      if (len > 0) { 
       dos.write(imgData, start, len); 
      } 
      dos.close(); 
      output.close(); 
      sk.close(); 

      System.out.println("Transfer complete."); 
     } 
    } catch (Exception ex){ 
     /* Catch any errors */ 
     System.out.println(ex.getMessage()); 
    } 
} 

SERVER:(所接收到的图像被保存到)

public static void main(String args[]) throws Exception{ 
    System.out.println("Server running..."); 

    /* Listen on port 5555 */ 

    ServerSocket server = new ServerSocket(23232); 

    /* Accept the sk */ 

    Socket sk = server.accept(); 

    System.out.println("Server accepted client"); 
    InputStream input = sk.getInputStream(); 
    BufferedReader inReader = new BufferedReader(new InputStreamReader(sk.getInputStream())); 
    BufferedWriter outReader = new BufferedWriter(new OutputStreamWriter(sk.getOutputStream())); 

    /* Read the filename */ 
    String nickname = inReader.readLine(); 

    if (!nickname.equals("")){ 

     /* Reply back to client with READY status */ 

     outReader.write("READY\n"); 
     outReader.flush(); 
    } 


    String current = "/home/kasgel/screenshots"; 

    DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy__HH:mm:ss"); 
    Date timestamp = new Date(); 
    File filename = new File(current + "/" + nickname + "-" + dateFormat.format(timestamp) + ".jpg"); 
    if (!filename.exists()) { 
     filename.createNewFile(); 
    } 
    FileOutputStream wr = new FileOutputStream(filename); 

    byte[] buffer = new byte[sk.getReceiveBufferSize()]; 

    int bytesReceived = 0; 

    while((bytesReceived = input.read(buffer))>0) { 
     wr.write(buffer,0,bytesReceived); 
    } 
    wr.close(); 
} 

与时间戳提到的文件夹和错误消息打开保存的屏幕截图时,我得到如下: display.im6:不是一个JPEG文件:使用0x00 0x03时`MyNick-30-03启动-2015__19:27:58.jpg'@ error/jpeg .C/JPEGErrorHandler/316。

+1

发送一些已知数据并进行比较。 – sstn 2015-03-31 13:26:50

+2

你附加一个'BufferedReader'并同时使用底层的'InputStream',所以我会说前者“吃掉”了你的一些数据,所以从后者读取的内容将缺少图片的头部。 – dnet 2015-03-31 13:33:38

回答

1

当你写你的形象,你先写含在图像的字节长度的32位有符号整数:

 dos.writeInt(len); 
     if (len > 0) { 
      dos.write(imgData, start, len); 
     } 

但是,当你正在阅读的图像回来,你不”先读长度;您正在读取所有数据(包括长度),就好像它们是图像的一部分一样。

虽然你有第二个问题,那本身也会导致这个问题。当您创建BufferedReader并调用readLine时,它将读取超出换行符 - 它将读取,直到其缓冲区已满。如果你继续读取它,这不是一个问题,但是在读完这行后,你继续从底层的InputStream中读取数据,这会在换行之后消耗更多的字节。

解决方法是:只使用一个抽象来读/写数据。在这种情况下,最简单的方法是使用DataOutputStreamDataInputStream。使用writeUTF写入文件名并使用readUTF读回。用writeInt写下文件的长度,然后用readInt读回。用write写入数据并用read读取数据 - 并确保只读取您从readInt调用收到的字节数。最重要的是,继续使用相同的DataOutputStreamDataInputStream实例;请勿在相同底层构造缓冲读取器和输入流InputStream