开发者

Bitmap byte manipulation in C#

开发者 https://www.devze.com 2023-03-23 20:48 出处:网络
Struggling with manipulating the underlying bytes of a Bitmap object to remove the transparency of an image.

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开发者_StackOverflow社区.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!


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:

 g = Graphics.FromImage(this);
 g.Clear(Color.Transparent); 
 g.DrawImage(original, 0, 0, width, height);

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:

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

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 pass g.Clear()


I'd try with the WriteableBitmap class. I heard that has been created just for pixel manipulation using managed code.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号