I need help with HikVision IPCam Video streaming. I searched for 2 hole weeks without luck.
My problem is the IPCamm DLL stream the image into a picturebox using PictureBox.Handle. Its working perfectly fine:
[DllImport("HCNetSDK.dll")]
public static extern int NET_DVR_RealPlay_V30(int lUserID, ref NET_DVR_CLIENTINFO lpClientInfo, RealDataCallBack_V30 fRealDataCallBack_V30, IntPtr pUser, bool bBlocked);
this.realDataCallBack = new RealDataCallBack_V30(RealDataCallback);
this.clientInfo.hPlayWnd = PictureBox.Handle;
this.clientInfo.lChannel = channel;
this.clientInfo.lLinkMode = 0;
this.playHandle = NET_DVR_RealPlay_V30(this.userID, ref this.clientInfo, realDataCallBack, IntPtr.Zero, true);
My Issue is that I need to process the image but I couldn't have any way to capture the image as Bitmap or Image and then display it As I like.
I tried Bitmap.FromHbitmap(PictureBox.Handle), Tried some MemoryMarshel solutions with no luck.
My Only way to get it now is by getting the data from call back functions which is with lower quality, lower frame-count, ...
This snippet draws the data from the handle into a bitmap and then sets the image of the picturebox. The CopyFromScreen line might not be necessary on older systems.
PictureBox.Image = CaptureControl(PictureBox.Handle, PictureBox.Width, PictureBox.Height);
// PictureBox.Image now contains the data that was drawn to it
[DllImport("gdi32.dll")]
private static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop);
public Bitmap CaptureControl(IntPtr handle, int width, int height)
{
Bitmap controlBmp;
using (Graphics g1 = Graphics.FromHwnd(handle))
{
controlBmp = new Bitmap(width, height, g1);
using (Graphics g2 = Graphics.FromImage(controlBmp))
{
g2.CopyFromScreen(this.Location.X + PictureBox.Left, this.Location.Y + PictureBox.Top, 0, 0, PictureBox.Size);
IntPtr dc1 = g1.GetHdc();
IntPtr dc2 = g2.GetHdc();
BitBlt(dc2, 0, 0, width, height, handle, 0, 0, 13369376);
g1.ReleaseHdc(dc1);
g2.ReleaseHdc(dc2);
}
}
return controlBmp;
}
You need to set hPlayWnd as zero. Set callback function to work on decoded data. I try to understand Hikvision SDK, a few difficult...
lpPreviewInfo.hPlayWnd = IntPtr.Zero;//预览窗口 live view window
m_ptrRealHandle = RealPlayWnd.Handle;
RealData = new CHCNetSDK.REALDATACALLBACK(RealDataCallBack);//预览实时流回调函数 real-time stream callback function
m_lRealHandle = CHCNetSDK.NET_DVR_RealPlay_V40(m_lUserID, ref lpPreviewInfo, RealData, pUser);
public void RealDataCallBack(Int32 lRealHandle, UInt32 dwDataType, IntPtr pBuffer, UInt32 dwBufSize, IntPtr pUser)
//解码回调函数
private void DecCallbackFUN(int nPort, IntPtr pBuf, int nSize, ref PlayCtrl.FRAME_INFO pFrameInfo, int nReserved1, int nReserved2)
{
// 将pBuf解码后视频输入写入文件中(解码后YUV数据量极大,尤其是高清码流,不建议在回调函数中处理)
if (pFrameInfo.nType == 3) //#define T_YV12 3
{
// FileStream fs = null;
// BinaryWriter bw = null;
// try
// {
// fs = new FileStream("DecodedVideo.yuv", FileMode.Append);
// bw = new BinaryWriter(fs);
// byte[] byteBuf = new byte[nSize];
// Marshal.Copy(pBuf, byteBuf, 0, nSize);
// bw.Write(byteBuf);
// bw.Flush();
// }
// catch (System.Exception ex)
// {
// MessageBox.Show(ex.ToString());
// }
// finally
// {
// bw.Close();
// fs.Close();
// }
}
}
See the source code
Related
I want to calculate average pixels color from a specific area of the screen. I'm making a LED backlight for my TV so it needs to be very fast. At least 30fps. Bitmap.GetPixel() is too slow for it. I found an OpenGL method Gl.ReadPixels() but i don't know how it works. It recieving int[] as a data to return. But after calling this method i only get an array full of 0. How can i use this method? Or maybe there is some other way for this task?
By far the fastest way to process images in C# is through pinvoke using Win32 Gdi32 and User32 functionality.
Here is some C# code which captures the current desktop. Optionally you can pass the filepath of a 'mask' image which can be used to isolate a region(s) of the desktop capture. In the mask, texel which is black (with alpha 0) will be discarded from the screen grab. It's quite rudimental since it only supports 32-bit images and requires the mask and screen capture to be the same size. You welcome to improve on it in your own way, or you can see how image processing is done on a texel by texel basis by hooking directly into the Win32 functions with pinvoke (see constructor).
public class ScreenCapture
{
private System.Drawing.Bitmap capture;
/// <summary>
/// Constructor
/// </summary>
/// <param name="maskFile">Optional mask file, use "" for no mask</param>
public ScreenCapture( string maskFile )
{
// capture the screen
capture = CaptureWindow(User32.GetDesktopWindow());
// if there is a mask file, load it and apply it to the capture
if (maskFile != "")
{
string maskfilename = maskFile + ".png";
System.Drawing.Bitmap maskImage = System.Drawing.Image.FromFile(maskfilename) as Bitmap;
// ensure mask is same dim as capture...
if ((capture.Width != maskImage.Width) || (capture.Height != maskImage.Height))
throw new System.Exception("Mask image is required to be " + capture.Width + " x " + capture.Height + " RGBA for this screen capture");
Rectangle rectCapture = new Rectangle(0, 0, capture.Width, capture.Height);
Rectangle rectMask = new Rectangle(0, 0, maskImage.Width, maskImage.Height);
System.Drawing.Imaging.BitmapData dataCapture = capture.LockBits(rectCapture, System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
System.Drawing.Imaging.BitmapData dataMask = maskImage.LockBits(rectCapture, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
IntPtr ptrCapture = dataCapture.Scan0;
IntPtr ptrMask = dataMask.Scan0;
int size = Math.Abs(dataCapture.Stride) * capture.Height;
byte[] bitsCapture = new byte[size];
byte[] bitsMask = new byte[size];
System.Runtime.InteropServices.Marshal.Copy(ptrCapture, bitsCapture, 0, size);
System.Runtime.InteropServices.Marshal.Copy(ptrMask, bitsMask, 0, size);
// check each pixel of the image... if the mask is 0 for each channel, set the capture pixel to 0.
for (int n = 0; n < size; n += 4)
{
bool clearPixel = true;
for ( int c = 0; c < 4; ++c )
{
// if any pixel of the mask is not black, do not clear the capture pixel
if (bitsMask[n + c] != 0)
{
clearPixel = false;
break;
}
}
if ( clearPixel )
{
bitsCapture[n] = 0;
bitsCapture[n + 1] = 0;
bitsCapture[n + 2] = 0;
bitsCapture[n + 3] = 0;
}
}
System.Runtime.InteropServices.Marshal.Copy(bitsCapture, 0, ptrCapture, size);
System.Runtime.InteropServices.Marshal.Copy(bitsMask, 0, ptrMask, size);
capture_.UnlockBits(dataCapture);
maskImage.UnlockBits(dataMask);
}
}
/// <summary>
/// Creates an Image object containing a screen shot of a specific window
/// </summary>
/// <param name="handle">The handle to the window.
/// (In windows forms, this is obtained by the Handle property)</param>
/// <returns>Screen grab image</returns>
private System.Drawing.Bitmap CaptureWindow(IntPtr handle)
{
// get te hDC of the target window
IntPtr hdcSrc = User32.GetWindowDC(handle);
// get the size
User32.RECT windowRect = new User32.RECT();
User32.GetWindowRect(handle, ref windowRect);
int width = windowRect.right - windowRect.left;
int height = windowRect.bottom - windowRect.top;
// create a device context we can copy to
IntPtr hdcDest = GDI32.CreateCompatibleDC(hdcSrc);
// create a bitmap we can copy it to,
// using GetDeviceCaps to get the width/height
IntPtr hBitmap = GDI32.CreateCompatibleBitmap(hdcSrc, width, height);
// select the bitmap object
IntPtr hOld = GDI32.SelectObject(hdcDest, hBitmap);
// bitblt over
GDI32.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, GDI32.SRCCOPY);
// restore selection
GDI32.SelectObject(hdcDest, hOld);
// clean up
GDI32.DeleteDC(hdcDest);
User32.ReleaseDC(handle, hdcSrc);
// get a .NET image object for it
System.Drawing.Bitmap img = System.Drawing.Image.FromHbitmap(hBitmap);
// free up the Bitmap object
GDI32.DeleteObject(hBitmap);
return img;
}
/// <summary>
/// Save this capture as a Png image.
/// </summary>
/// <param name="filename">File path and name not including extension</param>
public void SaveCapture( string filename )
{
capture.Save(filename + ".png", System.Drawing.Imaging.ImageFormat.Png);
}
/// <summary>
/// Helper class containing Gdi32 API functions
/// </summary>
private class GDI32
{
public const int SRCCOPY = 0x00CC0020; // BitBlt dwRop parameter
[DllImport("gdi32.dll")]
public static extern bool BitBlt(IntPtr hObject, int nXDest, int nYDest,
int nWidth, int nHeight, IntPtr hObjectSource,
int nXSrc, int nYSrc, int dwRop);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int nWidth,
int nHeight);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
[DllImport("gdi32.dll")]
public static extern bool DeleteDC(IntPtr hDC);
[DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
[DllImport("gdi32.dll")]
public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
}
/// <summary>
/// Helper class containing User32 API functions
/// </summary>
private class User32
{
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[DllImport("user32.dll")]
public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
public static extern IntPtr GetActiveWindow();
[DllImport("user32.dll")]
public static extern IntPtr GetWindowDC(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("user32.dll")]
public static extern IntPtr GetWindowRect(IntPtr hWnd, ref RECT rect);
}
}
It throws exceptions, so be sure to catch them. To use...
ScreenCapture grab = new ScreenCapture( "screenGrabMask.png" );
grab.SaveCapture( "screenGrab.png" );
Take a look at Bitmap.LockBits
https://msdn.microsoft.com/de-de/library/5ey6h79d(v=vs.110).aspx
to provide some basic idea
private unsafe void demo(Bitmap bm)
{
System.Drawing.Imaging.BitmapData D = bm.LockBits(new Rectangle(0, 0, bm.Width, bm.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
int stride = Math.Abs(D.Stride);
byte* pImg = (byte*)D.Scan0.ToPointer();
for(int y = 0; y < bm.Height; y++)
{
byte* pRow = (byte*)(pImg + y * stride);
for(int x = 0; x < bm.Width; x++)
{
uint b = *pRow++;
uint g = *pRow++;
uint r = *pRow++;
pRow++; // skip alpha
// do something with r g b
}
}
bm.UnlockBits(D);
}
Allow unsafe code (be careful) to avoid extra memory copies.
I am having a problem with capturing the graphics of another proccess, because for some users it is just a pure black screen which I capture. Unfortunately I have no idea why this is happening for some users only. I am using the sub window directly instead of the window handle and I ensured by posting the address of the windowhandle and checking with spy++ that this window handle is actually the right one.
const string className = "BlueStacksApp";
const string windowName = "_ctl.Window";
processMainHWND = process.MainWindowHandle;
clientRectangleHandle = User32.FindWindowEx(processMainHWND, 0, className, windowName);
internal Bitmap MakeSnapshot(IntPtr AppWndHandle, RECT rect)
{
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
IntPtr hdcTo = IntPtr.Zero;
IntPtr hdcFrom = IntPtr.Zero;
IntPtr hBitmap = IntPtr.Zero;
try
{
Bitmap clsRet = null;
// get device context of the window...
hdcFrom = User32.GetWindowDC(AppWndHandle);
// create dc that we can draw to...
hdcTo = GDI32.CreateCompatibleDC(hdcFrom);
hBitmap = GDI32.CreateCompatibleBitmap(hdcFrom, width, height);
// validate
if (hBitmap != IntPtr.Zero)
{
// adjust and copy
IntPtr hLocalBitmap = GDI32.SelectObject(hdcTo, hBitmap);
bool result = GDI32.BitBlt(hdcTo, 0, 0, width, height, hdcFrom, 0, 0, GDI32.SRCCOPY);
GDI32.SelectObject(hdcTo, hLocalBitmap);
// create bitmap for window image...
clsRet = Image.FromHbitmap(hBitmap);
}
return clsRet;
}
finally
{
// release the unmanaged resources
if (hdcFrom != IntPtr.Zero)
User32.ReleaseDC(AppWndHandle, hdcFrom);
if (hdcTo != IntPtr.Zero)
GDI32.DeleteDC(hdcTo);
if (hBitmap != IntPtr.Zero)
GDI32.DeleteObject(hBitmap);
}
}
I am trying to draw some text using TextRenderer (since this is favorable to using Graphics.DrawString) to a Bitmap, however it is having some very undesirable effects.
Example Code
using (Bitmap buffer = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
{
using (Graphics graphics = Graphics.FromImage(buffer))
{
// Produces the result below
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
// Produces clean text, but I'd really like ClearType!
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
TextRenderer.DrawText(graphics, "Hello World", this.Font, this.ClientRectangle, Color.Black);
}
e.Graphics.DrawImageUnscaled(buffer, this.ClientRectangle);
}
Result
I'm not sure exactly how to fix this...help!
I do NOT want to use Graphics.DrawString as I want correct GDI (as opposed to GDI+) rendering.
NOTE: I've just realized, I've left a gaping hole in this question. Some people have pointed out that rendering ClearType text is working fine on their machines...
I'm trying to render the text to a transparent (Color.Transparent) bitmap. If I do it with a solid color, everything works fine! (but it is imperative that I render to a transparent Bitmap).
Specify a BackColor in your call to DrawText():
TextRenderer.DrawText(graphics, "Hello World", this.Font, this.ClientRectangle, Color.Black, this.BackColor);
You can try setting TextRenderingHint for your Image Graphics:
using (Graphics graphics = Graphics.FromImage(buffer))
{
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
TextRenderer.DrawText(graphics, "Hello World", this.Font, this.ClientRectangle, Color.Black);
}
The issue is that TextRenderer uses GDI rendering that uses ClearType to render text, clear-type uses special anti-aliasing algorithm to smooth the text, unfortunately it doesn't work when you try to draw on bitmap device.
To make it work you have to use a trick, draw into in-memory and then copy to bitmap:
Create in-memory bitmap buffer that is compatible with display device context (IntPtr.Zero handle)
Fill the buffer background with solid color or image
Render the text into the memory bitmap
Copy from in-memory bitmap to image device context (BitBlt)
See this blog for details: GDI text rendering to image.
Sample code, sorry its a bit long:
public static class Test
{
public static Image Render()
{
// create the final image to render into
var image = new Bitmap(190, 30, PixelFormat.Format32bppArgb);
// create memory buffer from desktop handle that supports alpha channel
IntPtr dib;
var memoryHdc = CreateMemoryHdc(IntPtr.Zero, image.Width, image.Height, out dib);
try
{
// create memory buffer graphics to use for HTML rendering
using (var memoryGraphics = Graphics.FromHdc(memoryHdc))
{
// must not be transparent background
memoryGraphics.Clear(Color.White);
// execute GDI text rendering
TextRenderer.DrawText(memoryGraphics, "Test string 1", new Font("Arial", 12), new Point(5, 5), Color.Red, Color.Wheat);
TextRenderer.DrawText(memoryGraphics, "Test string 2", new Font("Arial", 12), new Point(100, 5), Color.Red);
}
// copy from memory buffer to image
using (var imageGraphics = Graphics.FromImage(image))
{
var imgHdc = imageGraphics.GetHdc();
BitBlt(imgHdc, 0, 0, image.Width, image.Height, memoryHdc, 0, 0, 0x00CC0020);
imageGraphics.ReleaseHdc(imgHdc);
}
}
finally
{
// release memory buffer
DeleteObject(dib);
DeleteDC(memoryHdc);
}
return image;
}
private static IntPtr CreateMemoryHdc(IntPtr hdc, int width, int height, out IntPtr dib)
{
// Create a memory DC so we can work off-screen
IntPtr memoryHdc = CreateCompatibleDC(hdc);
SetBkMode(memoryHdc, 1);
// Create a device-independent bitmap and select it into our DC
var info = new BitMapInfo();
info.biSize = Marshal.SizeOf(info);
info.biWidth = width;
info.biHeight = -height;
info.biPlanes = 1;
info.biBitCount = 32;
info.biCompression = 0; // BI_RGB
IntPtr ppvBits;
dib = CreateDIBSection(hdc, ref info, 0, out ppvBits, IntPtr.Zero, 0);
SelectObject(memoryHdc, dib);
return memoryHdc;
}
[DllImport("gdi32.dll")]
public static extern int SetBkMode(IntPtr hdc, int mode);
[DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
private static extern IntPtr CreateCompatibleDC(IntPtr hdc);
[DllImport("gdi32.dll")]
private static extern IntPtr CreateDIBSection(IntPtr hdc, [In] ref BitMapInfo pbmi, uint iUsage, out IntPtr ppvBits, IntPtr hSection, uint dwOffset);
[DllImport("gdi32.dll")]
public static extern int SelectObject(IntPtr hdc, IntPtr hgdiObj);
[DllImport("gdi32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop);
[DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
[DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
public static extern bool DeleteDC(IntPtr hdc);
[StructLayout(LayoutKind.Sequential)]
internal struct BitMapInfo
{
public int biSize;
public int biWidth;
public int biHeight;
public short biPlanes;
public short biBitCount;
public int biCompression;
public int biSizeImage;
public int biXPelsPerMeter;
public int biYPelsPerMeter;
public int biClrUsed;
public int biClrImportant;
public byte bmiColors_rgbBlue;
public byte bmiColors_rgbGreen;
public byte bmiColors_rgbRed;
public byte bmiColors_rgbReserved;
}
}
It's a fairly standard screen capture function using BitBlt that's found in the net:
Main Function:
while(true)
{
printscreen = GetDesktopImage(X, Y, secMonitorSize.Width, secMonitorSize.Height);
Thread.Sleep(1000);
}
Capture Desktop function:
public Bitmap GetDesktopImage(int X, int Y, int width, int height)
{
IntPtr hDC = WIN32_API.GetDC(WIN32_API.GetDesktopWindow());
IntPtr hMemDC = WIN32_API.CreateCompatibleDC(hDC);
IntPtr m_HBitmap = WIN32_API.CreateCompatibleBitmap(hDC, width, height);
if (m_HBitmap != IntPtr.Zero)
{
IntPtr hOld = (IntPtr)WIN32_API.SelectObject(hMemDC, m_HBitmap);
WIN32_API.BitBlt(hMemDC, 0, 0, width, height, hDC, X, Y, WIN32_API.SRCCOPY | WIN32_API.CAPTURE_BLT);
WIN32_API.SelectObject(hMemDC, hOld);
WIN32_API.DeleteDC(hMemDC);
WIN32_API.ReleaseDC(WIN32_API.GetDesktopWindow(), hDC);
Bitmap printscreen = System.Drawing.Image.FromHbitmap(m_HBitmap);
WIN32_API.DeleteObject(m_HBitmap);
return printscreen;
}
return null;
}
The problem is that the code runs fine for roughly 20 mins, then CreateCompatibleBitmap will keep returning 0. Using setlasterror=true on CreateCompatibleBitmap, it displays the error code 997 (Overlapped I/O Operation Is In Progress).
There's only symantec running in the background. Anyone have any idea how do I start troubleshooting?
GDI functions do not use GetLastError(), so using setlasterror=true will report errors from earlier API calls.
Try this:
public Bitmap GetDesktopImage(int X, int Y, int width, int height)
{
Bitmap printscreen = null;
IntPtr hWnd = WIN32_API.GetDesktopWindow();
IntPtr hDC = WIN32_API.GetDC(hWnd);
if (hDC != IntPtr.Zero)
{
IntPtr hMemDC = WIN32_API.CreateCompatibleDC(hDC);
if (hMemDC != IntPtr.Zero)
{
IntPtr m_HBitmap = WIN32_API.CreateCompatibleBitmap(hDC, width, height);
if (m_HBitmap != IntPtr.Zero)
{
IntPtr hOld = (IntPtr)WIN32_API.SelectObject(hMemDC, m_HBitmap);
WIN32_API.BitBlt(hMemDC, 0, 0, width, height, hDC, X, Y, WIN32_API.SRCCOPY | WIN32_API.CAPTURE_BLT);
WIN32_API.SelectObject(hMemDC, hOld);
printscreen = System.Drawing.Image.FromHbitmap(m_HBitmap);
WIN32_API.DeleteObject(m_HBitmap);
}
WIN32_API.DeleteDC(hMemDC);
}
WIN32_API.ReleaseDC(hWnd, hDC);
}
return printscreen;
}
I am trying to use an HIMAGELIST from an unmanaged dll which gives me the result as an IntPtr.
Is there a way for me to turn this IntPtr into a Bitmap or an Image so I can use it for Winforms buttons, as in:
myButton.Image = intPtrImage
You need to call ImageList_GetIcon for each image in the list - this will give you an HICON which is easy to load into a Bitmap
Use this functions for that:
private const string Gdi32Dll = #".\gdi32.dll";
[DllImport(Gdi32Dll, ExactSpelling = true)]
internal static extern int SetDIBitsToDevice(
IntPtr hdc,
int xdst,
int ydst,
int width,
int height,
int xsrc,
int ysrc,
int start,
int lines,
IntPtr bitsptr,
IntPtr bmiptr,
int color);
public static Bitmap BitmapFromDIB(IntPtr dibPtrArg)
{
Bitmapinfoheader bmiHeader;
IntPtr pixptr = IntPtr.Zero;
GetPixelInfo(dibPtrArg, out pixptr, out bmiHeader);
Bitmap bitMap = new Bitmap(bmiHeader.biWidth, bmiHeader.biHeight);
Graphics scannedImageGraphics = Graphics.FromImage(bitMap);
IntPtr hdc = scannedImageGraphics.GetHdc();
SetDIBitsToDevice(
hdc,
0, // XDest
0, // YDest
bmiHeader.biWidth,
bmiHeader.biHeight,
0, // XSrc
0, // YSrc
0, // uStartScan
bmiHeader.biHeight, // cScanLines
pixptr, // lpvBits
dibPtrArg, // lpbmi
DibRgbColors); // 0 = literal RGB values rather than palette
scannedImageGraphics.ReleaseHdc(hdc);
return bitMap;
}
private static void GetPixelInfo(IntPtr bmpptr, out IntPtr pix, out Bitmapinfoheader bmi)
{
bmi = new Bitmapinfoheader();
Marshal.PtrToStructure(bmpptr, bmi); // copy into struct.
if (bmi.biSizeImage == 0)
{
bmi.biSizeImage = ((((bmi.biWidth * bmi.biBitCount) + 31) & ~31) >> 3) * bmi.biHeight;
}
int p = bmi.biClrUsed;
if ((p == 0) && (bmi.biBitCount <= 8))
{
p = 1 << bmi.biBitCount;
}
pix = (IntPtr)((p * 2) + bmi.biSize + (int)bmpptr);
}