50% OFF!!!

Monday, October 4, 2010

Trim Image white-spaces (black&white) | C# Winforms

I searched for a simple code that preform "TRIMMING" to an image.
By "trimming" i mean, that if i have a LARGE image that contains information (painting/drawing...) only in small part of the image and all other is white-space (WHITE or BLACK pixels).

I needed to remove such whitespace and also to decrease image size.
Following three code examples:

Code #1 - Gets the NON-WHITE-SPACE bounds of an image
private Rectangle GetImageNonWhiteSpaceBounds(Bitmap p_img, bool p_isBlackWhitespace)
{
    Rectangle rect = new Rectangle();
    unsafe
    {
        BitmapData bdActual = null;
        try
        {
            int width = p_img.Width;
            int height = p_img.Height;

            bdActual = p_img.LockBits(new Rectangle(0, 0, width, height), System.Drawing.Imaging.ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            Int32 i;
            Int32 pSize = 3;
            Byte whiteTrashold = (Byte)240;
            Byte blackTrashold = (Byte)10;
            Byte* sourceRow;

            Int32 minX = width;
            Int32 maxX = 0;
            Int32 minY = height;
            Int32 maxY = 0;
            bool isWhitepace;

            for (Int32 _y = 0; _y < height; ++_y)             {                 sourceRow = (Byte*)bdActual.Scan0 + (_y * bdActual.Stride);                 for (Int32 _x = 0; _x < width; ++_x)                 {                     i = _x * pSize;                     isWhitepace =                         (p_isBlackWhitespace && sourceRow[i] <= blackTrashold && sourceRow[i + 1] <= blackTrashold && sourceRow[i + 2] <= blackTrashold)                         ||                         (!p_isBlackWhitespace && sourceRow[i] >= whiteTrashold && sourceRow[i + 1] >= whiteTrashold && sourceRow[i + 2] >= whiteTrashold);

                    if (isWhitepace == false)
                    {
                        // NO whitespace!!!
                        minX = Math.Min(_x, minX);
                        maxX = Math.Max(_x, maxX);

                        minY = Math.Min(_y, minY);
                        maxY = Math.Max(_y, maxY);
                    }
                }
            }

            rect.X = minX;
            rect.Y = minY;
            rect.Width = maxX - minX;
            rect.Height = maxY - minY;
        }
        finally
        {
            if (bdActual != null)
            {
                p_img.UnlockBits(bdActual);
            }
        }
    }
    return rect;
}

Code #2 - Draw rectangle around the NON-WHITE-SPACE
private void DrawNonWhiteSpaceRectangle(Bitmap p_img, bool p_isBlackWhitespace, Color p_color)
{
    unsafe
    {
        BitmapData bdActual = null;
        try
        {
            int width = p_img.Width;
            int height = p_img.Height;

            bdActual = p_img.LockBits(new Rectangle(0, 0, width, height), System.Drawing.Imaging.ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            Int32 i;
            Int32 pSize = 3;
            Byte whiteTrashold = (Byte)240;
            Byte blackTrashold = (Byte)10;
            Byte* sourceRow;

            Int32 minX = width;
            Int32 maxX = 0;
            Int32 minY = height;
            Int32 maxY = 0;
            bool isWhitepace;

            for (Int32 _y = 0; _y < height; ++_y)             {                 sourceRow = (Byte*)bdActual.Scan0 + (_y * bdActual.Stride);                 for (Int32 _x = 0; _x < width; ++_x)                 {                     i = _x * pSize;                     isWhitepace =                         (p_isBlackWhitespace && sourceRow[i] <= blackTrashold && sourceRow[i + 1] <= blackTrashold && sourceRow[i + 2] <= blackTrashold)                         ||                         (!p_isBlackWhitespace && sourceRow[i] >= whiteTrashold && sourceRow[i + 1] >= whiteTrashold && sourceRow[i + 2] >= whiteTrashold);

                    if (isWhitepace == false)
                    {
                        // NO whitespace!!!
                        minX = Math.Min(_x, minX);
                        maxX = Math.Max(_x, maxX);

                        minY = Math.Min(_y, minY);
                        maxY = Math.Max(_y, maxY);
                    }
                }
            }

            // draw rectagle:
            for (Int32 _y = minY; _y <= maxY; ++_y)             {                 sourceRow = (Byte*)bdActual.Scan0 + (_y * bdActual.Stride);                 i = minX * pSize;                 sourceRow[i] = (Byte)p_color.R;                 sourceRow[i + 1] = (Byte)p_color.G;                 sourceRow[i + 2] = (Byte)p_color.B;                 i = maxX * pSize;                 sourceRow[i] = (Byte)p_color.R;                 sourceRow[i + 1] = (Byte)p_color.G;                 sourceRow[i + 2] = (Byte)p_color.B;             }             Byte* sourceRowX1 = (Byte*)bdActual.Scan0 + (minY * bdActual.Stride);             Byte* sourceRowX2 = (Byte*)bdActual.Scan0 + (maxY * bdActual.Stride);             for (Int32 _x = minX; _x <= maxX; ++_x)             {                 i = _x * pSize;                 sourceRowX1[i] = (Byte)p_color.R;                 sourceRowX1[i + 1] = (Byte)p_color.G;                 sourceRowX1[i + 2] = (Byte)p_color.B;                 sourceRowX2[i] = (Byte)p_color.R;                 sourceRowX2[i + 1] = (Byte)p_color.G;                 sourceRowX2[i + 2] = (Byte)p_color.B;             }         }         finally         {             if (bdActual != null)             {                 p_img.UnlockBits(bdActual);             }         }     } }


Code #3 - Trim Image whitespaces
private Bitmap CropImageWhitespaces(Bitmap p_img, bool p_isBlackWhitespace)
{
    Rectangle rect = new Rectangle();
    unsafe
    {
        BitmapData bdActual = null;
        try
        {
            int width = p_img.Width;
            int height = p_img.Height;

            bdActual = p_img.LockBits(new Rectangle(0, 0, width, height), System.Drawing.Imaging.ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            Int32 i;
            Int32 pSize = 3;
            Byte whiteTrashold = (Byte)240;
            Byte blackTrashold = (Byte)10;
            Byte* sourceRow;

            Int32 minX = width;
            Int32 maxX = 0;
            Int32 minY = height;
            Int32 maxY = 0;
            bool isWhitepace;

            for (Int32 _y = 0; _y < height; ++_y)             {                 sourceRow = (Byte*)bdActual.Scan0 + (_y * bdActual.Stride);                 for (Int32 _x = 0; _x < width; ++_x)                 {                     i = _x * pSize;                     isWhitepace =                         (p_isBlackWhitespace && sourceRow[i] <= blackTrashold && sourceRow[i + 1] <= blackTrashold && sourceRow[i + 2] <= blackTrashold)                         ||                         (!p_isBlackWhitespace && sourceRow[i] >= whiteTrashold && sourceRow[i + 1] >= whiteTrashold && sourceRow[i + 2] >= whiteTrashold);

                    if (isWhitepace == false)
                    {
                        // NO whitespace!!!
                        minX = Math.Min(_x, minX);
                        maxX = Math.Max(_x, maxX);

                        minY = Math.Min(_y, minY);
                        maxY = Math.Max(_y, maxY);
                    }
                }
            }

            rect.X = minX;
            rect.Y = minY;
            rect.Width = maxX - minX;
            rect.Height = maxY - minY;
        }
        finally
        {
            if (bdActual != null)
            {
                p_img.UnlockBits(bdActual);
            }
        }
    }

    return p_img.Clone(rect, p_img.PixelFormat);
}

I hope it will be helpful for you.
this code if fast and easy to use.

No comments:

Post a Comment