14

I am trying to set up two programs in C#. Basically, a simple client server set up where I want the server to listen for an image from the client. Then, upon receiving the image, will display it in a PictureBox.

I keep running into the following error:

A first chance exception of type 'System.ArgumentException' occurred in System.Drawing.dll

The error is happening on the server code that is listening at this line: Image bmp = Image.FromStream(ms); Any ideas?

The Server code that listens:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Net.Sockets;

namespace NetView
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            startListening();
        }

        private void startListening()
        {
            ////////////////////////////////////////////

            Console.WriteLine("Server is starting...");
            byte[] data = new byte[1024];
            IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);

            Socket newsock = new Socket(AddressFamily.InterNetwork,
                            SocketType.Stream, ProtocolType.Tcp);

            newsock.Bind(ipep);
            newsock.Listen(10);
            Console.WriteLine("Waiting for a client...");

            Socket client = newsock.Accept();
            IPEndPoint newclient = (IPEndPoint)client.RemoteEndPoint;
            Console.WriteLine("Connected with {0} at port {1}",
                            newclient.Address, newclient.Port);

            while (true)
            {
                data = ReceiveVarData(client);
                MemoryStream ms = new MemoryStream(data);
                try
                {
                    Image bmp = Image.FromStream(ms);
                    pictureBox1.Image = bmp;
                }
                catch (ArgumentException e)
                {
                    Console.WriteLine("something broke");
                }


                if (data.Length == 0)
                    newsock.Listen(10);
            }
            //Console.WriteLine("Disconnected from {0}", newclient.Address);
            client.Close();
            newsock.Close();
            /////////////////////////////////////////////

        }

        private static byte[] ReceiveVarData(Socket s)
        {
            int total = 0;
            int recv;
            byte[] datasize = new byte[4];

            recv = s.Receive(datasize, 0, 4, 0);
            int size = BitConverter.ToInt32(datasize, 0);
            int dataleft = size;
            byte[] data = new byte[size];


            while (total < size)
            {
                recv = s.Receive(data, total, dataleft, 0);
                if (recv == 0)
                {
                    break;
                }
                total += recv;
                dataleft -= recv;
            }
            return data;
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

    }
}

The Client Code:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Drawing;
using System.IO;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            byte[] data = new byte[1024];
            int sent;
            IPEndPoint ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050);

            Socket server = new Socket(AddressFamily.InterNetwork,
                            SocketType.Stream, ProtocolType.Tcp);

            try
            {
                server.Connect(ipep);
            }
            catch (SocketException e)
            {
                Console.WriteLine("Unable to connect to server.");
                Console.WriteLine(e.ToString());
                Console.ReadLine();
            }


            Bitmap bmp = new Bitmap("c:\\eek256.jpg");

            MemoryStream ms = new MemoryStream();
            // Save to memory using the Jpeg format
            bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);

            // read to end
            byte[] bmpBytes = ms.GetBuffer();
            bmp.Dispose();
            ms.Close();

            sent = SendVarData(server, bmpBytes);

            Console.WriteLine("Disconnecting from server...");
            server.Shutdown(SocketShutdown.Both);
            server.Close();
            Console.ReadLine();
        }

        private static int SendVarData(Socket s, byte[] data)
        {
            int total = 0;
            int size = data.Length;
            int dataleft = size;
            int sent;

            byte[] datasize = new byte[4];
            datasize = BitConverter.GetBytes(size);
            sent = s.Send(datasize);

            while (total < size)
            {
                sent = s.Send(data, total, dataleft, SocketFlags.None);
                total += sent;
                dataleft -= sent;
            }
            return total;
        }
    }
}
  • What side are you getting the exception? – Daniel A. White Apr 15 '09 at 01:30
  • Doesn't the debugger show you where the argument exception is thrown? – Patrik Svensson Apr 15 '09 at 01:31
  • Server side, try { Image bmp = Image.FromStream(ms); pictureBox1.Image = bmp; } catch (ArgumentException e) { Console.WriteLine("something broke"); } –  Apr 15 '09 at 01:33
  • Try outputting Console.Writeline(e.ToString()) (or ideally attach the debugger) to get a more specific error. – Patrik Svensson Apr 15 '09 at 01:36
  • 1
    If you save the Image bmp object to file can you open it? That would be a quick test to make sure nothing is going wrong with your data transmission code. – sipsorcery Apr 15 '09 at 01:37
  • System.ArgumentException: Parameter is not valid. at System.Drawing.Image.FromStream(Stream stream, Boolean useEmbeddedColorManagement, Boolean validateImageData) at System.Drawing.Image.FromStream(Stream stream) at NetView.Form1.startListening() –  Apr 15 '09 at 01:39

6 Answers6

9

ArgumentException tells you that the image format in the stream is invalid. Which is probably caused by the client application closing the memory stream before the data were sent.

Try replacing byte[] bmpBytes = ms.GetBuffer(); with

byte[] bmpBytes = ms.ToArray();

Or close the stream after the data were sent.

Remember that the byte-array returned by the .GetBuffer() returns the underlying array, not a copy of it (.ToArray() returns a copy), that is valid as long as the parent stream.

arul
  • 13,998
  • 1
  • 57
  • 77
6

If you have access to the JPG file itself (as in the example), you should send the file bytes and not use the Image/Bitmap classes. By reading a JPG file and re-encoding into JPG you are decreasing the image quality and incurring unnecessary overhead. You can use File.ReadAllBytes() to quickly get the complete byte[] or read/send it in pieces if your memory space is limited.

