C# C语言中的位图字节操作#

C# C语言中的位图字节操作#,c#,bitmap,png,transparency,gif,C#,Bitmap,Png,Transparency,Gif,正在努力操纵位图对象的底层字节以去除图像的透明度。 我有一个静态删除透明度方法,它采用位图对象,相关代码: 现在,当我使用基于文件的位图对象调用它时,位图不会发生变化。如果我理解正确,这是因为它基于 因此创建了一个复制位图的方法: 一切都很好。与PNG配合良好,但与GIF不配合。他们表现得很糟糕 扭曲的 尝试了另一种方法,将文件写入字节数组,然后基于该方法创建位图: byte[] b = new byte[2048]; int c; byte[]

正在努力操纵位图对象的底层字节以去除图像的透明度。 我有一个静态删除透明度方法,它采用位图对象,相关代码:

现在,当我使用基于文件的位图对象调用它时,位图不会发生变化。如果我理解正确,这是因为它基于

因此创建了一个复制位图的方法:

一切都很好。与PNG配合良好,但与GIF不配合。他们表现得很糟糕 扭曲的

尝试了另一种方法,将文件写入字节数组,然后基于该方法创建位图:

        byte[] b = new byte[2048];
        int c;
        byte[] imgArr;
        using (FileStream fs = new FileStream(path, FileMode.Open))
        {
            using (MemoryStream ms = new MemoryStream())
            {
                while ((c = fs.Read(b, 0, b.Length)) > 0)
                    ms.Write(b, 0, c);
                imgArr = ms.ToArray();
            }
        }

        return (Bitmap)Bitmap.FromStream(new MemoryStream(imgArr));
这不会扭曲gif。但是,我的删除透明度方法不再适用于PNG! 很明显我做错了什么,希望有人能帮忙

我想和全班同学一起试试。我听说它是为使用托管代码进行像素操作而创建的。

编辑:

从以下文件加载时,可以解决不可变位图问题:

var bmp=新位图(Image.FromFile(“C:\bmp.bmp”))

这样可以避免您执行任何Marshal.Copy(速度较慢),还可以解决GIF被破坏和扭曲的问题。如果您感兴趣,则执行此操作的内部.NET代码如下:

 g = Graphics.FromImage(this);
 g.Clear(Color.Transparent); 
 g.DrawImage(original, 0, 0, width, height);
这就是我在下面给你的代码,用来解决你的透明度问题,它不能满足你的速度需求

但是,如果您可以通过g.FromImage同时进行加载和复制,我的速度为
(g.FromImage为5.6秒,而您的1000 GIF为6.4秒@543x341)

从理论上讲,如果将复制和删除透明度合并到同一个功能中,则可以加快速度。如果加载GIF而不重写图像,它将采用不同的像素格式,事实上,
8bpindexed
,这意味着您的函数将无法正常工作。无论哪种方式,上面的解决方案都会在使用CheckIftTransparent函数时解决问题,下面的解决方案(我必须编辑一点)会更快。如果我这样做的话,我可能会花一些时间考虑这个问题。我觉得这个问题很有趣

我确实注意到你删除alpha的算法并不完全准确。我不确定确切的位置,但是当使用透明渐变时,你的算法看起来是错误的。使用直接GDI的那个看起来和预期的一样。我会确保你正确地转换颜色


如果您只想删除png或gif上的透明度,执行所有这些
Marshal.Copy
和不安全的代码,为什么不创建一个新位图,将背景画成白色,然后在其上覆盖现有的png/gif?似乎不那么复杂的代码

编辑:类似这样的内容:

    public static Bitmap ManagedSafeBitmap(string file)
    {
        using (var img = Image.FromFile(file))
        {
            var bmp = new Bitmap(img.Width, img.Height);
            bmp.SetResolution(img.HorizontalResolution, img.VerticalResolution);
            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.Clear(Color.White);
                g.DrawImage(img, 0, 0);
            }

            return bmp;
        }
    }

这将为您提供一个白色背景的新图像,并将源图像置于该图像之上,有效地将所有透明像素更改为
颜色。白色
或您想要传递的任何颜色
g.Clear()

与您的问题没有直接关系,但如果有精彩的
ReadAllBytes()
文件
对象上的
方法,
System.IO.File.ReadAllBytes()
思考全局的伟大工作!是的,最初是这样做的,但想从中挤出更多的速度。。托管方法比MakeSafe和CleanTransparent的组合慢大约50%。如果没有makesafe(尽管不可否认,没有它就无法工作……),速度会慢300%。我会处理很多图像,这样速度差就很重要了。。。(1亿美元)。谢谢!我自己做了一些速度测试,加上负载和透明(托管和非托管),我的速度分别是5.1和5.3 p/1000。然而,其优点是,当图像没有透明度时,非托管方法的速度更快(仅对支持它的图像可以选择删除透明度)-我们的大量图像也将是jpg的。。无论如何,我在这上面花了太多的时间,所以现在我要用你的方法-截止日期和所有。。。然而,我仍然对图像失真的原因非常感兴趣,我很想让orig方法发挥作用。。如果有帮助的话:)我认为复制过程中图像会失真,而不是透明度的变化。加载的GIF是使用索引托盘加载的,我认为Marshal.Copy是将现有数据复制到不同的像素格式。LockBits希望您知道PixelFormat,我认为它应该被设置为8bpping时被设置为32bitArgb。当然,您不能执行封送处理。然后复制并期望得到正确的结果,因为您必须变换每个像素,这通常是有损转换。
    public static Bitmap ManagedSafeBitmap(string file)
    {
        using (var img = Image.FromFile(file))
        {
            var bmp = new Bitmap(img.Width, img.Height);
            bmp.SetResolution(img.HorizontalResolution, img.VerticalResolution);
            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.Clear(Color.White);
                g.DrawImage(img, 0, 0);
            }

            return bmp;
        }
    }