修剪位图会导致底部文本被剪切

Posted

技术标签:

【中文标题】修剪位图会导致底部文本被剪切【英文标题】:Trimming Bitmap Causes Cutting of Text at Bottom 【发布时间】:2017-09-09 02:36:18 【问题描述】:

我正在使用以下代码来删除图像周围的空白。

  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;
        

我正在尝试修剪一个带有文本绘制的位图。修剪后正确的图像应该是这样的

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

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

【问题讨论】:

你展示的图片让我很困惑。任何 alpha == 0 在哪里?结果是哪一部分?只是红色盒子里面的部分??您假设 a==0 或 == 255 可能是错误的边界清晰,并且您有半透明像素..很难从图像中分辨出来。也许阈值比测试 0 更有效。 @TaW 我已经绘制了红色框以显示底部文本的剪切.. 例如比较第一张和第二张图片中的s。另外我正在绘制这个文本一个单独的图像(new Bitmap(somewidth,someheight))并在另一个图像上绘制文本位图。 @TaW hmm.. 好的.. 你能更新代码并为我回答吗? 试试这个:srcRect = Rectangle.FromLTRB(xMin, yMin, xMax-xMin , yMax-yMin); @TaW 此更新导致图像的一半被切割.. 要清楚.. 上面的代码用于修剪图像周围的白色部分/空白区域(左、右、顶部和底部).. 【参考方案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);

..导致RectangleHeight=10 即使0..10 应该覆盖11 像素行!所以Right-Bottom 坐标实际上从结果中排除!!

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

【讨论】:

以上是关于修剪位图会导致底部文本被剪切的主要内容,如果未能解决你的问题,请参考以下文章

剪切路径文本底部上的悬停动画“向下滑动”不起作用。你能帮助我吗?

html文本溢出

adjustsFontSizeToFitWidth 时 UILabel 的裁剪

网页颤动:底部的文字被切断

文本溢出显示省略号

Camtasia如何剪辑视频,剪切视频的片段