C# - Remove Bitmap padding

浪子不回头ぞ 提交于 2019-12-19 11:16:07

问题


I was wondering if there's a way in order to remove the padding generated by the 24 bit Bitmap for each scan line.

What I mean is like this :

Original [Pure Cyan 24 Bit BMP] :

FF FF 00 FF FF 00 FF FF **00 00** FF FF 00 FF FF 00 FF FF 00

Desired output [Removed Padding] :

FF FF 00 FF FF 00 FF FF **00** FF FF 00 FF FF 00 FF FF 00

Here's my code for getting the pixel data.

            Bitmap tmp_bitmap = BitmapFromFile;

            Rectangle rect = new Rectangle(0, 0, tmp_bitmap.Width, tmp_bitmap.Height);
            System.Drawing.Imaging.BitmapData bmpData =
                tmp_bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
                PixelFormat.Format24bppRgb);

            int length = bmpData.Stride * bmpData.Height;

            byte[] bytes = new byte[length];

            // Copy bitmap to byte[]
            Marshal.Copy(bmpData.Scan0, bytes, 0, length);
            tmp_bitmap.UnlockBits(bmpData);

Thank you in advance.


回答1:


No, you'll have to remove it yourself. Padding is added to ensure that the start of a scanline in the bitmap starts at a multiple of 4. So getting padding is pretty likely when the pixel format is 24bpp, bmp_bitmap.Width * 3 is only divisible by 4 by accident.

You'll need a loop to copy each line. Something like this:

byte[] bytes = new byte[bmpData.Width * bmpData.Height * 3];
for (int y = 0; y < bmpData.Height; ++y) {
    IntPtr mem = (IntPtr)((long)bmpData.Scan0 + y * bmpData.Stride);
    Marshal.Copy(mem, bytes, y * bmpData.Width * 3, bmpData.Width * 3);
}



回答2:


You should copy the bitmap line by line, but skip padding bytes. An extension method for that would be:

static class BitmapExtensions
{
    public static void RemovePadding(this Bitmap bitmap)
    {
        int bytesPerPixel = Image.GetPixelFormatSize(bitmap.PixelFormat) / 8;

        BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
        var pixels = new byte[bitmapData.Width * bitmapData.Height * bytesPerPixel];

        for (int row = 0; row < bitmapData.Height; row++)
        {
            var dataBeginPointer = IntPtr.Add(bitmapData.Scan0, row * bitmapData.Stride);
            Marshal.Copy(dataBeginPointer, pixels, row * bitmapData.Width * bytesPerPixel, bitmapData.Width * bytesPerPixel);
        }

        Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length);
        bitmap.UnlockBits(bitmapData);
    }
}



回答3:


I created an Extension mehtod to AutoCrop images.I look for the first filed pixel on Left, Top, Right and Bottom. Then calculate a rectangle. Using Graphics.DrawImage you can specify the cropped region via the source and new Rectangle.

public static Bitmap AutoCrop(this Bitmap bitmap)
    {
        int leftSHift = 0;
        int topShift = 0;
        int rightShift = 0;
        int bottomShift = 0;

        // left Shift
        for (int widthX = 0; widthX < bitmap.Width; widthX++)
        {
            for (int heightY = 0; heightY < bitmap.Height; heightY++)
            {
                Color c = bitmap.GetPixel(widthX, heightY);
                if (!c.Name.Equals("0"))
                {
                    leftSHift = widthX;
                    break;
                }

            }
            if (!leftSHift.Equals(0))
                break;
        }

        // Top Shift
        for (int widthX = 0; widthX < bitmap.Height; widthX++)
        {
            for (int heightY = 0; heightY < bitmap.Width - 1; heightY++)
            {
                Color c = bitmap.GetPixel(heightY, widthX);
                if (!c.Name.Equals("0"))
                {
                    topShift = widthX;
                    break;
                }
            }
            if (!topShift.Equals(0))
                break;
        }

        // Right Shift
        for (int heightX = bitmap.Width - 1; heightX >= 0; heightX--)
        {
            for (int widthY = 0; widthY < bitmap.Height; widthY++)
            {
                Color c = bitmap.GetPixel(heightX, widthY);
                if (!c.Name.Equals("0"))
                {
                    rightShift = heightX;
                    break;
                }
            }
            if (!rightShift.Equals(0))
                break;
        }

        //Bottom Shift.
        for (int heightX = bitmap.Height - 1; heightX >= 0; heightX--)
        {
            for (int widthY = 0; widthY < bitmap.Width - 1; widthY++)
            {
                Color c = bitmap.GetPixel(widthY, heightX);
                if (!c.Name.Equals("0"))
                {
                    bottomShift = heightX;
                    break;
                }
            }
            if (!bottomShift.Equals(0))
                break;
        }

        Rectangle cropRect = new Rectangle
            (
            leftSHift + 1,
            topShift,
            bitmap.Width - (leftSHift + (bitmap.Width - rightShift)),
            bitmap.Height - (topShift + (bitmap.Height - bottomShift))
            );

        Bitmap src = bitmap;
        Bitmap target = new Bitmap(cropRect.Width, cropRect.Height);

        using (Graphics g = Graphics.FromImage(target))
        {
            g.DrawImage(src, new Rectangle(0, 0, target.Width, target.Height), cropRect, GraphicsUnit.Pixel);

        }

        return target;
    }


来源:https://stackoverflow.com/questions/16775436/c-sharp-remove-bitmap-padding

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!