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
函数。
假设我们有这张 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
函数。