在C#中将原始字节转换为gif文件图像

时间:2018-12-04 14:55:11

标签: c# image-processing gif converters

我有原始字节数组数据,并想将其转换为c#上的.gif图像。我尝试过这种方法,如下所示。 我想问一下如何在c#中执行此操作。

我尝试过的方法: 从MemoryStream构造byte[]并使用Image.FromStream:这不起作用,因为我只有原始字节数组,要显示的图像像素以及构造函数字节数组需要的参数也是图像的元数据。

public static Image ConvertByteArraytoBitmap(byte[] bytes)
        {
            using (MemoryStream ms = new MemoryStream(bytes))
                return Image.FromStream(ms);
        }

edit:对于John,原始字节数组(此图像较小,并且字节数组仅为100字节):

 woDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoDCgMKAwoA=

1 个答案:

答案 0 :(得分:0)

在.Net中处理8位图像的方法不是很简单。您需要使用Bitmap构造函数创建一个新的(width, height, pixelformat),然后使用LockBits打开其后备字节数组,并使用Marshal.Copy将图像数据复制到其中。

请注意,此后备数据数组中一行的长度(以字节为单位)称为“跨步”,始终四舍五入为四个字节的倍数,因此您必须逐行复制数据,然后跳至使用跨距的下一行位置,而不仅仅是(图像宽度*每像素位数)值。

但是,就图像宽度而言...您的字节数组仅是图像的一部分。如果仅仅是像素数据,则将丢失所有常用的图像标头信息,例如图像尺寸,并且假设像素格式为8位索引(如gif),则为调色板。此数据不是可选的;没有它,就无法重建图像。

如果图像是灰度图像,并且每个字节仅代表亮度,则可以通过简单的for循环轻松生成调色板,但是:

Color[] palette = new Color[256];
for (Int32 i = 0; i < palette.Length; i++)
    palette[i] = Color.FromArgb(i, i, i);

一旦(以某种方式)获得了丢失的信息,这就是通过字节数组制作图像的方法:

/// <summary>
/// Creates a bitmap based on data, width, height, stride and pixel format.
/// </summary>
/// <param name="sourceData">Byte array of raw source data</param>
/// <param name="width">Width of the image</param>
/// <param name="height">Height of the image</param>
/// <param name="stride">Scanline length inside the data</param>
/// <param name="pixelFormat">Pixel format</param>
/// <param name="palette">Color palette</param>
/// <param name="defaultColor">Default color to fill in on the palette if the given colors don't fully fill it.</param>
/// <returns>The new image</returns>
public static Bitmap BuildImage(Byte[] sourceData, Int32 width, Int32 height, Int32 stride, PixelFormat pixelFormat, Color[] palette, Color? defaultColor)
{
    Bitmap newImage = new Bitmap(width, height, pixelFormat);
    BitmapData targetData = newImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, pixelFormat);
    //If the input stride is larger than the width, this calculates the actual amount of bytes to copy for each line.
    Int32 newDataWidth = ((Image.GetPixelFormatSize(pixelFormat) * width) + 7) / 8;
    // Compensate for possible negative stride on BMP format data.
    Boolean isFlipped = stride < 0;
    stride = Math.Abs(stride);
    // Cache these to avoid unnecessary getter calls.
    Int32 targetStride = targetData.Stride;
    Int64 scan0 = targetData.Scan0.ToInt64();
    for (Int32 y = 0; y < height; y++)
        Marshal.Copy(sourceData, y * stride, new IntPtr(scan0 + y * targetStride), newDataWidth);
    newImage.UnlockBits(targetData);
    // Fix negative stride on BMP format.
    if (isFlipped)
        newImage.RotateFlip(RotateFlipType.Rotate180FlipX);
    // For indexed images, set the palette.
    if ((pixelFormat & PixelFormat.Indexed) != 0 && palette != null)
    {
        ColorPalette pal = newImage.Palette;
        for (Int32 i = 0; i < pal.Entries.Length; i++)
        {
            if (i < palette.Length)
                pal.Entries[i] = palette[i];
            else if (defaultColor.HasValue)
                pal.Entries[i] = defaultColor.Value;
            else
                break;
        }
        newImage.Palette = pal;
    }
    return newImage;
}

对于8位图像的紧凑字节数组,宽度和步幅应相同。但是,如果没有调色板或尺寸,则无法实现。

为记录起见,您在上方重复的{0xC2,0x80}字节数组作为10×20灰度图像加载(200字节,而不是您所说的100字节),给出了此结果(放大到x20):

Byte array loaded as 8-bit grayscale image 只是2个重复字节,宽度相等,所以您得到的只是垂直线...