-2

I am trying to build a client-server Program in which the server sends the image to client and client displays the received image in JFrame. I am converting Image on the server-side to ImageIcon object and sending it to the client via ObjecOutputStream. But it fails and gives me failed to load image contents error on server-side, it happens while the ObjectOutputStream.writeObject() method is called.

Server-side code

import java.io.*;
import java.net.*;
import javax.swing.*;

public class ImageServer{

  private static ServerSocket serverSocket;
  private static final int PORT = 1234;

  public static void main(String[] args){

       System.out.println("Opening port…\n");
       try{
         serverSocket = new ServerSocket(PORT);
       }
       catch(IOException ioEx){
         System.out.println("Unable to attach to port!");
         System.exit(1);
       }
       while(true){
             try{
               Socket connection = serverSocket.accept();

               ObjectOutputStream outStream =new ObjectOutputStream(
                                              connection.getOutputStream());
               ImageIcon icon=new ImageIcon("//Give image path//");
               System.out.println(icon.getImageLoadStatus());// To check if image is loded correctly or not.

               outStream.writeObject(icon);

               outStream.flush();
             }
            catch(IOException ioEx){
                ioEx.printStackTrace();
            }
      }
 }
}

Just give the path for an image file, for testing purposes.

Client-side code

import java.io.*;
import java.net.*;
import java.awt.*; 
import java.awt.event.*;
import javax.swing.*;

public class ImageClient extends JFrame{
    private InetAddress host;
    private final int PORT = 1234;
    private ImageIcon image;

    public static void main(String[] args){

         ImageClient pictureFrame = new ImageClient();
         pictureFrame.setSize(340,315);
         pictureFrame.setVisible(true);
         pictureFrame.setDefaultCloseOperation(EXIT_ON_CLOSE);  
    }

   public ImageClient(){
        try{
           host = InetAddress.getLocalHost();
        }
        catch(UnknownHostException uhEx){

            System.out.println("Host ID not found!");
            System.exit(1);
        }

        try{
            Socket connection = new Socket(host,PORT);

            ObjectInputStream inStream =new ObjectInputStream(
                                           connection.getInputStream());

            image = (ImageIcon)inStream.readObject();

            connection.close();
        }
        catch(IOException ioEx){
              ioEx.printStackTrace();
        }
        catch(ClassNotFoundException cnfEx){
              cnfEx.printStackTrace();
        }

        repaint();
  }

  public void paint(Graphics g){
       image.paintIcon(this,g,0,0);
   }
}

Error generated on Server-side

java.io.IOException: failed to load image contents
     at javax.swing.ImageIcon.writeObject(Unknown Source)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
     at java.lang.reflect.Method.invoke(Unknown Source)
     at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
     at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
     at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
     at java.io.ObjectOutputStream.writeObject0(Unknown Source)
     at java.io.ObjectOutputStream.writeObject(Unknown Source)
     at ImageServer.main(ImageServer.java:27)

This is a code excerpt from the following book: http://www.springer.com/us/book/9781447152538

