5

我一直在寻找将位图转换为 8bpp 的最快方法。我找到了两种方法:

1.

        public static System.Drawing.Image ConvertTo8bpp(Bitmap oldbmp)
    {
        using (var ms = new MemoryStream())
        {
            oldbmp.Save(ms, ImageFormat.Gif);
            ms.Position = 0;
            return System.Drawing.Image.FromStream(ms);
        }
    }

2. http://www.wischik.com/lu/programmer/1bpp.html

但是: 1.结果质量非常低(坏托盘)

2给了我一个负步幅的位图,当我尝试锁定位并将数据复制到字节数组时,我得到一个异常:尝试读取或写入受保护的内存。这通常表明其他内存已损坏。

        BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat);

        this.stride = bmpData.Stride;
        this.bytesPerPixel = GetBytesPerPixel(bmp.PixelFormat);
        int length = bmpData.Stride * bmp.Height;
        if (this.stride < 0)
            this.data = new byte[-length];
        else
            this.data = new byte[length];
        Marshal.Copy(bmpData.Scan0, data, 0, length);

        //Unlock the bitmap
        bmp.UnlockBits(bmpData);

我怎样才能使2取得积极进展?或者如何使用负跨度的锁定位复制数据?

4

5 回答 5

8

这里的问题是Scan0指向第一个扫描线的开始,而不是第一个数据字节的开始。在自底向上位图中,第一扫描线是Stride位图数据末尾的字节。

当您调用Marshal.Copy从 复制数据时Scan0,它会尝试(Height*Stride)从 position 开始复制字节((Height-1)*Stride)。显然,这会跑到杂草中。

如果你只是想复制位图数据,你必须用 . 计算起始地址Scan0 - (Height-1)*Stride。这将从位图数据的开头开始。您可以将该计算出的地址传递给Marshal.Copy.

如果要按顺序复制扫描线(即顶部,下一个,下一个,...底部),那么您必须一次复制一行:Stride从 复制字节Scan0,然后添加Stride(这是负数),复制该行等等。Rick Brewster 有正确的答案:https ://stackoverflow.com/a/10360753/56778

于 2013-06-14T19:39:40.893 回答
7

一次复制 1 行,将行的起始指针计算为((byte*)scan0 + (y * stride))。无论是正步还是负步,代码都是相同的。

于 2012-04-28T05:03:39.357 回答
5

我不知道为什么该FromHbitmap方法创建的 Bitmap 有一些奇怪的地方,但我知道您可以通过Bitmap bmpClone = (Bitmap)bmp.Clone();在 bmpClone 上使用和执行 LockBits 来修复它。

另外,我发现如果你使用bmp.Clone(),在你完成克隆之前你不能 Dispose() 的 bmp。

这也有效,让您尽早处理负步幅图像:

        Bitmap bmp = null;
        using (Bitmap bmpT = CopyToBpp(bmpO, 1))
        {
            bmp = new Bitmap(bmpT);
        }
于 2012-04-26T20:58:54.500 回答
1

来自 BitmapData 上的 C# 文档:步幅是单行像素(扫描线)的宽度,四舍五入到四字节边界。如果步幅为正,则位图是自上而下的。如果步幅为负,则位图自下而上

于 2011-07-26T18:55:11.087 回答
-2

我猜你得到的例外是由于

this.data = new byte[-length];

然后尝试将数据复制到一个负大小的字节数组中(我看不出它是如何编译的……)。

于 2012-05-03T12:01:10.547 回答