IntPtr parameter is not valid bitmap GetHdc - c#

I have a problem, and i don't know how resolved.. I'm using the drive twain to do scanner some documents, and i don't get create a new BitMap when i'm scanning a big number of the files.. So.. i need help to solution this.. my code is:
public static Bitmap FromHDib(IntPtr dibPtrArg, out ServiceError error)
{
error = null;
try
{
Win32.BITMAPINFOHEADER bmi;
IntPtr pixptr;
var ptr = Win32.GlobalLock(dibPtrArg);
GetPixelInfo(ptr, out pixptr, out bmi);
Bitmap bitMap = new Bitmap(bmi.biWidth, bmi.biHeight);
Graphics scannedImageGraphics = Graphics.FromImage(bitMap);
**IntPtr hdc = scannedImageGraphics.GetHdc();** //parameter is not valid
SetDIBitsToDevice(
hdc,
0, // XDest
0, // YDest
bmi.biWidth,
bmi.biHeight,
0, // XSrc
0, // YSrc
0, // uStartScan
bmi.biHeight, // cScanLines
pixptr, // lpvBits
ptr, // lpbmi
0); // 0 = literal RGB values rather than palette
scannedImageGraphics.ReleaseHdc(hdc);
const float inchPerMeter = 39.3700787F;
bitMap.SetResolution(bmi.biXPelsPerMeter / inchPerMeter, bmi.biYPelsPerMeter / inchPerMeter);
Win32.GlobalUnlock(dibPtrArg);
Win32.GlobalFree(dibPtrArg);
Win32.DeleteDC(hdc);
bitMap.Dispose();
return bitMap;
}
catch (OutOfMemoryException memoryEx)
{
return new Bitmap(0, 0);
}
catch (ArgumentException argEx)
{
return new Bitmap(0, 0);
}
}

Related

how to solve system.argumentexception parameter is not valid. at system.drawing.bitmap..ctor(int32 width, int32 height, pixelformat format)

