3

この安全でないコードをリファクタリングして、 MSDNSystem.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 );
}

編集

私はこれまでにこれを思いついたが、@BenVoigtウォークを介して作業する試みで。残念ながら、次のエラーが発生します。

保護されたメモリの読み取りまたは書き込みを試みました。これは多くの場合、他のメモリが破損していることを示しています。

    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);
    }

誰かが私が間違ったことを見ることができますか?正直なところ、これは私の頭の中に少しあります。私は本を​​何冊か買うべきだと思います。

4

3 に答える 3

3
  1. LockBits起源。
  2. Marshal.CopyソースBitmapDatabyte[]バッファに。
  3. UnlockBits起源。
  4. LockBits目的地。
  5. Marshal.CopyバッファBitmapDataへの宛先。byte[]
  6. そのチャネルをループしてソースbyte[]から宛先にコピーしますbyte[](ポインターではなくインデックスで算術演算を使用することに注意してください)
  7. Marshal.Copybyte[]に戻る宛先BitmapData
  8. UnlockBits目的地。

でも、要点はわかりません。を使用Marshal.Copyするコードは、キーワードを使用するコードと同じくらい危険でunsafeあり、同様のコードセキュリティ権限が必要です。

潜在的により効率的な方法はImageAttributes.SetColorMatrix、宛先画像から目的のチャンネルを削除し、ソース画像から他のすべてのチャンネルを削除してからブレンドすることです。の例を参照してくださいColorMatrix

または、DirectX(またはOpenGL)と1つのチャネルを転送するだけのシェーダーを使用します。

于 2012-06-07T15:15:28.927 に答える
0

残念ながら、2つの別々の画像のチャンネルを結合する場合、ColorMatrixは機能しません。加算(またはビット単位または)のブレンド方法が必要になります。GDI+によって提供されるブレンドは、オーバーとコピーのみです。また、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));
于 2012-06-08T00:03:00.947 に答える
0

NugetまたはCodeplexの単純なLINQベースの画像処理フレームワークを使用して、チャネルを入れ替える単純なクエリを作成できます。

このコードのように、ColorMatrixを使用してチャネルスワップを実行することもできます。

于 2012-06-07T15:34:20.163 に答える