2011-04-20 14 views
1

我目前正試圖使用​​writeablebitmap來掃描圖像的IntPtr,並將每個圖像變成Bitmap。林想使用WriteableBitmap的,因爲有標準的GDI GDI+ System.Drawing.Bitmap gives error Parameter is not valid intermittently使用來自intptr的可寫位圖創建位圖時使用WritePixels。

問題IM上有一個WriteableBitmap的方法調用WritePixels http://msdn.microsoft.com/en-us/library/aa346817.aspx

林不知道我的緩衝區和步幅每一個例子,我設置發現它顯示的步幅爲0,儘管這會引發錯誤。當我將步幅設置爲5時,圖像顯示爲黑色。我知道這可能不是最有效的代碼,但任何幫助將不勝感激。

//create bitmap header 
bmi = new BITMAPINFOHEADER(); 

//create initial rectangle 
Int32Rect rect = new Int32Rect(0, 0, 0, 0); 

//create duplicate intptr to use while in global lock 
dibhand = dibhandp; 
bmpptr = GlobalLock(dibhand); 

//get the pixel sizes 
pixptr = GetPixelInfo(bmpptr); 

//create writeable bitmap 
var wbitm = new WriteableBitmap(bmprect.Width, bmprect.Height, 96.0, 96.0, System.Windows.Media.PixelFormats.Bgr32, null); 

//draw the image 
wbitm.WritePixels(rect, dibhandp, 10, 0); 

//convert the writeable bitmap to bitmap 
var stream = new MemoryStream(); 

var encoder = new JpegBitmapEncoder(); 
encoder.Frames.Add(BitmapFrame.Create(wbitm)); 
encoder.Save(stream); 

byte[] buffer = stream.GetBuffer(); 
var bitmap = new System.Drawing.Bitmap(new MemoryStream(buffer)); 

GlobalUnlock(dibhand); 
GlobalFree(dibhand); 
GlobalFree(dibhandp); 
GlobalFree(bmpptr); 
dibhand = IntPtr.Zero; 

return bitmap; 

回答

2

的有效方式在C#中的位圖的工作是在不安全模式下暫時通過(我知道我完全不回答這個問題,但我覺得OP沒有設法使用位圖,所以這可能是無論如何,解決方案)。你只需要鎖定位,就大功告成了:

unsafe private void GaussianFilter() 
{ 
    // Working images 
    using (Bitmap newImage = new Bitmap(width, height)) 
    { 
     // Lock bits for performance reason 
     BitmapData newImageData = newImage.LockBits(new Rectangle(0, 0, newImage.Width, 
      newImage.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); 

     byte* pointer = (byte*)newImageData.Scan0; 
     int offset = newImageData.Stride - newImageData.Width * 4; 

     // Compute gaussian filter on temp image 
     for (int j = 0; j < InputData.Height - 1; ++j) 
     { 
      for (int 0 = 1; i < InputData.Width - 1; ++i) 
      { 
       // You browse 4 bytes per 4 bytes 
       // The 4 bytes are: B G R A 
       byte blue = pointer[0]; 
       byte green = pointer[1]; 
       byte red = pointer[2]; 
       byte alpha = pointer[3]; 

       // Your business here by setting pointer[i] = ... 
       // If you don't use alpha don't forget to set it to 255 else your whole image will be black !! 

       // Go to next pixels 
       pointer += 4; 
      } 
      // Go to next line: do not forget pixel at last and first column 
      pointer += offset; 
     } 


     // Unlock image 
     newImage.UnlockBits(newImageData); 
     newImage.Save("D:\temp\OCR_gray_gaussian.tif"); 
    } 
} 

這真的比SetPixel(i, j)更有效率,你就必須要小心指針限制(而不是忘記解鎖數據時,你就大功告成了) 。

現在回答您的問題有關的步幅:步幅是在一條線上的字節長度,它是4以我爲例我使用的格式Format32bppArgb其使用每像素4個字節(R,G,B的倍數和alpha),所以newImageData.StridenewImageData.Width * 4總是相同的。我只在我的循環中使用偏移量來顯示它在何處是必要的。

但是,如果您使用其他格式,例如Format24bppRgb,它使用每個像素3個字節(僅R,G和B),則可能存在步幅和寬度之間的偏移量。對於這種格式的10 * 10像素的圖像,您將有10 * 3 = 30的步幅,+ 2達到4的最接近倍數,即32.