C# 中的位图字节操作
努力操作 Bitmap 对象的底层字节以消除图像的透明度。 我有一个静态删除透明度方法,它需要一个 Bitmap 对象,相关代码: http://pastebin.com/ZjjPSdx8
现在,当我使用基于文件的位图对象调用它时,位图不会发生变化。如果我理解正确,这是因为它基于 http://support.microsoft.com/ 的文件kb/814675
因此创建了一个复制位图的方法: http://pastebin.com/9rXRJ6cx
private Bitmap LoadBmp(string name)
{
Assembly asm = Assembly.GetExecutingAssembly();
string loc = Path.GetDirectoryName(asm.Location);
string path = Path.Combine(loc, "Images\\" + name);
Bitmap notsafe = (Bitmap)Bitmap.FromFile(path);
return ImageProcessor.SafeBitmap(notsafe);
...
一切都很好。适用于 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! 显然我做错了什么,希望有人可以帮助!
Struggling with manipulating the underlying bytes of a Bitmap object to remove the transparency of an image.
I have a static remove transparency method, that takes a Bitmap object, relevent code: http://pastebin.com/ZjjPSdx8
Now when I call this with a Bitmap object based on a File, the bitmap isn't mutated. If I understand correctly this is because as it's based on a File as per http://support.microsoft.com/kb/814675
So created a method to copy the bitmap:
http://pastebin.com/9rXRJ6cx
private Bitmap LoadBmp(string name)
{
Assembly asm = Assembly.GetExecutingAssembly();
string loc = Path.GetDirectoryName(asm.Location);
string path = Path.Combine(loc, "Images\\" + name);
Bitmap notsafe = (Bitmap)Bitmap.FromFile(path);
return ImageProcessor.SafeBitmap(notsafe);
...
All fine and dandy. Works well with PNGs, however not with GIFs. They come out horribly
distorted.
Tried an alternate method writing the file to a byte array, and then basing the bitmap on that:
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));
This doesn't distort the gif's. however my remove transparency method no longer works on the PNGs!
Clearly I'm doing something wrong, hopefully someone can help!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
编辑:
您可以在从文件加载时解决不可变位图问题,如下所示:
var bmp = new Bitmap(Image.FromFile("C:\bmp.bmp"))
这使您不必执行任何 Marshal.Copy(速度很慢),它还可以解决 GIF 被肢解和扭曲的问题。如果您感兴趣的话,执行此操作的内部 .NET 代码如下:
所以它本质上是我在下面提供的代码,用于解决您的透明度问题,但它不能满足您的速度需求。
但是,如果您可以通过 g.FromImage 同时进行加载和复制,我的速度为
(5.6 秒 g.FromImage vs 6.4 秒,1000 个 gif @ 543x341)
理论上,您如果将复制和删除透明度合并到同一个函数中,可以使您的速度更快。如果您加载 GIF 而不重写图像,它将采用不同的像素格式,事实上,
8bppindexed
,这意味着您的函数将无法按原样工作。无论哪种方式,上面的解决方案都可以解决使用 CheckIfTransparent 函数时的问题,而下面的解决方案(我必须对其进行一些编辑)会更快。如果我这样做的话,我可能会花一些时间来研究这个问题。我觉得这个问题很有趣。我确实注意到你删除阿尔法的算法并不完全准确。我不确定具体在哪里,但是当与透明渐变一起使用时,您的算法看起来是错误的。使用直接 GDI 的看起来符合预期。我会确保您正确转换颜色。
如果您只想删除 png 或 gif 上的透明度,执行所有这些
Marshal.Copy
和不安全的代码,为什么不直接创建一个新的位图,将背景绘制为白色,然后覆盖现有的位图png/gif 就可以了吗?看起来代码不太复杂。编辑:像这样的:
这将为您提供一个具有白色背景的新图像,并将源图像放在其之上,有效地将所有透明像素更改为
Color.White
或您想要的任何颜色通过g.Clear()
EDIT:
You can solve your immutable bitmap problem when loading from a file as such:
var bmp = new Bitmap(Image.FromFile("C:\bmp.bmp"))
That prevents you from having to do any Marshal.Copy (which are slow), it also solves your problem with GIFs getting mutilated and distorted. The internal .NET code which does this, if you're interested is the following:
so it is essentially the code I gave you below, for solving your transparency problem, which didn't meet your speed needs.
However, if you you can do the load and copy at the same time via g.FromImage, I got speeds of
(5.6 seconds g.FromImage vs 6.4 seconds yours with 1000 gifs @ 543x341)
In theory you can make yours faster, if you combine the copying and removing transparency into the same function. If you load a GIF without rewriting the image, it will be in a different pixel format, in fact,
8bppindexed
, which means your function won't work as is. Either way, the solution above will solve the issue when using your CheckIfTransparent function, and the solution below (I had to edit a little of it) will do it faster. I may spend some time looking to that if I do. I find the problem interesting.I did notice that your algo to remove the alpha isn't completely accurate. I'm not sure where exactly, but your algo looks wrong when used with transparent gradients. The one using straight GDI looks as expected. I would make sure you're converting the colors correctly.
If you just want to remove the transparency on a png or a gif, doing all this
Marshal.Copy
and unsafe code, why not just create a new Bitmap, draw the background white, and then overlay the exiting png/gif on it? Seems like less complicated code.EDIT: Something like this:
That will give you a new image with a white background, and put the source image on top of that, effectively changing all transparent pixels to
Color.White
or whatever color you want to passg.Clear()
我会尝试使用 WriteableBitmap班级。我听说它只是为了使用托管代码进行像素操作而创建的。
I'd try with the WriteableBitmap class. I heard that has been created just for pixel manipulation using managed code.