Неверный параметр в Image.FromStream(MemoryStream)

я пытаюсь отправить изображение через сетевой поток, у меня есть функции sendData и Getdata, и я всегда получаю недопустимый параметр при использовании функции Image.FromStream

это мой код: я получаю изображение с экрана, затем преобразовываю его в байт [] и вставляю его в поток памяти, который я отправляю через сетевой поток.

    private void SendData()
    {
        StreamWriter swWriter = new StreamWriter(this._nsClient);
        // BinaryFormatter bfFormater = new BinaryFormatter();

        // this method
        lock (this._secLocker)
        {
            while (this._bShareScreen)
            {
                // Check if you need to send the screen
                if (this._bShareScreen)
                {
                    MemoryStream msStream = new MemoryStream();
                    this._imgScreenSend = new Bitmap(this._imgScreenSend.Width,   this._imgScreenSend.Height);
                    // Send an image code
                    swWriter.WriteLine(General.IMAGE);
                    swWriter.Flush();

                    // Copy image from screen
                    this._grGraphics.CopyFromScreen(0, 0, 0, 0, this._sizScreenSize);
                    this._imgScreenSend.Save(msStream, System.Drawing.Imaging.ImageFormat.Jpeg);
                    msStream.Seek(0, SeekOrigin.Begin);

                    // Create the pakage
                    byte[] btPackage = msStream.ToArray();

                    // Send its langth
                    swWriter.WriteLine(btPackage.Length.ToString());
                    swWriter.Flush();

                    // Send the package
                    _nsClient.Write(btPackage, 0, btPackage.Length);
                    _nsClient.Flush();
                }
            }
        }
    }


    private void ReciveData()
    {
        StreamReader srReader = new StreamReader(this._nsClient);
        string strMsgCode = String.Empty;
        bool    bContinue = true;
        //BinaryFormatter bfFormater = new BinaryFormatter();
        DataContractSerializer x = new DataContractSerializer(typeof(Image));
        // Lock this method
        lock (this._objLocker)
        {
            while (bContinue)
            {
                // Get the next msg
                strMsgCode = srReader.ReadLine();

                // Check code
                switch (strMsgCode)
                {
                    case (General.IMAGE):
                        {
                            // Read bytearray
                            int nSize = int.Parse(srReader.ReadLine().ToString());
                            byte[] btImageStream = new byte[nSize];
                            this._nsClient.Read(btImageStream, 0, nSize);

                            // Get the Stream
                            MemoryStream msImageStream = new MemoryStream(btImageStream, 0, btImageStream.Length);

                            // Set seek, so we read the image from the begining of the stream
                            msImageStream.Position = 0;

                            // Build the image from the stream
                            this._imgScreenImg = Image.FromStream(msImageStream); // Error Here

person David Limkys    schedule 31.08.2012    source источник


Ответы (2)


Часть проблемы заключается в том, что вы используете WriteLine(), который добавляет Environment.NewLine в конце записи. Когда вы просто вызываете Read() на другом конце, вы неправильно работаете с новой строкой.

То, что вы хотите сделать, это просто Write() в поток, а затем прочитать его на другом конце.

Преобразование в строку странное.

То, что вы делаете при передаче изображения, отправляет массив байтов. Все, что вам нужно сделать, это отправить длину ожидаемого потока, а затем само изображение, а затем прочитать длину и массив байтов на другой стороне.

Самый простой и наивный способ передачи массива байтов по сети состоит в том, чтобы сначала отправить целое число, представляющее длину массива, и прочитать эту длину на принимающей стороне.

Как только вы теперь знаете, сколько данных нужно отправить/получить, вы затем отправляете массив в виде необработанного массива байтов по проводу и считываете длину, которую вы ранее определили, на другой стороне.

Теперь, когда у вас есть необработанные байты и размер, вы можете восстановить массив из своего буфера в допустимый объект изображения (или любой другой двоичный формат, который вы только что отправили).

Кроме того, я не уверен, почему этот DataContractSerializer существует. Это необработанные двоичные данные, и вы все равно вручную сериализуете их в байты, так что это бесполезно.

Одной из фундаментальных проблем сетевого программирования с использованием сокетов и потоков является определение вашего протокола, потому что иначе принимающая сторона не может знать, чего ожидать или когда закончится поток. Вот почему каждый распространенный протокол либо имеет очень строго определенный размер и расположение пакетов, либо делает что-то вроде отправки пар длина/данные, чтобы принимающая сторона знала, что делать.

Если вы реализуете очень простой протокол, такой как отправка целого числа, представляющего длину массива, и чтение целого числа на принимающей стороне, вы достигли половины цели. Затем и отправитель, и получатель приходят к соглашению относительно того, что произойдет дальше. Затем отправитель отправляет точно такое же количество байтов по проводу, а получатель считывает точно такое же количество байтов по проводу и считает, что чтение завершено. Теперь у вас есть точная копия исходного массива байтов на принимающей стороне, и вы можете делать с ней что угодно, поскольку вы знаете, что это были за данные изначально.

Если вам нужен пример кода, я могу предоставить простой пример, либо в сети доступно множество примеров.

person dodexahedron    schedule 31.08.2012
comment
Я отправляю в строке записи чтение в readLine, это потому, что я отправляю сообщение IMG, поэтому функция ReciveData теперь будет получать изображение, и я также отправляю размер массива в строку записи и читаю это в строке чтения, я отправляю массив при записи и читаю его при чтении, я не понимаю вашей точки зрения. - person David Limkys; 31.08.2012

Попытка сделать это кратким: функция Stream.Read (которую вы используете) возвращает int, в котором указано, сколько байтов было прочитано, это возвращается вам, чтобы вы могли убедиться, что все байты, которые вам нужны, получены. что-то типа:

int byteCount=0;
while(byteCount < nSize)
{
      int read = this._nsClient.Read(btImageStream, byteCount, nSize-byteCount);
      byteCount += read;
}

это не лучший код для работы

person Eyal H    schedule 31.08.2012
comment
Спасибо, похоже, это помогает, но теперь у меня более серьезная проблема, метод записи не отправляет все данные, как я могу это исправить? - person David Limkys; 31.08.2012
comment
извините, не могу придумать причину, по которой запись не отправляет все данные. просто чтобы вы знали, согласно MSDN, нет смысла вызывать flush() в сетевом потоке. - person Eyal H; 31.08.2012