Search code examples
c#imagepixellockbits

Cropping white space from image right side in C#


I have some images, which contains a lot of white space at the bottom and the right side. I want to crop that white space before displaying to the user.

So far I've implemented non-white pixels detecting from the bottom. Pixel format is Format32BppArgb.

        byte[] byteImage = Convert.FromBase64String(imageString);

        MemoryStream ms = new MemoryStream(byteImage, 0, byteImage.Length);
        ms.Write(byteImage, 0, byteImage.Length);
        Image image = Image.FromStream(ms, true);
        Bitmap bmpImage = new Bitmap(image);
        int imageDataHeight = bmpImage.Height;
        int imageWidth = bmpImage.Width;
        int imageHeight = bmpImage.Height;

        BitmapData data = bmpImage.LockBits(new Rectangle(0, 0, imageWidth, imageHeight), ImageLockMode.ReadOnly, bmpImage.PixelFormat);
        try
        {
            unsafe
            {
                int width = data.Width / 2;
                for (int y = data.Height-1; y > 0 ; y--)
                {
                    byte* row = (byte*)data.Scan0 + (y * data.Stride);

                    int blue = row[width * 3];
                    int green = row[width * 2];
                    int red = row[width * 1];

                    if ((blue != 255) || (green != 255) || (red != 255))
                    {
                        imageDataHeight = y + 50;
                        break;
                    }
                }
            }
        }
        finally
        {
            bmpImage.UnlockBits(data);
        }

        // cropping a rectangle based on imageDataHeight
        // ...

How properly iterate through columns starting from right side to left and detect non-white pixels?


Solution

  • This will give you the target width:

        unsafe int CropRight(BitmapData data)
        {
            int targetWidth = data.Width;
            for (int x = data.Width - 1; x >= 0; x--)
            {
                bool isWhiteStripe = true;
                for (int y = data.Height - 1; y > 0; y--)
                {
                    if (!IsWhite(data, x, y))
                    {
                        isWhiteStripe = false;
                        break;
                    }
                }
    
                if (!isWhiteStripe)
                    break;
                targetWidth = x;
            }
            return targetWidth;
        }
    
        int bytesPerPixel = 4; //32BppArgb = 4bytes oer pixel
        int redOffset = 1; // 32BppArgb -> red color is the byte at index 1, alpha is at index 0
    
        unsafe bool IsWhite(BitmapData data, int x, int y)
        {
            byte* row = (byte*)data.Scan0 + (y * data.Stride) + (x * bytesPerPixel);
    
            int blue = row[redOffset + 2];
            int green = row[redOffset + 1];
            int red = row[redOffset];
    
            // is not white?
            if ((blue != 255) || (green != 255) || (red != 255))
            {
                return false;
            }
    
            return true;
        }
    

    Then, you can crop the image: How to crop an image using C#?