i have a project that captures images by basler camera and for this i have a onimagegrabbed Function that grabs image.
while running my project in any cpu it i did not getting any error. but when i turned to x86 , project runs but after 2 or 3 seconds I am getting exception message " system.argumentexception parameter is not valid. at system.drawing.bitmap..ctor(int32 width, int32 height, pixelformat format) ."
also gettig this message in this in console tab
"Exception thrown: 'System.ArgumentException' in System.Drawing.dll"
the exception message screenshot is here
heres what i have tried
private void OnImageGrabbed(object sender, ImageGrabbedEventArgs e)
{
bool invokeRequired = base.InvokeRequired;
if (invokeRequired)
{
base.BeginInvoke(new EventHandler<ImageGrabbedEventArgs>(this.OnImageGrabbed), new object[]
{
sender,
e.Clone()
});
}
else
{
try
{
this.grabResult = e.GrabResult;
bool isValid = this.grabResult.IsValid;
if (isValid)
{
bool flag = !this.stopWatch.IsRunning || this.stopWatch.ElapsedMilliseconds > 33L;
if (flag)
{
this.stopWatch.Restart();
Bitmap bitmap = new Bitmap(this.grabResult.Width, this.grabResult.Height, PixelFormat.Format32bppRgb);
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
this.converter.OutputPixelFormat = PixelType.BGRA8packed;
IntPtr scan = bitmapData.Scan0;
this.converter.Convert(scan, (long)(bitmapData.Stride * bitmap.Height), this.grabResult);
bitmap.UnlockBits(bitmapData);
object obj = this.lockObject;
lock (obj)
{
Bitmap bitmap2 = this.DisplayWindow.Image as Bitmap;
bitmap.RotateFlip(RotateFlipType.Rotate90FlipNone);
this.gb = this.CreateNonIndexedImage(bitmap);
this.DisplayWindow.Image = bitmap;
bool flag3 = bitmap2 != null;
if (flag3)
{
bitmap2.Dispose();
}
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
e.DisposeGrabResultIfClone();
}
}
}
the line:150 is " Bitmap bitmap = new Bitmap(this.grabResult.Width, this.grabResult.Height, PixelFormat.Format32bppRgb);"

Is there another way to export a frame in ffmpeg to a texture2d? My code working in Windows but not Linux

Sound is working in Linux the same as it did in Windows. But the video is just a black screen and when I attempt to save the frames as BMP files all of them were corrupt/empty files. I am using Ffmpeg.Autogen to interface with the libraries. https://github.com/Ruslan-B/FFmpeg.AutoGen. The file is VP8 and OGG in a MKV container. Though the extension is AVI for some reason.
I tried messing with the order of the code a bit. I checked to make sure the build of Ffmpeg on Linux had VP8. I was searching online but was having trouble finding another way to do what I am doing. This is to contribute to the OpenVIII project. My fork-> https://github.com/Sebanisu/OpenVIII
This just preps the scaler to change the pixelformat or else people have blue faces.
private void PrepareScaler()
{
if (MediaType != AVMediaType.AVMEDIA_TYPE_VIDEO)
{
return;
}
ScalerContext = ffmpeg.sws_getContext(
Decoder.CodecContext->width, Decoder.CodecContext->height, Decoder.CodecContext->pix_fmt,
Decoder.CodecContext->width, Decoder.CodecContext->height, AVPixelFormat.AV_PIX_FMT_RGBA,
ffmpeg.SWS_ACCURATE_RND, null, null, null);
Return = ffmpeg.sws_init_context(ScalerContext, null, null);
CheckReturn();
}
Converts Frame to BMP
I am thinking this is where the problem is. Because I had added bitmap.save to this and got empty BMPs.
public Bitmap FrameToBMP()
{
Bitmap bitmap = null;
BitmapData bitmapData = null;
try
{
bitmap = new Bitmap(Decoder.CodecContext->width, Decoder.CodecContext->height, PixelFormat.Format32bppArgb);
AVPixelFormat v = Decoder.CodecContext->pix_fmt;
// lock the bitmap
bitmapData = bitmap.LockBits(new Rectangle(0, 0, Decoder.CodecContext->width, Decoder.CodecContext->height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
byte* ptr = (byte*)(bitmapData.Scan0);
byte*[] srcData = { ptr, null, null, null };
int[] srcLinesize = { bitmapData.Stride, 0, 0, 0 };
// convert video frame to the RGB bitmap
ffmpeg.sws_scale(ScalerContext, Decoder.Frame->data, Decoder.Frame->linesize, 0, Decoder.CodecContext->height, srcData, srcLinesize); //sws_scale broken on linux?
}
finally
{
if (bitmap != null && bitmapData != null)
{
bitmap.UnlockBits(bitmapData);
}
}
return bitmap;
}
After I get a bitmap we turn it into a Texture2D so we can draw it.
public Texture2D FrameToTexture2D()
{
//Get Bitmap. there might be a way to skip this step.
using (Bitmap frame = FrameToBMP())
{
//string filename = Path.Combine(Path.GetTempPath(), $"{Path.GetFileNameWithoutExtension(DecodedFileName)}_rawframe.{Decoder.CodecContext->frame_number}.bmp");
//frame.Save(filename);
BitmapData bmpdata = null;
Texture2D frameTex = null;
try
{
//Create Texture
frameTex = new Texture2D(Memory.spriteBatch.GraphicsDevice, frame.Width, frame.Height, false, SurfaceFormat.Color); //GC will collect frameTex
//Fill it with the bitmap.
bmpdata = frame.LockBits(new Rectangle(0, 0, frame.Width, frame.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);// System.Drawing.Imaging.PixelFormat.Format32bppArgb);
byte[] texBuffer = new byte[bmpdata.Width * bmpdata.Height * 4]; //GC here
Marshal.Copy(bmpdata.Scan0, texBuffer, 0, texBuffer.Length);
frameTex.SetData(texBuffer);
}
finally
{
if (bmpdata != null)
{
frame.UnlockBits(bmpdata);
}
}
return frameTex;
}
}
I can post more if you want it's pretty much all up on my fork
Video will play back as it does in Windows. As smooth as 15 fps can be. :)
I ended up removing the bitmap part of the code. And it worked! So previously I would convert the frame to a bitmap and it would copy the pixels out of the bitmap into the Texture2D. I looked closer and realized I could skip that step of the bitmap. I'm sorry for not being clear enough on my question.
/// <summary>
/// Converts Frame to Texture
/// </summary>
/// <returns>Texture2D</returns>
public Texture2D FrameToTexture2D()
{
Texture2D frameTex = new Texture2D(Memory.spriteBatch.GraphicsDevice, Decoder.CodecContext->width, Decoder.CodecContext->height, false, SurfaceFormat.Color);
const int bpp = 4;
byte[] texBuffer = new byte[Decoder.CodecContext->width * Decoder.CodecContext->height * bpp];
fixed (byte* ptr = &texBuffer[0])
{
byte*[] srcData = { ptr, null, null, null };
int[] srcLinesize = { Decoder.CodecContext->width * bpp, 0, 0, 0 };
// convert video frame to the RGB data
ffmpeg.sws_scale(ScalerContext, Decoder.Frame->data, Decoder.Frame->linesize, 0, Decoder.CodecContext->height, srcData, srcLinesize);
}
frameTex.SetData(texBuffer);
return frameTex;
}

c# Capturing and taking a screenshot of a window in a infinite loop

I make screenshot of a window in a infinite loop
it works good.
But I hope it can be improved.
When i run my project, it has a litter delay to copy "Myscreen" from "PictureBox".
Anyone have a idea?
Or did you know any other solutions?
I just want to get Screen's BITMAP constantly.(faster..)
Below source is screen capture function.
public static Bitmap ScreenCapture_B(System.Windows.Forms.Screen MyScreen)
{
try
{
Rectangle rect = MyScreen.Bounds;
// 2nd screen = Screen.AllScreens[1]
int bitsPerPixel = MyScreen.BitsPerPixel;
PixelFormat pixelFormat = PixelFormat.Format32bppArgb;
if (bitsPerPixel <= 16)
{
pixelFormat = PixelFormat.Format16bppRgb565;
}
if (bitsPerPixel == 24)
{
pixelFormat = PixelFormat.Format24bppRgb;
}
else
{
pixelFormat = PixelFormat.Format24bppRgb;
}
Bitmap bmp = new Bitmap(rect.Width, rect.Height, pixelFormat);
using (Graphics gr = Graphics.FromImage(bmp))
{
// 화면을 그대로 카피해서 Bitmap 메모리에 저장
gr.CopyFromScreen(rect.Left, rect.Top, 0, 0, rect.Size);
}
return bmp;
}
catch(Exception)
{
throw;
}
}
Bellow source is Thread.
public void ThreadLoop()
{
try
{
//infinite loop
while (true)
{
bm = null;
Screen MyScreen = Screen.PrimaryScreen;
bm = ScreenCapture_B(MyScreen);
setImage(bm, pictureEdit1);
Bitmap btimage = new Bitmap(pictureEdit1.Image);
ProcessImage_new(btimage);
}
}
catch (Exception ex)
{
throw;
}
}

Grab Bitmap-Image (Winforms) and convert to WPF-Image fails

I grab an image from a external camera. The winforms application works so far. Now I need to transfer it to WPF. Therefore I converted the bitmap-image to WPF like this:
GrabHandler frameCallbackDelegate;
void frameCallBack(IntPtr lpUserData, ref VCECLB_FrameInfoEx frameInfo)
{
if (frameInfo.dma_status != 0) return;
// fill image
Rectangle rect = new Rectangle(0, 0, image.Width, image.Height);
BitmapData bmdata = image.LockBits(rect, ImageLockMode.ReadWrite, image.PixelFormat);
UInt32 outputBitDepth;
IntPtr stride = new IntPtr(bmdata.Stride);
VCECLB_Error err = NativeFunctions.VCECLB_UnpackRawPixelsEx(ref pRawPixelInfo, frameInfo.lpRawBuffer, bmdata.Scan0, ref stride, VCECLB_Output_Format.VCECLB_EX_FMT_TopDown | VCECLB_Output_Format.VCECLB_EX_FMT_3Channel, out outputBitDepth);
image.UnlockBits(bmdata);
Dispatcher.Invoke(new Action(() =>
{
// Convert bitmap to WPF-Image
var bmp = new Bitmap(image);
var hBitmap = bmp.GetHbitmap();
ImageSource wpfBitmap = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
hBitmap,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
image_LowLight.Source = wpfBitmap;
DeleteObject(hBitmap);
image.Dispose();
}));
GC.Collect();
}
private void StartGrab(object sender, RoutedEventArgs e)
{
start_button.IsEnabled = true;
stop_button.IsEnabled = false;
frameCallbackDelegate = new GrabHandler(frameCallBack);
m_ImageAquisition.StartGrab(frameCallbackDelegate);
}
When I enter for the first time the frameCallBack from the StartGrab, the image.Width and image.Height have a valid value (not 0) and it seems correct. When the frameCallBack is entered for the second time all image-data (width and height) are 0 and therefore rect gives an error.
Is there something wrong in the way I am using the Dispatcher.Invoke to get a valid bitmap-image?
Thanks!
Avoid using volatile data in an Action() which gets executed some time later by the Dispatcher.
Refactor your code like this:
GrabHandler frameCallbackDelegate;
void frameCallBack(IntPtr lpUserData, ref VCECLB_FrameInfoEx frameInfo)
{
if (frameInfo.dma_status != 0) return;
// fill image
Rectangle rect = new Rectangle(0, 0, image.Width, image.Height);
BitmapData bmdata = image.LockBits(rect, ImageLockMode.ReadWrite, image.PixelFormat);
UInt32 outputBitDepth;
IntPtr stride = new IntPtr(bmdata.Stride);
VCECLB_Error err = NativeFunctions.VCECLB_UnpackRawPixelsEx(ref pRawPixelInfo, frameInfo.lpRawBuffer, bmdata.Scan0, ref stride, VCECLB_Output_Format.VCECLB_EX_FMT_TopDown | VCECLB_Output_Format.VCECLB_EX_FMT_3Channel, out outputBitDepth);
image.UnlockBits(bmdata);
// Convert bitmap to WPF-Image
var bmp = new Bitmap(image);
var hBitmap = bmp.GetHbitmap();
ImageSource wpfBitmap =
System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
hBitmap,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
DeleteObject(hBitmap);
image.Dispose();
Dispatcher.Invoke(new Action(() =>
{
image_LowLight.Source = wpfBitmap;
}));
GC.Collect();
}

How to convert ISampleGrabber::BufferCB's buffer to a bitmap

I am trying to use the ISampleGrabberCB::BufferCB to convert the current frame to bitmap using the following code:
int ISampleGrabberCB.BufferCB(double sampleTime, IntPtr buffer, int bufferLength)
{
try
{
Form1 form1 = new Form1("", "", "");
if (pictureReady == null)
{
Debug.Assert(bufferLength == Math.Abs(pitch) * videoHeight, "Wrong Buffer Length");
}
Debug.Assert(imageBuffer != IntPtr.Zero, "Remove Buffer");
Bitmap bitmapOfCurrentFrame = new Bitmap(width, height, capturePitch, PixelFormat.Format24bppRgb, buffer);
MessageBox.Show("Works");
form1.changepicturebox3(bitmapOfCurrentFrame);
pictureReady.Set();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
return 0;
}
However this does not seem to be working.
Additionally it seems to call this function when i press a button which runs the following code:
public IntPtr getFrame()
{
int hr;
try
{
pictureReady.Reset();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
imageBuffer = Marshal.AllocCoTaskMem(Math.Abs(pitch) * videoHeight);
try
{
gotFrame = true;
if (videoControl != null)
{
hr = videoControl.SetMode(stillPin, VideoControlFlags.Trigger);
DsError.ThrowExceptionForHR(hr);
}
if (!pictureReady.WaitOne(9000, false))
{
throw new Exception("Timeout waiting to get picture");
}
}
catch
{
Marshal.FreeCoTaskMem(imageBuffer);
imageBuffer = IntPtr.Zero;
}
return imageBuffer;
}
Once this code is ran I get a message box which shows 'Works' thus meaning my BufferCB must of been called however does not update my picture box with the current image.
Is the BufferCB not called after every new frame? If so why do I not recieve the 'Works' message box?
Finally is it possible to convert every new frame into a bitmap (this is used for later processing) using BufferCB and if so how?
Edited code:
int ISampleGrabberCB.BufferCB(double sampleTime, IntPtr buffer, int bufferLength)
{
Debug.Assert(bufferLength == Math.Abs(pitch) * videoHeight, "Wrong Buffer Length");
Debug.Assert(imageBuffer != IntPtr.Zero, "Remove Buffer");
CopyMemory(imageBuffer, buffer, bufferLength);
Decode(buffer);
return 0;
}
public Image Decode(IntPtr imageData)
{
var bitmap = new Bitmap(width, height, pitch, PixelFormat.Format24bppRgb, imageBuffer);
bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
Form1 form1 = new Form1("", "", "");
form1.changepicturebox3(bitmap);
bitmap.Save("C:\\Users\\...\\Desktop\\A2 Project\\barcode.jpg");
return bitmap;
}
Button code:
public void getFrameFromWebcam()
{
if (iPtr != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(iPtr);
iPtr = IntPtr.Zero;
}
//Get Image
iPtr = sampleGrabberCallBack.getFrame();
Bitmap bitmapOfFrame = new Bitmap(sampleGrabberCallBack.width, sampleGrabberCallBack.height, sampleGrabberCallBack.capturePitch, PixelFormat.Format24bppRgb, iPtr);
bitmapOfFrame.RotateFlip(RotateFlipType.RotateNoneFlipY);
barcodeReader(bitmapOfFrame);
}
public IntPtr getFrame()
{
int hr;
try
{
pictureReady.Reset();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
imageBuffer = Marshal.AllocCoTaskMem(Math.Abs(pitch) * videoHeight);
try
{
gotFrame = true;
if (videoControl != null)
{
hr = videoControl.SetMode(stillPin, VideoControlFlags.Trigger);
DsError.ThrowExceptionForHR(hr);
}
if (!pictureReady.WaitOne(9000, false))
{
throw new Exception("Timeout waiting to get picture");
}
}
catch
{
Marshal.FreeCoTaskMem(imageBuffer);
imageBuffer = IntPtr.Zero;
}
return imageBuffer;
}
I also still need to press the button to run the BufferCB
Thanks for reading.
BufferCB is called for every new frame that has been captured by the camera. You don't see the message box, because the method is called from another thread (not the ui thread). See this question for details.
In my code I used AutoResetEvent for capturing a frame:
#region samplegrabber
/// <summary>
/// buffer callback, COULD BE FROM FOREIGN THREAD.
/// </summary>
int ISampleGrabberCB.BufferCB (double sampleTime,
IntPtr pBuffer,
int bufferLen)
{
if (_sampleRequest)
{
_sampleRequest = false;
if (bufferLen > _bufferSize)
throw new Exception ("buffer is wrong size");
Win32.CopyMemory (_buffer, pBuffer, _bufferSize);
// Picture is ready.
_resetEvent.Set ();
}
else
_dropped++;
return 0;
}
The image can then be decoded from the IntPtr with another function:
public Image Decode (IntPtr data)
{
var bitmap = new Bitmap (_width, _height, _stride, PixelFormat.Format24bppRgb, data);
bitmap.RotateFlip (RotateFlipType.RotateNoneFlipY);
return bitmap;
}

Categories

Resources