2015-08-15 62 views
1

我試圖做一種Grahpics.DrawImage實現使用不安全的代碼和指針當然。C#繪製圖像的實現

在這種情況下,即時通訊試圖繪製一個更大的寬度(都32bppArgb)的小位圖。

這是我的代碼

private static unsafe void Draw(Bitmap bmp, Bitmap bmp2, int xPoint, int yPoint) 
    { 

     BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, bmp.PixelFormat); 
     BitmapData bmData2 = bmp2.LockBits(new Rectangle(0, 0, bmp2.Width, bmp2.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp2.PixelFormat); 

     IntPtr scan0 = bmData.Scan0; 
     IntPtr scan02 = bmData2.Scan0; 

     int stride = bmData.Stride; 
     int stride2 = bmData2.Stride; 

     int nWidth = bmp2.Width; 
     int nHeight = bmp2.Height; 

     int sourceX = 0; 
     int sourceY = 0; 
     byte* p = (byte*)scan0.ToPointer(); 
     p += yPoint * stride + xPoint * 4; 
     byte* p2 = (byte*)scan02.ToPointer(); 
     p2 += sourceY * stride2 + sourceX * 4; 
     int bytes = nWidth * 4; 

     for (int y = 0; y < nHeight; y++) 
     { 

      for (int x = 0; x <nWidth; x++) 
      { 


       p[0] = p2[0]; 
       p[1] = p2[1]; 
       p[2] = p2[2]; 
       p[3] = p2[3]; 

      } 

      p += 4; 
      p2 += 4; 
     } 

     bmp.UnlockBits(bmData); 
     bmp2.UnlockBits(bmData2); 
    } 

這是更新的代碼

+0

你把它拷貝到自身。對於'b2',你應該使用'scan02'而不是'scan0'。您還應該爲'b2'使用'stride2'。然後你應該使用'stride'和'stride2'將'b'和'b2'移到下一行,而不是假設下一行在當前之後立即開始。線條之間可以填充,當圖像在內存中倒置時,步幅甚至可以爲負值。 – Guffa

+0

@Guffa ohh ..沒有看到它......謝謝你! – Slashy

+0

@Guffa等待..現在我在這裏得到一個異常'p [0] = p2 [0]; **試圖讀取或寫入受保護的內存** – Slashy

回答

2

我做了一些改動,使其工作:

  • 使用ImageLockMode.WriteOnlyLockBits呼籲像你想寫信給。
  • 請勿移動p2根據xPointyPoint

我看到你在外循環內設置了指針,所以你不需要在循環結尾移動指針。我建議你在外層循環之外計算起點,並將指針移動到其中。

我還建議這些變化,我做到了:

  • 添加檢查圖像的界限,讓你不小心嘗試將圖像之外繪製。

  • 使方法void。返回一個位圖表明它創建一個新的位圖,而不是改變傳入它的一個位圖。

我添加了一個pixelBytes參數,以使它適用於不同的像素格式。 (主要是因爲我有發生的JPEG,PNG圖像不與測試。)

代碼:

private static unsafe void Draw(Bitmap bmp, Bitmap bmp2, int xPoint, int yPoint, int pixelBytes) { 

    BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, bmp.PixelFormat); 
    BitmapData bmData2 = bmp2.LockBits(new Rectangle(0, 0, bmp2.Width, bmp2.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp2.PixelFormat); 

    IntPtr scan0 = bmData.Scan0; 
    IntPtr scan02 = bmData2.Scan0; 

    int stride = bmData.Stride; 
    int stride2 = bmData2.Stride; 

    int nWidth = bmp2.Width; 
    int nHeight = bmp2.Height; 

    int sourceX = 0; 
    int sourceY = 0; 

    if (xPoint < 0) { 
    sourceX = -xPoint; 
    nWidth -= sourceX; 
    xPoint = 0; 
    } 
    if (yPoint < 0) { 
    sourceY = -yPoint; 
    nHeight -= sourceY; 
    yPoint = 0; 
    } 
    if (xPoint + nWidth > bmp.Width) { 
    nWidth = bmp.Width - xPoint; 
    } 
    if (yPoint + nHeight > bmp.Height) { 
    nHeight = bmp.Height - yPoint; 
    } 

    if (nWidth > 0 && nHeight > 0) { 

    byte* p = (byte*)scan0.ToPointer(); 
    p += yPoint * stride + xPoint * pixelBytes; 
    byte* p2 = (byte*)scan02.ToPointer(); 
    p2 += sourceY * stride2 + sourceX * pixelBytes; 

    int bytes = nWidth * pixelBytes; 

    for (int y = 0; y < nHeight; y++) { 
     for (int x = 0; x < bytes; x++) { 
     p[0] = p2[0]; 
     p++; 
     p2++; 
     } 
     p += stride - nWidth * pixelBytes; 
     p2 += stride2 - nWidth * pixelBytes; 
    } 

    } 

    bmp.UnlockBits(bmData); 
    bmp2.UnlockBits(bmData2); 
} 
+0

謝謝你,真棒!你的代碼是直截了當的!+1 – Slashy

+0

最後一件事就是確定了這種方法的解析時間,它比我的速度慢(我知道它沒有工作,但仍然)。我認爲主要的瓶頸是內部循環運行'字節'時間...它可以運行得更快嗎?你能更新我的代碼中的某些東西嗎?巨大的巨大感謝兄弟!你的回答很棒,但是有點慢......先謝謝了! – Slashy

+0

@Slashy:如果您刪除'pixelBytes'參數並將其設爲循環像素而不是字節,則應該返回該性能。 – Guffa