我正在尝试重构这个不安全的代码,根据MSDN上的这个示例,使用System.Runtime.InteropServices.Marshal.Copy
将单个ARGB频道从一个图像复制到另一个图像,但我完全迷失了。
有没有人可以告诉我如何解决这个问题?
public enum ChannelARGB
{
Blue = 0,
Green = 1,
Red = 2,
Alpha = 3
}
public static void transferOneARGBChannelFromOneBitmapToAnother(
Bitmap source,
Bitmap dest,
ChannelARGB sourceChannel,
ChannelARGB destChannel )
{
if ( source.Size!=dest.Size )
throw new ArgumentException();
Rectangle r = new Rectangle( Point.Empty, source.Size );
BitmapData bdSrc = source.LockBits( r,
ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb );
BitmapData bdDst = dest.LockBits( r,
ImageLockMode.ReadWrite,
PixelFormat.Format32bppArgb );
unsafe
{
byte* bpSrc = (byte*)bdSrc.Scan0.ToPointer();
byte* bpDst = (byte*)bdDst.Scan0.ToPointer();
bpSrc += (int)sourceChannel;
bpDst += (int)destChannel;
for ( int i = r.Height * r.Width; i > 0; i-- )
{
*bpDst = *bpSrc;
bpSrc += 4;
bpDst += 4;
}
}
source.UnlockBits( bdSrc );
dest.UnlockBits( bdDst );
}
为了尝试通过@Ben Voigt,我到目前为止已经提出了这个问题。不幸的是,我现在收到以下错误:
尝试读取或写入受保护的内存。这通常是一个 表明其他内存已损坏。
private static void TransferOneArgbChannelFromOneBitmapToAnother(
Bitmap source,
Bitmap destination,
ChannelARGB sourceChannel,
ChannelARGB destinationChannel)
{
if (source.Size != destination.Size)
{
throw new ArgumentException();
}
Rectangle rectangle = new Rectangle(Point.Empty, source.Size);
// Lockbits the source.
BitmapData bitmapDataSource = source.LockBits(rectangle,
ImageLockMode.ReadWrite,
PixelFormat.Format32bppArgb);
// Declare an array to hold the bytes of the bitmap.
int bytes = bitmapDataSource.Stride * bitmapDataSource.Height;
// Allocate a buffer for the source image
byte[] sourceRgbValues = new byte[bytes];
// Get the address of the first line.
IntPtr ptrSource = bitmapDataSource.Scan0;
// Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(ptrSource,
sourceRgbValues,
0,
bytes);
// Unlockbits the source.
source.UnlockBits(bitmapDataSource);
// Lockbits the destination.
BitmapData bitmapDataDestination = destination.LockBits(rectangle,
ImageLockMode.ReadWrite,
PixelFormat.Format32bppArgb);
// Allocate a buffer for image
byte[] destinationRgbValues = new byte[bytes];
IntPtr ptrDestination = bitmapDataDestination.Scan0;
// Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(ptrDestination,
destinationRgbValues,
0,
bytes);
ptrSource += (int)sourceChannel;
ptrDestination += (int)destinationChannel;
for (int i = rectangle.Height * rectangle.Width; i > 0; i--)
{
destinationRgbValues[i] = sourceRgbValues[i];
ptrSource += 4;
ptrDestination += 4;
}
// Copy the RGB values back to the bitmap
// ******This is where I am getting the exception*******.
System.Runtime.InteropServices.Marshal.Copy(destinationRgbValues,
0,
ptrDestination,
bytes);
// Unlock bits the destination.
destination.UnlockBits(bitmapDataDestination);
}
谁能看到我做错了什么?老实说,这有点过头了。我想我应该买些书。
答案 0 :(得分:3)
LockBits
来源。Marshal.Copy
来源BitmapData
到byte[]
缓冲区。UnlockBits
来源。LockBits
目的地。Marshal.Copy
目的地BitmapData
到byte[]
缓冲区。byte[]
复制到目标byte[]
(注意,对索引而不是指针使用算术)Marshal.Copy
目的地byte[]
返回BitmapData
。UnlockBits
目的地。Marshal.Copy
的代码与使用unsafe
关键字的代码一样危险,并且应该要求类似的代码安全权限。
一种可能更有效的方法是使用ImageAttributes.SetColorMatrix
从目标图像中删除所需的频道,从源图像中删除所有其他频道,然后混合。请参阅ColorMatrix
或者使用DirectX(或OpenGL)和只传输一个通道的着色器。
答案 1 :(得分:0)
答案 2 :(得分:0)
不幸的是,如果要组合来自两个单独图像的通道,ColorMatrix将无法工作。您需要一种加法(或按位或)混合方法,GDI +提供的唯一混合是Over和Copy。它也让我觉得任何允许你直接访问位的方法,包括LockBits都被锁定。
我认为唯一的选择是在每个像素上使用GetPixel和SetPixel,如下所示:
Color dstColor = bpDst.GetPixel(x, y);
Color srcColor = bpSrc.GetPixel(x, y);
int srcValue = (srcColor.ToArgb() >> (sourceChannel * 8)) & 0xff;
int dstArgb = (dstColor.ToArgb() & ~(0xff << (destChannel * 8))) | (srcValue << (destChannel * 8));
bpDst.SetPixel(x, y, Color.FromArgb(dstArgb));