Показать байтовый массив в pictureBox в C # - PullRequest
4 голосов
/ 02 апреля 2012

Я прочитал много вопросов и ответов, большинство из них предлагают:

byte[] byteArray; //(contains image data)
MemoryStream stream = new MemoryStream(byteArray);
Bitmap image = new Bitmap(stream);
pictureBox.Image = image;

или более:

pictureBox.Image = Image.FromStream(stream);

Я всегда получаю: «Необработанное исключение типа« Система ».ArgumentException 'произошло в System.Drawing.dll

Дополнительная информация: параметр недействителен. "

в отношении параметра потока.

Даже в случае, когда:

byte[] byteArray = new byte[1];
byteArray[0] = 255;

Я не могу понять, почему.

РЕДАКТИРОВАТЬ:

Я получаю данные из файла, как это:

//byteArray is defined as List<byte> byteArray = new List<byte>();
TextReader tr = new StreamReader(file);
string File = tr.ReadToEnd();
string[] bits = File.Split('\t');
List<string> image = new List<string>(bits);
height = int.Parse(bits[0]);
width  = int.Parse(bits[1]);
image.RemoveRange(0, 2);
image.RemoveAt(image.Count - 1);
foreach (string s in image)
{
  byteArray.Add(byte.Parse(s));
}
return byteArray //(i do .ToArray() in the MemoryStream call);

Вотладчик, я вижу то есть, что byteArray в порядке, count = 2244, значения везде и т. д.

EDIT # 2: Образец файла данных (первый байт [0] - высота, второй байт [1] - ширина), остальные данные RGB)

47 15 12 55 25 52 55 25 52 55 25 52 55 25 52 55
25 52 55 25 52 55 25 52 55 25 52 55 25 52 55 25
52 55 25 52 55 25 52 55 25 52 55 25 52 55 25 52
55 25 52 55 25 52 55 25 52 55 25 52 55 25 52 55
25 52 51 24 82 49 24 82 49 24 92 50 25 12 50 24
92 48 24 92 50 24 82 50 25 02 50 24 92 50 25 02
51 25 12 50 24 92 49 25 02 50 25 02 49 25 12 49
25 02 49 25 02 47 25 12 47 25 22 50 24 82 47 24
82 50 24 72 50 24 82 49 24 82 50 24 72 50 24 82
50 24 72 49 24 82 49 25 22 52 24 92 50 24 82 50
24 72 47 25 00 etc.

РЕДАКТИРОВАТЬ # 3: РЕШЕНИЕ

Bitmap bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
IntPtr ptr = bmpData.Scan0;
Marshal.Copy(byteArray, 0, ptr, height * width * 3);
bmp.UnlockBits(bmpData);
pictureBox.Image = bmp;

Необходимо проверить выравнивание 4 байта, поэтому функция загрузки теперь:

TextReader tr = new StreamReader(file);
string File = tr.ReadToEnd();
string[] bits = File.Split('\t');
List<string> image = new List<string>(bits);
height = int.Parse(bits[0]);
width  = int.Parse(bits[1]);
int falseBits = 0;
int oldWidth = width;
while (width % 4 != 0)
{
    width++;
    falseBits++;
}
int size = height * width * 3;
byte[] byteArray = new byte[size];
Parallel.For(0, size - 1, i => byteArray[i] = 255);
int index  = 0;
int lineIndex = 0;
image.RemoveRange(0, 2);
image.RemoveAt(image.Count - 1);
foreach (string s in image)
{
    byteArray [index]   = byte.Parse(s);
    byteArray [index + 1] = byteArray [index];
    byteArray [index + 2] = byteArray [index];
    index +=3;
    lineIndex++;
    if (lineIndex == oldWidth)
    {
        lineIndex = 0;
        index += 3*falseBits;
    }
}
return byteArray ;

Ответы [ 2 ]

2 голосов
/ 02 апреля 2012

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

http://en.wikipedia.org/wiki/BMP_file_format

Это пример моего исходного кода при работе с таким ByteArray

