c#-使用安全代码将频道从一个图像复制到另一个
作者:互联网
我试图使用System.Runtime.InteropServices.Marshal.Copy重构此不安全的代码,以将单个ARGB通道从一个图像复制到另一个图像,如本例中MSDN所示,但我完全迷失了.
谁能指导我完成我的工作?
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 walk,尽管到目前为止我已经提出了这个建议.不幸的是,我现在收到以下错误:
Attempted to read or write protected memory. This is often an
indication that other memory is corrupt.
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);
}
谁能看到我做错了吗?老实说,这有点让我烦恼.我想我应该买一些书.
解决方法:
> LockBits源.
>元帅.将源BitmapData复制到byte []缓冲区.
>解锁源.
> LockBits目的地.
>元帅.将目标BitmapData复制到byte []缓冲区.
>遍历并将该通道从源字节[]复制到目标字节[](请注意,对索引而不是对指针使用算术运算)
>元帅.将目标字节[]复制回BitmapData.
>解锁目标.
不过,我不确定这是什么意思.使用Marshal.Copy的代码与使用unsafe关键字的代码一样危险,并且应该需要类似的代码安全权限.
可能更有效的方法是使用ImageAttributes.SetColorMatrix从目标图像中删除所需的通道,从源图像中删除所有其他通道,然后进行融合.参见示例ColorMatrix
或者使用DirectX(或OpenGL)和仅传输一个通道的着色器.