c#从图像中剪切透明部分

c# Cut transparent parts from image

假设我们有这张 32bppRGBA 图像

如您所见,它是一张 1920x1080 的图像,只有一个小的红色矩形,我只想剪切该图像的非透明像素(在我们的例子中,只有小块)。

所以我开始扫描这张图片并获取非传输块边界。 这是我到目前为止所做的:

 private unsafe Bitmap CodeImage(Bitmap bmp)
    {
        Bitmap bmpRes = new Bitmap(bmp.Width, bmp.Height);

        BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);

        IntPtr scan0 = bmData.Scan0;
        int stride = bmData.Stride;
        int nWidth = bmp.Width;
        int nHeight = bmp.Height;
        int minX = 10000 ;
        int maxX = -10000;
        int minY = 10000;
        var maxY = -10000;

        for (int y = 0; y < nHeight; y++)
        {
            byte* p = (byte*)scan0.ToPointer();
            p += y * stride;

            for (int x = 0; x < nWidth; x++)
            {
                if (p[3]!=0)  //Check if pixel is not transpert;
                {
                  if (x < minX)
                      minX = x;
                  if (y < minY)
                      minY = y;
                   if (x > maxX)
                      maxX = x;
                  if (y > maxY)
                      maxY = y;
                }
                p += 4;
            }
        }

        bmp.UnlockBits(bmData);
        Rectangle temp = new Rectangle(minX, minY,maxX, maxY);

      //  MessageBox.Show(minX.ToString() + "," + minY.ToString() + "," + maxX.ToString() + "," + maxY.ToString());
        return bmp.Clone(temp,bmp.PixelFormat);
    }

但是我得到了奇怪的结果......我认为这是一个我无法弄清楚的简单错字......或者代码的逻辑可能有问题......

我将不胜感激并提供帮助!

我刚刚在他的另一个 post 上回答了这个问题:

    public static Bitmap Trim(string fileName)
    {
        Bitmap bmp = null;

        try
        {
            bmp = Bitmap.FromFile(fileName) as Bitmap;

            if (bmp == null)
                throw new ArgumentException("The file is not a valid image.");

            if (bmp.PixelFormat != PixelFormat.Format32bppArgb)
                throw new ArgumentException("The image file is in an invalid format (32bpp ARGB required)");

        }
        catch (Exception ex)
        {
            throw new ArgumentException("The file is not a valid image.", ex);
        }

        BitmapData bmpData = null;

        int minX, minY, maxX, maxY;
        minX = minY = int.MaxValue;
        maxX = maxY = int.MinValue;

        try
        {
            bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);

            IntPtr ptr = bmpData.Scan0;

            int bytes = bmpData.Stride * bmp.Height;
            int[] pixelData = new int[bmp.Width * bmp.Height];

            System.Runtime.InteropServices.Marshal.Copy(ptr, pixelData, 0, pixelData.Length);

            for (int y = 0; y < bmp.Height; y++)
            {
                for (int x = 0; x < bmp.Width; x++)
                {
                    Color pixel = Color.FromArgb(pixelData[x + (bmp.Width * y)]);

                    if (pixel.A != 0)
                    {
                        if (x < minX) minX = x;
                        if (x > maxX) maxX = x;
                        if (y < minY) minY = y;
                        if (y > maxY) maxY = y;
                    }
                }
            }

            pixelData = null;

            Rectangle cutRect = new Rectangle(minX, minY, maxX - minX, maxY - minY);

            bmp.UnlockBits(bmpData);

            return bmp.Clone(cutRect, bmp.PixelFormat);

        }
        finally
        {
        }
    }

我觉得最大的问题是矩形的计算不正确。您有一个最小值 x/y 和一个最大值 x/y,并且您将其用作 x、y、宽度、高度。您需要从最小值减去最大值 x/y 来计算 width/height。

另一个问题是像素格式是 32BPP ARGB,而不是 RGBA,所以 alpha 通道排在第一位,而不是索引 3。最好的办法是从整数创建 Color 结构值并检查它,但上面的算法仅适用于 32bpp ARGB 值,因为颜色只有 FromARGB 函数。