''' <summary>
''' Copies an Bytearray into an image and return it.
''' </summary>
''' <param name="ArrSrc">Source byte array of image which can be anything</param>
''' <param name="ImageSize">the image size of the image</param>
''' <param name="SourceArrayPixelFormat">Pixel format, like 24Bit or 32Bit</param>
''' <returns>System.Drawing.Image</returns>
''' <remarks>copyright, http://software.goldengel.ch, 2012</remarks>
Public Function ArrayToBitmapData(ByVal ArrSrc() As Byte, ByVal ImageSize As System.Drawing.Size, ByVal SourceArrayPixelFormat As System.Drawing.Imaging.PixelFormat) As System.Drawing.Bitmap
    'Kopiert ein ByteArray in ein Bitmap

    Dim m As Integer
    Dim bmTemp As System.Drawing.Bitmap = Nothing
    Dim S As System.Drawing.Size
    Dim MemorySize As Integer
    Dim ScanLine As Integer

    'Bild prüfen
    If ArrSrc Is Nothing Then Return bmTemp

    'Bildgrösse definieren
    'Bei unterschiedlichen Grössen, wird muss die kleinere Grösse verwendet werden
    S = ImageSize


    'Helfer für die Bildverarbeitung erzeugen
    Dim bts As System.Drawing.Imaging.BitmapData

    'Bitmap erzeugen um damit zu arbeiten
    bmTemp = New System.Drawing.Bitmap(S.Width, S.Height, SourceArrayPixelFormat)

    'Farbtiefe berechnen
    '24Bit und 32Bit Bilder werden unterstützt
    'Kann beliebig erweitert werden
    m = BytesInPixelFormat(SourceArrayPixelFormat)



    '*** Hauptroutine - Array --> Bitmap ***

    'Bilddaten in die Picturebox laden
    bts = bmTemp.LockBits(New System.Drawing.Rectangle(0, 0, S.Width, _
        S.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, SourceArrayPixelFormat)


    'Speicherplatz reservieren
    'MemorySize = S.Height * S.Width * m
    'Nur zur Kontrolle
    ScanLine = GetScanline(S, SourceArrayPixelFormat)

    MemorySize = S.Height * bts.Stride
    If ArrSrc.Length >= MemorySize Then
        'Bilddaten aus dem Array laden
        Global.System.Runtime.InteropServices.Marshal.Copy(ArrSrc, 0, bts.Scan0, MemorySize)
    End If
    bmTemp.UnlockBits(bts)

    'Erzeugtes Bitmap zurückgeben
    Return bmTemp

End Function



convert Bitmap image into byte array

'Neue Funktion 27.2.2008
'Mit korrekter Dimensionierung mittels bts.Stride und Umrechnung auf das Pixelformat
''' <summary>
''' Get an Array of the data of any image. 
''' Bitmap header execluded.
''' </summary>
''' <param name="bmSrc">Source image</param>
''' <param name="NeededDestinationPixelFormat">Pixelformat, like 24Bit or 32Bit</param>
''' <returns>Image content</returns>
''' <remarks>copyright http://software.goldengel.ch, 2012</remarks>
Public Function BitmapDataToArray(ByVal bmSrc As System.Drawing.Bitmap, ByVal NeededDestinationPixelFormat As System.Drawing.Imaging.PixelFormat, ByRef DstStride As Integer) As Byte()
    'Kopiert ein Bild in ein Bytearray

    Dim m As Integer
    Dim A() As Byte = Nothing
    Dim S As System.Drawing.Size
    Dim MemorySize As Integer
    Dim bmTemp As System.Drawing.Bitmap = Nothing

    'Bild prüfen
    If bmSrc Is Nothing Then Return A

    'Bildgrösse definieren
    'Bei unterschiedlichen Grössen, wird muss die kleinere Grösse verwendet werden
    S = bmSrc.Size


    'Helfer für die Bildverarbeitung erzeugen
    Dim bts As System.Drawing.Imaging.BitmapData

    'Farbtiefe berechnen
    '24Bit und 32Bit Bilder werden unterstützt
    'Kann beliebig erweitert werden
    m = BytesInPixelFormat(NeededDestinationPixelFormat)


    '*** Hauptroutine - Bitmap --> Array ***
    'Bilddaten aus der Picturebox laden
    If NeededDestinationPixelFormat <> bmSrc.PixelFormat Then
        'Bitmap erzeugen um damit zu arbeiten
        bmTemp = New System.Drawing.Bitmap(S.Width, S.Height, NeededDestinationPixelFormat)

        Using gr As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(bmTemp)
            gr.DrawImage(bmSrc, 0, 0)
        End Using
        'ImgSrc.Dispose()'Achtung, würde das Original mit zerstören
        bmSrc = bmTemp
    End If

    bts = bmSrc.LockBits(New System.Drawing.Rectangle(0, 0, S.Width, _
        S.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, NeededDestinationPixelFormat)

    'Speicherplatz reservieren
    MemorySize = S.Height * bts.Stride
    ReDim A(MemorySize - 1) '28.2.2010. wichtige Änderung. 1 Byte zuviel wurde reserviert. Das konnte bei Wiederholung von Graphics.Drawing zu einem Fehler kommen

    'Bitmapdaten in das Array kopieren
    Global.System.Runtime.InteropServices.Marshal.Copy(bts.Scan0, A, 0, A.Length)
    bmSrc.UnlockBits(bts)

    DstStride = bts.Stride

    If bmTemp IsNot Nothing Then bmTemp = Nothing

    Return A

End Function
1 голос
/ 02 апреля 2012

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

pictureBox.Image = GetImage();

public Image GetImage()
{
    Image image;
    using (FileStream fs = File.OpenRead(@"C:\picture.jpg"))
    {
        long length = fs.Length;

        byte[] bytes = new byte[length];

        for (int pos = 0; pos < length; )
            pos += fs.Read(bytes, pos, (int)length - pos);

        fs.Position = 0;

        using (MemoryStream ms = new MemoryStream(bytes))
            image = Image.FromStream(ms);
    }

    return image;
}

Теперь, насколько это безопасно / правильно, я не знаю, но, похоже, это работает.

...