ck0049
  • 1
  • 3
  • 1
    I assume you didn’t actually use *"//Give image path//"*. If so, that’s probably your issue. – achAmháin Feb 11 '18 at 22:47
  • No, I didn't use that. I gave the actual path of the image file. – ck0049 Feb 11 '18 at 22:49
  • 1
    And you've tested that you've actually successfully read in an image before trying to send it on its way right? -- doesn't look like you have. Myself, I'd get the Image via `ImageIO.read(...)` and would test that it exists and is not null first. Also, it's usually better to get the image as a resource, not as a File. – Hovercraft Full Of Eels Feb 11 '18 at 22:54
  • I did use getImageLoadStatus() method of imageIcon class on Server-side to test if the image was loaded as image icon or not. I did receive a positive integer as output. I'll add this to the existing code. – ck0049 Feb 11 '18 at 23:01
  • 1
    `icon.getImageLoadStatus` would have to return a value of `MediaTracker.COMPLETE`, but since it's an asynchronous method of load an image, it's not guaranteed to return fully completed image. Instead, use `ImageIO.read` which will either fail with a `IOException` or return a fully realised image. Mind you, it would be more appropriate to either return a `URL` through which the client could download the image themselves or use something like base64 encoding. Object serialisation just cause more problems – MadProgrammer Feb 11 '18 at 23:05
  • Actually, I am working on old code for server-client image sharing framework. I have to use ImageIcon to share the object via serialization, as a lot of code depends on ImageIcon objects. This is just a test code where I am experimenting if I am able to send at least 1 image file as ImageIcon object. – ck0049 Feb 11 '18 at 23:11
  • `ImageIcon(ImageIO.read(...))` - `ImageIO.read` returns a `BufferedImage` which extends from `Image` – MadProgrammer Feb 11 '18 at 23:13
  • Which is not serializable, but if you absolutely must serialize, then you can wrap the Image in an ImageIcon via `new ImageIcon(image)`. But I like the URL idea! – Hovercraft Full Of Eels Feb 11 '18 at 23:16
  • 1
    @ck0049 ... Please, don't just don't. I've been using `ImageIcon` this way for over 17 years, I guarantee that it works this way [`ImageIcon(Image)`](https://docs.oracle.com/javase/8/docs/api/javax/swing/ImageIcon.html#ImageIcon-java.awt.Image-) expects a `java.awt.Image`. If you take a look at the [JavaDocs for `BufferedImage`](https://docs.oracle.com/javase/8/docs/api/java/awt/image/BufferedImage.html) you will see that it extends from ... `java.awt.Image` – MadProgrammer Feb 11 '18 at 23:34
  • I get the following error if I use @MadProgrammer method to read the image:**image:javax.imageio.IIOException: Can't read input file! at javax.imageio.ImageIO.read(Unknown Source) at ImageServer.main(ImageServer.java:33)** – ck0049 Feb 11 '18 at 23:34
  • 1
    @ck0049 Then the problem is either, the image doesn't exist where you think it exists OR it's not a valid image format. Since `ImageIO` supports a wider range of image formats that `ImageIcon`, that might begin to suggest to you part of the source of your problems. What type of image are you actually trying to read? – MadProgrammer Feb 11 '18 at 23:36
  • @MadProgrammer I am using PNG image. – ck0049 Feb 11 '18 at 23:37
  • @ck0049 Okay, start by placing `System.out.println(new File(//Give image path//).exists());` in you code before you read the image and see if the file actually exists at the location you are trying to read it from – MadProgrammer Feb 11 '18 at 23:39
  • @MadProgrammer It shows False. But how? I kept the image file in src directory. – ck0049 Feb 11 '18 at 23:41
  • @MadProgrammer should I keep it where class files are generated? – ck0049 Feb 11 '18 at 23:42
  • @ck0049 Okay. When it's stored within the application context, in most cases this means the image (aka resource) will be embedded with the resulting Jar file, this makes it no longer accessible as a file (and `ImageIcon(String)` will expect it to be a file on the file system). Instead, you need to use `ImageIO.read(ImageServer.class.getResource("//Give image path//")` which DOESN'T included the reference to `src`, but which `/` is the root context of `src` (or the top of the package) – MadProgrammer Feb 11 '18 at 23:44
  • @ck0049 So, if the image is stored in `src/images/Image.png`, then it would be something like `ImageIO.read(ImageServer.class.getResource("/images/Image.png")` – MadProgrammer Feb 11 '18 at 23:45
  • You might consider attaching a debugger and including the src.zip file from the JDK; step into the JDK code and see what's happening. – Charlie Feb 11 '18 at 23:45
  • @MadProgrammer I was able to get true as the output for exists() method. But still got the error: javax.imageio.IIOException: Can't read input file! at javax.imageio.ImageIO.read(Unknown Source) at ImageServer.main(ImageServer.java:34) – ck0049 Feb 11 '18 at 23:46
  • NB You are also leaking accepted sockets. You need to close the `ObjectOutputStream` some time. – user207421 Feb 11 '18 at 23:56

1 Answers1

1

Okay, so I created an project using Netbeans. I placed a image (named 29bd6417998561.5635a605ad357.png in the package named images.

Project structure

I created the Server class...

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;

public class Server {

    private static final int PORT = 9999;

    public static void main(String[] args) {

        System.out.println("Opening port…\n");
        try (ServerSocket serverSocket = new ServerSocket(PORT)) {
            while (true) {
                ;
                try {
                    System.out.println("Waiting for connection");
                    Socket connection = serverSocket.accept();

                    System.out.println("Read image...");
                    ImageIcon icon = new ImageIcon(ImageIO.read(Server.class.getResource("/images/29bd6417998561.5635a605ad357.png")));

                    System.out.println("Read image...");
                    try (ObjectOutputStream outStream = new ObjectOutputStream(connection.getOutputStream())) {
                        System.out.println("Write image");
                        outStream.writeObject(icon);
                    }
                } catch (IOException ioEx) {
                    ioEx.printStackTrace();
                }
            }
        } catch (IOException ioEx) {
            System.out.println("Unable to attach to port!");
            System.exit(1);
        }
    }
}

and created the Client class...

import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class Client {

    private InetAddress host;
    private final int PORT = 9999;
    private ImageIcon image;
    private JLabel label;

    public static void main(String[] args) {

        Client pictureFrame = new Client();
    }

    public Client() {
        try {
            host = InetAddress.getLocalHost();
        } catch (UnknownHostException uhEx) {

            System.out.println("Host ID not found!");
            System.exit(1);
        }

        JFrame frame = new JFrame();
        label = new JLabel();
        frame.add(label);

        System.out.println("Connect to server");
        try (Socket connection = new Socket(host, PORT)) {
            try (ObjectInputStream inStream = new ObjectInputStream(connection.getInputStream())) {
                System.out.println("Read image");
                image = (ImageIcon) inStream.readObject();
                label.setIcon(image);
                System.out.println("All done");
            } catch (ClassNotFoundException ex) {
                ex.printStackTrace();
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }

        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

I started the Server and ran the Client and it worked fine...

Downloaded image

Disclaimer...

Undoubtedly, others will point out the inherent issues with this code, but that's not the point of the example.

Firstly, you should never be performing blocking or long running operations from within the Event Dispatching Thread (like connecting to a server and/or reading an image from it). You should also not be modifying the UI from outside the context of the Event Dispatching Thread (kind of safe here as the frame's not realised on the screen, but still not a great example).

In both cases, something like a SwingWorker would help solve those issues.

Take a look at Work Threads and SwingWorker for more details

Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366