gpt4 book ai didi

c# - 如何将位图像素复制到其他位图,在 C# 中保留 alpha 透明度?

转载 作者:太空狗 更新时间:2023-10-30 00:43:55 24 4
gpt4 key购买 nike

有人可以重写以下函数以使用任何优化机制吗?我很确定这不是继续逐像素复制的方式。

我读过 AlphaBlend , 或 BitBlt ,但我不习惯本地代码。

public static Bitmap GetAlphaBitmap(Bitmap srcBitmap)
{
Bitmap result = new Bitmap(srcBitmap.Width, srcBitmap.Height, PixelFormat.Format32bppArgb);

Rectangle bmpBounds = new Rectangle(0, 0, srcBitmap.Width, srcBitmap.Height);

BitmapData srcData = srcBitmap.LockBits(bmpBounds, ImageLockMode.ReadOnly, srcBitmap.PixelFormat);

try
{
for (int y = 0; y <= srcData.Height - 1; y++)
{
for (int x = 0; x <= srcData.Width - 1; x++)
{
Color pixelColor = Color.FromArgb(
Marshal.ReadInt32(srcData.Scan0, (srcData.Stride * y) + (4 * x)));

result.SetPixel(x, y, pixelColor);
}
}
}
finally
{
srcBitmap.UnlockBits(srcData);
}

return result;
}

重要提示:源图像的像素格式 (Format32bppRgb) 错误,因此我需要调整 alpha channel 。这是唯一适合我的机制。

src图片像素格式错误的原因解释here .

我尝试了以下选项但没有成功:

  • 创建一个新图像并使用 src 中的 Graphics.DrawImage 绘制 src 图像。没有保留 alpha。
  • 使用 Scan0 表单 src 创建新图像。工作正常,但当 GC 处理 src 图像时出现问题(在另一个 post 中解释);

此解决方案是唯一真正有效的解决方案,但我知道这不是最佳解决方案。我需要知道如何使用 WinAPI 或其他优化机制来做到这一点。

非常感谢!

最佳答案

假设源图像确实每个像素有 32 位,这应该是使用不安全代码和指针的足够快的实现。使用编码也可以实现同样的效果,但如果我没记错的话,性能损失大约为 10%-20%。

使用 native 方法很可能会更快,但这应该比 SetPixel 快几个数量级。

public unsafe static Bitmap Clone32BPPBitmap(Bitmap srcBitmap)
{
Bitmap result = new Bitmap(srcBitmap.Width, srcBitmap.Height, PixelFormat.Format32bppArgb);

Rectangle bmpBounds = new Rectangle(0, 0, srcBitmap.Width, srcBitmap.Height);
BitmapData srcData = srcBitmap.LockBits(bmpBounds, ImageLockMode.ReadOnly, srcBitmap.PixelFormat);
BitmapData resData = result.LockBits(bmpBounds, ImageLockMode.WriteOnly, result.PixelFormat);

int* srcScan0 = (int*)srcData.Scan0;
int* resScan0 = (int*)resData.Scan0;
int numPixels = srcData.Stride / 4 * srcData.Height;
try
{
for (int p = 0; p < numPixels; p++)
{
resScan0[p] = srcScan0[p];
}
}
finally
{
srcBitmap.UnlockBits(srcData);
result.UnlockBits(resData);
}

return result;
}

这是使用编码的此方法的安全版本:

public static Bitmap Copy32BPPBitmapSafe(Bitmap srcBitmap)
{
Bitmap result = new Bitmap(srcBitmap.Width, srcBitmap.Height, PixelFormat.Format32bppArgb);

Rectangle bmpBounds = new Rectangle(0, 0, srcBitmap.Width, srcBitmap.Height);
BitmapData srcData = srcBitmap.LockBits(bmpBounds, ImageLockMode.ReadOnly, srcBitmap.PixelFormat);
BitmapData resData = result.LockBits(bmpBounds, ImageLockMode.WriteOnly, result.PixelFormat);

Int64 srcScan0 = srcData.Scan0.ToInt64();
Int64 resScan0 = resData.Scan0.ToInt64();
int srcStride = srcData.Stride;
int resStride = resData.Stride;
int rowLength = Math.Abs(srcData.Stride);
try
{
byte[] buffer = new byte[rowLength];
for (int y = 0; y < srcData.Height; y++)
{
Marshal.Copy(new IntPtr(srcScan0 + y * srcStride), buffer, 0, rowLength);
Marshal.Copy(buffer, 0, new IntPtr(resScan0 + y * resStride), rowLength);
}
}
finally
{
srcBitmap.UnlockBits(srcData);
result.UnlockBits(resData);
}

return result;
}

编辑:您的源图像有负步幅,这意味着扫描线在内存中倒置存储(仅在 y 轴上,行仍然从左到右)。这实际上意味着 .Scan0 返回位图最后一行的第一个像素。

因此我修改了代码以一次复制一行。

注意:我只修改了安全密码。不安全的代码仍然假设两个图像都取得了积极的进展!

关于c# - 如何将位图像素复制到其他位图,在 C# 中保留 alpha 透明度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9319199/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com