C# - Remove Bitmap padding

前端 未结 3 1849
花落未央
花落未央 2021-01-15 23:13

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

相关标签:
3条回答
  • 2021-01-15 23:52

    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);
    }
    
    0 讨论(0)
  • 2021-01-15 23:53

    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;
        }
    
    0 讨论(0)
  • 2021-01-16 00:04

    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);
        }
    }
    
    0 讨论(0)
提交回复
热议问题