Lucas
  • 17,277
  • 5
  • 45
  • 40
6

A better way to send the image would be to use BinaryFormatter.

eg, some snippets from my own code to send an image every second...

sending:

        TcpClient client = new TcpClient();  
        try  
        {    
            client.Connect(address, port); 

            // Retrieve the network stream.  
            NetworkStream stream = client.GetStream();  
            MessageData data = new MessageData(imageToSend); 

            IFormatter formatter = new BinaryFormatter();

            while(true)
            {
                formatter.Serialize(stream, data);
                Thread.Sleep(1000);
                data.GetNewImage();
            }    
        } 

receiving:

        TcpListener listener = new TcpListener(address, port);
        listener.Start();

        try
        { 
            using (TcpClient client = listener.AcceptTcpClient())
            {
                stream = client.GetStream();

                IFormatter formatter = new BinaryFormatter();
                while (true)
                {
                    MessageData data = (MessageData)formatter.Deserialize(stream);

                    if (ImageReceivedEvent != null) ImageReceivedEvent(data.Picture);
                }
            }
        }

and the MessageData class simply holds the image and has the [Serializable] attribute.

geometrikal
  • 3,195
  • 2
  • 29
  • 40
  • What is `data.GetNewImage()`? By the name, I would suspect that it returns an image, but from what I see, it does not do anything with the return. I don't see you sending data either -- not sure though: does `formatter.Serialize` do the sending? – pookie Jul 28 '16 at 08:01
  • @pookie It has been years since this code so I'm not sure. I think `GetNewImage()` retrieves another image from a camera and stores it within the `MessageData` object. I'm pretty sure `formatter.Serialize` writes the object to the Stream, so yes, it does the sending. – geometrikal Jul 28 '16 at 13:20
  • Oh, sorry! I didn't see that this is from '09! Yes, a long time ago. Thanks for getting back to me, anyway. – pookie Jul 28 '16 at 13:22
  • @pookie No worries, hope it helps anyway. – geometrikal Jul 28 '16 at 13:25
4

Use Arul's code to get the data to send correctly -- you want .ToArray(), not .GetBuffer(). Then, you'll want to run the server's 'startListening' method on a background thread or you won't actually see anything (as the form thread will be busy running the server code. Try:

var t = new Thread(startListening);
t.IsBackground = true;
t.start();

In your Form_Load method instead of directly calling startListening in your constructor.

Jonathan Rupp
  • 15,522
  • 5
  • 45
  • 61
1

Here is a code that works for me. User starts server with a button and client selects photo by opening the file dialog of computer. At last sends the image but be careful about the photo size because UDP cannot transmit much large data.

Server:

    delegate void showMessageInThread(string message);
    UdpClient listener = null;
    IPEndPoint endpoint = null;
    Thread listenThread = null;

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {

    }

    private void button1_Click(object sender, EventArgs e)
    {
        startServer();
    }
    private void startServer()
    {
        endpoint = new IPEndPoint(IPAddress.Any, 1234);
        listener = new UdpClient(endpoint);
        ShowMsg("Waiting for a client!");

        listenThread = new Thread(new ThreadStart(Listening));
        listenThread.Start();
    }
    private void Listening()
    {
        while (true)
        {
            //take the coming data
            byte[] comingDataFromClient = listener.Receive(ref endpoint);
            ImageConverter convertData = new ImageConverter();
            Image image =  (Image)convertData.ConvertFrom(comingDataFromClient);
            pictureBox1.Image = image;
        }
   private void ShowMsg(string msg)
   {
      this.richTextBox1.Text += msg + "\r\n";
   }

Client:

   Socket server = null;
    MemoryStream ms;
    IPEndPoint endpoint = null;
    public Form1()
    {
        InitializeComponent();
    }
    private void Form1_Load(object sender, EventArgs e)
    {
        server = new Socket(AddressFamily.InterNetwork,
            SocketType.Dgram, ProtocolType.Udp);
        endpoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1234);
    }
    private void btn_browse_Click(object sender, EventArgs e)
    {
        openFileDialog1.ShowDialog();
        string path = openFileDialog1.FileName;
        pictureBox1.Image = Image.FromFile(path);
        textPath.Text = path;
    }
    private void btn_send_Click(object sender, EventArgs e)
    {
        try
        {                
            ms = new MemoryStream();
            Bitmap bmp = new Bitmap(this.openFileDialog1.FileName);
            bmp.Save(ms, ImageFormat.Jpeg);
            byte[] byteArray = ms.ToArray();

            server.Connect(endpoint);
            server.SendTo(byteArray, endpoint);

            }
        }
        catch (Exception ex)
        {

        }
0
data = ReceiveVarData(client);
MemoryStream ms = new MemoryStream(data);
Image bmp = Image.FromStream(ms);
pictureBox1.Image = bmp;

The error may due to corrupted or incomplete bmp image received in the MemoryStream it worked fine for me after increasing the socket send/receive buffers values
adjust the sender "Socket.SendBufferSize" and the receiver "Socket.ReceiveBufferSize" to large values for example = 1024 * 2048 *10 this will help sending the entire image at once. or another solution is to check whether the received data size (data.length) is the same as the sent image data size, before the code line of forming the received image stream