修剪位图导致底部文本切割

时间:2017-04-13 05:40:37

标签: c# .net bitmap gdi+ gdi

我使用以下代码删除图片周围的空白。

  static Bitmap TrimBitmap(Bitmap source)
        {
            Rectangle srcRect = default(Rectangle);
            BitmapData data = null;
            try
            {
                data = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
                byte[] buffer = new byte[data.Height * data.Stride];
                Marshal.Copy(data.Scan0, buffer, 0, buffer.Length);

                int xMin = int.MaxValue,
                    xMax = int.MinValue,
                    yMin = int.MaxValue,
                    yMax = int.MinValue;

                bool foundPixel = false;

                // Find xMin
                for (int x = 0; x < data.Width; x++)
                {
                    bool stop = false;
                    for (int y = 0; y < data.Height; y++)
                    {
                        byte alpha = buffer[y * data.Stride + 4 * x + 3];
                        if (alpha != 0)
                        {
                            xMin = x;
                            stop = true;
                            foundPixel = true;
                            break;
                        }
                    }
                    if (stop)
                        break;
                }

                // Image is empty...
                if (!foundPixel)
                    return null;

                // Find yMin
                for (int y = 0; y < data.Height; y++)
                {
                    bool stop = false;
                    for (int x = xMin; x < data.Width; x++)
                    {
                        byte alpha = buffer[y * data.Stride + 4 * x + 3];
                        if (alpha != 0)
                        {
                            yMin = y;
                            stop = true;
                            break;
                        }
                    }
                    if (stop)
                        break;
                }

                // Find xMax
                for (int x = data.Width - 1; x >= xMin; x--)
                {
                    bool stop = false;
                    for (int y = yMin; y < data.Height; y++)
                    {
                        byte alpha = buffer[y * data.Stride + 4 * x + 3];
                        if (alpha != 0)
                        {
                            xMax = x;
                            stop = true;
                            break;
                        }
                    }
                    if (stop)
                        break;
                }

                // Find yMax
                for (int y = data.Height - 1; y >= yMin; y--)
                {
                    bool stop = false;
                    for (int x = xMin; x <= xMax; x++)
                    {
                        byte alpha = buffer[y * data.Stride + 4 * x + 3];
                        if (alpha != 0)
                        {
                            yMax = y;
                            stop = true;
                            break;
                        }
                    }
                    if (stop)
                        break;
                }
                srcRect = Rectangle.FromLTRB(xMin, yMin, xMax , yMax);
            }
            finally
            {
                if (data != null)
                    source.UnlockBits(data);
            }

            Bitmap dest = new Bitmap(srcRect.Width, srcRect.Height);
            Rectangle destRect = new Rectangle(0, 0, srcRect.Width, srcRect.Height);
            using (Graphics graphics = Graphics.FromImage(dest))
            {
                graphics.DrawImage(source, destRect, srcRect, GraphicsUnit.Pixel);
            }
            return dest;
        }

我试图修剪一个带有文字的位图。修剪后,正确的图像应如下所示

enter image description here

但是在修剪之后我得到了以下结果..底部被剪掉了

我做错了什么?请指教..

enter image description here

1 个答案:

答案 0 :(得分:1)

这实际上是Rectangle.FromLTRB的问题!

仔细观察图像,您会发现实际上只丢失了一个像素行。 (强大的放大倍数让我被愚弄了一段时间..)

确定矩形的高度(和宽度)的算法基本上是正确的,但关闭一个

如果你使用这个

srcRect = Rectangle.FromLTRB(xMin, yMin, xMax + 1 , yMax + 1);

或者这个:

srcRect = new Rectangle(xMin, yMin, xMax - xMin + 1 , yMax - yMin + 1);

它应该有用。

你可以用笔和纸测试:说:第一个像素行的颜色= 4,首先是从10个像素的正方形底部:8,这使得5个不是4个净数据:4,5,6,7,8

请注意,FromLTRB

中存在此问题
Rectangle myRectangle = Rectangle.FromLTRB(0, 0, 10, 10);

..即使Rectangle覆盖Height=10像素行,0..10也会产生11!因此Right-Bottom坐标实际上是排除的结果!!

我认为矩形偏离的整个问题源于legacy ways to use a Pen with its alignment。当使用相同的矩形填充Brush时,所有工作都按预期工作。