Hi, i'm making a server client piant program that send what is painted on the server to the client(and vice versa). this program is supposed to use instruction based transmission of the image.

i have a server client program that sends what is drawn on the server to the client but it uses image based tranmission of the image and i'm not sure how to change this from image based to instruction based. (I made the image based sending first because this is part of my homework and the image based program is worth more points. needless to say i still need to do the instruction based version.)

right now what my program does is after the the image is drawn it uses the image of what is currently drawn and sends it to the client. but what i want it to do is instead of sending the actual image just send the cordinates of the lines that have been drawn and when the client gets it the client will redraw the lines to create the same image. something like that.

this is the code for the server. (The server and client are pretty much identical in what they do except one is the server and one is the client so i'm only putting the code for the server to save space.)

Please help! Any advice will really be appreciated. Thanks.

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

import javax.imageio.ImageIO;
import javax.swing.*;

class Lab9_1_Server extends JFrame
{   
    public static void main(String[] args)
    {
        new Lab9_1_Server();

    }

    BufferedImage receivedImage = null;
    BufferedImage bi;
    ServerSocket serverSocket;
    Socket socket;
    private JPanel controls = new JPanel();
    private JPanel rpControls = new JPanel();
    private PadDrawV1 drawPad = new PadDrawV1();
    private JPanel leftPanel = new JPanel(new BorderLayout());
    private JPanel rightPanel = new JPanel(new BorderLayout());
    private JButton send = new JButton("SEND");

    public Lab9_1_Server(){
        setTitle("Paint it");
        setSize(1000, 600);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setResizable(false);
        setVisible(true);

        //controls.setPreferredSize(new Dimension(32, 68));
        drawPad.setPreferredSize(new Dimension(460, 532));
        Container content = this.getContentPane();
        content.setLayout(new BorderLayout());

        leftPanel.add(drawPad, BorderLayout.NORTH);
        leftPanel.add(controls, BorderLayout.SOUTH);

        rightPanel.setPreferredSize(new Dimension(460, 532));
        rightPanel.setBackground(Color.WHITE);
        rightPanel.add(rpControls, BorderLayout.SOUTH);

        content.add(leftPanel, BorderLayout.WEST);
        content.add(send, BorderLayout.CENTER);
        content.add(rightPanel, BorderLayout.EAST);

        makeColorButton(Color.BLUE);
        makeColorButton(Color.MAGENTA);
        makeColorButton(Color.RED);
        makeColorButton(Color.GREEN);
        makeColorButton(Color.BLACK);

        JButton clearButton = new JButton("Clear");
        clearButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                drawPad.clear();
            }
        });
        controls.add(clearButton);

        JButton saveButton = new JButton("Save");
        saveButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                drawPad.saveImage((BufferedImage)drawPad.image, "ServerPic.png");
            }
        });
        controls.add(saveButton);  

        JButton rpSaveButton = new JButton("Save");
        rpSaveButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                drawPad.saveImage(receivedImage, "RecievedFromClient.png");
            }
        });
        rpControls.add(rpSaveButton);

        send.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {

                try {
                    bi = (BufferedImage)drawPad.image;
                    ImageIO.write(bi, "PNG", socket.getOutputStream());


                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });   

        try{
             serverSocket = new ServerSocket(8000);
             socket = serverSocket.accept();

             receivedImage = ImageIO.read(socket.getInputStream());
             rightPanel.add(new JLabel(new ImageIcon(receivedImage)), BorderLayout.NORTH);
             rightPanel.revalidate();
        }
        catch(IOException ex){
            System.err.println(ex);
        }   
    }

    public void makeColorButton(final Color color)
    {
        JButton tempButton = new JButton();
        tempButton.setBackground(color);
        tempButton.setPreferredSize(new Dimension(16, 16));
        controls.add(tempButton);
        tempButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                drawPad.changeColor(color);
            }
        });
    }  
}

class PadDrawV1 extends JPanel
{
    Image image;
    Graphics2D graphics2D;
    int currentX, currentY, oldX, oldY;

    public PadDrawV1()
    {
        setDoubleBuffered(false);
        addMouseListener(new MouseAdapter()
        {
            public void mousePressed(MouseEvent e)
            {
                oldX = e.getX();
                oldY = e.getY();
            }
        });

        addMouseMotionListener(new MouseMotionAdapter()
        {
            public void mouseDragged(MouseEvent e)
            {
                currentX = e.getX();
                currentY = e.getY();

                graphics2D.drawLine(oldX, oldY, currentX, currentY);
                repaint();

                oldX = currentX;
                oldY = currentY;
            }
        });
    }

    public void paintComponent(Graphics g)
    {
        if(image == null)
        {
            image = createImage(getSize().width, getSize().height);
            graphics2D = (Graphics2D)image.getGraphics();
            graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

            clear();
        }

        g.drawImage(image, 0, 0, null);
    }

    public void clear()
    {
        graphics2D.setPaint(Color.white);
        graphics2D.fillRect(0, 0, getSize().width, getSize().height);
        graphics2D.setPaint(Color.black);
        repaint();
    }

    public void changeColor(Color theColor)
    {
        graphics2D.setPaint(theColor);
        repaint();
    }

    public void saveImage(BufferedImage img, String filename) {
        try {
            String format = (filename.endsWith(".png")) ? "png" : "jpg";
            ImageIO.write(img, format, new File(filename));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

} 

Edited 3 Years Ago by IcyFire

When you call graphics2D.drawLine(oldX, oldY, currentX, currentY) you will also want to add that to a list that records each line that is drawn, something like history.add(new Line(oldX, oldY, currentX, currentY, graphics2D.getColor()). Then when you want to send the image, you can just send the history list using a DataOutputStream.

Aside from that, it looks like you only check for the client sending images once. That seems pretty broken. I don't know exactly how that server is supposed to work, but I would expect it to be ready to accept an image at any time.

Also, you probably shouldn't be running that constructor in the main thread. It does stuff that according to the rules you are only supposed to do in the event dispatch thread.

thanks for your help. i have a question though. how do i create the list that records the lines that were drawn. i know you gave the example with history but i'm not sure what history is. is it come sort of component or some kind of variable? this may be a silly question but i'm just not sure how to implement it.

also thanks for pointing out that that i only check for images once. that shouldn't be like that.

Re implementing bguild's excellent suggestion:
Simply create a little class Line, with vars for oldX, oldY etc. Give it a constructor that takes all the values it needs. Declare it as "implements Serializable" so it can be sent over an object stream. "history" can then be an ArrayList of LineData, which can be sent over a socket as a single object.

This question has already been answered. Start a new discussion instead.