当使用来自intptr的可写位图来创建位图时使用WritePixels
本文关键字:位图 创建 WritePixels intptr | 更新日期: 2023-09-27 17:50:35
我目前试图使用writeablebitmap来拍摄图像扫描的IntPtr
,并将每个图像转换为Bitmap
。我想使用writeablebitmap,因为我有一个问题与标准gdiGDI+ System.Drawing.Bitmap给出错误参数间歇性无效
在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;
在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.Stride
和newImageData.Width * 4
总是相同的。我在循环中使用偏移量只是为了显示必要的地方。
但是如果你使用另一种格式,例如Format24bppRgb
,它每像素使用3个字节(R, G和B),那么stride和width之间可能会有偏移。对于这种格式的10 * 10像素的图像,您将使用10 * 3 = 30,+ 2来达到最接近4的倍数,即32。