【问题标题】:Display a byte array in a pictureBox in C#在C#中的pictureBox中显示一个字节数组
【发布时间】:2012-04-02 18:27:06
【问题描述】:

我阅读了很多问题和答案,大多数建议:

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

或更直接地:

pictureBox.Image = Image.FromStream(stream);

我总是得到:“System.Drawing.dll 中发生了“System.ArgumentException”类型的未处理异常

附加信息:参数无效。"

关于流参数。

即使在以下情况下:

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,值无处不在,等等。

编辑 #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 ;

【问题讨论】:

  • bytearray中图片的格式是什么?最后一个例子永远不会工作......想不出一个字节的图像:)
  • 那么 byte[] 数据格式不正确。
  • 最后一个例子只是说即使我知道数据格式正确,如 leppie 所说,流也不起作用,我将编辑并编写我拥有的数据的示例
  • 您能给我们看一个示例数据文件吗?
  • 数据是否表示每个像素的实际 RGB 颜色值?一个像素使用多少字节?或者数据是否还包含标题(例如位图标题)?

标签: c# bitmap picturebox


【解决方案1】:

每个图像都需要描述字节数组的内容。这种描述称为标题。如果现在要交换字节,则需要避免更改标头。

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

【讨论】:

    【解决方案2】:

    按照您帖子顶部的原始建议,我对这项工作没有任何问题。

    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;
    }
    

    现在,我不知道这是否安全/正确,但它似乎有效。

    【讨论】:

    • 是的,这几乎就是我想要做的,除了我的数据来自文本文件并且流不起作用......
    • 也许 ReadToEnd 没有返回您认为返回的内容?您是否尝试将其读入缓冲区?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-09
    • 1970-01-01
    • 2016-05-29
    • 2016-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多