Convert PictureBox image to bitmap - c#

I am working with a fingerprint module and am able to capture and display the output in a picture box (C#). Now picture.Image is null even though picturebox displays an image. So I am trying to save the picturebox image as bmp and then assign that bmp to the same picturebox so that Picturebox.image is not null.
Here is the code :
Bitmap bmp = new Bitmap(picFP.width, picFP.height);
picFP.DrawToBitmap(bmp, picFP.ClientRectangle);
bmp.Save("path", Imageformat.bmp);
picFP.image = bmp;
Here bitmap image saved is blank. What can be the problem?

A PictureBox has three layers it can display and PictureBox.DrawToBitmap will put all three things into the Bitmap:
The BackgroundImage
The Image
Any graphics created in or from the Paint event
If your bitmap comes out black then you have none of the three, or the last you have is all black.
From your description it seems as if you can display the image in the PictureBox.
So I assume that you don't display it in the right way, probably you do it like this:
using (Graphics G = picFP.CreateGraphics())
G.DrawImage(yourCapturedImage, ..)
This will not work as it only creates non-persistent graphics. These go away with e.g. each minimize-restore cycle and are not called from the DrawToBitmap call
If you really want to draw it onto the PB's surface use the Paint event! But the more natural choice would be to set the PB's Image directly:
picFP.Image = yourCapturedImage;
Update 1 As you now reveal that you don't display it yourself but simply give the control handle to the external code objNitgen=picFP.Handle; the same applies: It is that Nitgen draws only onto the surface and the result is non-persistent.
In this case the remedy is either
Taking a screenshot of the result and then work from that. Here is a post that shows you how to capture a control via screenshot..
Or you may want to check if Nitgen will draw into a bitmap directly..
For this you should be to pass it not a handle to the PictureBox but to a Bitmap instead:
private void button_Click(object sender, EventArgs e)
{
Bitmap bmp = new Bitmap(picFP.ClientSize.Width, picFP.ClientSize.Height);
Graphics G = Graphics.FromImage(bmp);
IntPtr dc= G.GetHdc();
objNitgen = dc;
objNitgen.capture();
G.ReleaseHdc(dc);
pictureBox1.Image = bmp; // now display..
bmp.Save(yourfilename); // .. and/or save
}
Update 2
You noted in a comment that doing a manual screenshot also does not capture the image; so it seems the control handle is only used to overlay it with the image much like video overlays do; if this is the case I doubt you can get at the image without using other, more fitting Nitgen SDK methods.

Related

Custom bitmap capture that keeps formatting?

I have been using Bitmap to take a capture of my main form and saving it as jpeg. Unfortunately bitmap does not keep my text colour. Best way I can describe this is by images (see below). My mainform has an objectlistview which has a column coloured red. Bitmap however captures this as black text? why?
Is there any other alternative method I can use?
I have tried capturing screen and cutting out the the mainform as shown in the code below. This works great on a 1080p monitor, but not on my 4k monitor with 200% scaling, it results in the image being cut.
public void SaveControlImage(Form form)
{
string path_and_file = "C:\1.png";
Bitmap controlBitMap = new Bitmap(form.Width, form.Height);
Graphics g = Graphics.FromImage(controlBitMap);
g.CopyFromScreen(PointToScreen(form.Location), new Point(0, 0), form.Size);
// example of saving to the desktop
controlBitMap.Save(path_and_file, System.Drawing.Imaging.ImageFormat.Png);
}

Webcam image differ from printed image

I am busy with a C# winform software. I use webcam to take a picture which display in a pictureBox.
When I capture the image with the webcam, it captures a zoomed image, and when printing, it is a stretched image. I have tried a variety of SizeMode settings.All give the same result
Because I am not sure where the fault is, I will include as much detail as possible:
Using
using AForge.Video;
using AForge.Video.DirectShow;
Selecting Camera:
webcam = new FilterInfoCollection(FilterCategory.VideoInputDevice);
foreach (FilterInfo VideoCaptureDevice in webcam)
{
cmbVideoList.Items.Add(VideoCaptureDevice.Name);
}
Using camera (btn click):
cam = new VideoCaptureDevice(webcam[cmbVideoList.SelectedIndex].MonikerString);
cam.NewFrame += new NewFrameEventHandler(cam_NewFrame);
cam.Start();
if (cam.IsRunning)
{
btnStart.Hide();
}
btnStop.Show();
}
void cam_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
Bitmap bit = (Bitmap)eventArgs.Frame.Clone();
pboxPhoto.Image = bit;
}
PictureBox size:
Width: 226
Height: 328
Printing code:
PictureBox pict = (PictureBox)pboxPhoto;
pict.SizeMode = PictureBoxSizeMode.Zoom;
e.Graphics.DrawImage(pict.Image, 20, 416, 305, 328);
Here is a sample of the image on software:
enter image description here
Sample of printed image.
enter image description here
The simplest way is to tell the PictureBox to draw itself to a Bitmap.
This can be done with all Controls and the result will include not just the Image and maybe BackgroundImage but also anything drawn in the Paint event as well as any nested Controls.
Here is a simple example:
Size sz = pictureBox1.ClientSize;
using (Bitmap bmp = new Bitmap(sz.Width, sz.Height))
{
pictureBox1.DrawToBitmap(bmp, pictureBox1.ClientRectangle);
// save the image..
bmp.Save(yourfilepath, ImageFormat.Png);
// ..or print it!
}
A few notes:
Due to the using clause the Bitmap get disposed after the last curly, so you would either make use of it inside scope or change to a pattern that disposes of the Bitmap at a later point in time.
The nested Controls will be drawn a reverse order which will cause problem if they are overlapping!
Only nested, not overlayed Controls will be included. Since PictureBox is not a Container (as opposed to e.g. a Panel) it won't do to simply placea, say Label, over it; instead you need to nest it in code, i.e. make the PictureBox its Parent and also set a suitable relative Location..
By default the Bitmap will have the current machine's screen dpi resolution. You cold change it afterwards with bmp.SetResolution()..

DrawToBitmap returning blank image

I have a problem on creating bitmap image out of my winform application.
Situation:
I have a UserControl named as "CanvasControl" that accepts OnPaint method acting as canvas for my Draw Pad application. Inside this user control I have a function "PrintCanvas()" that will create a screenshot image of the UserControl into PNG file. Below is the PrintCanvas() function:
public void PrintCanvas(string filename = "sample.png")
{
Graphics g = this.CreateGraphics();
//new bitmap object to save the image
Bitmap bmp = new Bitmap(this.Width, this.Height);
//Drawing control to the bitmap
this.DrawToBitmap(bmp, new Rectangle(0, 0, this.Width, this.Height));
bmp.Save(Application.StartupPath +
#"\ExperimentFiles\Experiment1" + filename, ImageFormat.Png);
bmp.Dispose();
}
This user control (CanvasControl) is called out inside my main form where user will draw something and have an option to save afterwards using a save button. The save button will call out the "PrintCanvas()" function of the UserControl.
I get the output image file as expected, but the problem is it was a blank image.
What I have tried so far:
To test that it is not a syntax issue, I tried to transfer the PrintCanvas() function into my main form and surprisingly I get an image of the whole main form on file but the UserControl is not visible there.
Is there any other setup i missed out to make a winform UserControl printable?
UPDATE: (DRAWING ROUTINES)
User control acting as canvas - code here
The code in the question gave a first hint but the code in the link showed the source of the problem: You use a 'wrong' instance of the Graphics object for drawing:
protected override void OnPaint(PaintEventArgs e)
{
// If there is an image and it has a location,
// paint it when the Form is repainted.
Graphics graphics = this.CreateGraphics();
..
This is one of the most common mistakes with winforms graphics! Never use CreateGraphics ! You always should draw onto the control surface with the Graphics object in a Paint or DrawXXX event. These events have a parameter e.Graphics which is the only one that can draw persistent graphics.
Persistent means that it will always be refreshed when necessary, not just when you trigger it. This is a nasty error because everything seems to work until you come upon a situation when an outside event makes redrawing necessary:
Minimizing and then maximizing the form
Moving it off the screen and back again
Calling DrawToBitmap
...
Note that all will only really work if you use the valid and current Graphics object from the PaintEventArgs e parameter.
So, the solution is simple:
protected override void OnPaint(PaintEventArgs e)
{
// If there is an image and it has a location,
// paint it when the Form is repainted.
Graphics graphics = e.Graphics(); // << === !!
..
But what is the CreateGraphics good for? It is only good for luring newbies into that error??
Not quite; here are some uses for it:
Drawing non-persistent graphics like a rubber-band rectangle or a special mouse cursor
Measuring text sizes without actually drawing it with a TextRenderer or the MeasureString method
Querying the screen or Bitmap resolution with Graphics.DpiX/Y
and probably some others I can't think of at the moment..
So for normal drawing onto controls always use the e.Grapahics object! You can pass it on to subroutines to make the code more structured, but do not try to cache it; it needs to be current!

C# Remove drawing from PictureBox

I have a PictureBox pic , and an Image img, pic.Image = img
and I draw some rectangles on the Image using
Graphics g = Grpahics.FromImage(pic.Image);
g.DrawRectangle(...);
But at one point, I want to remove the rectangle from the Image,I tried
pic.Image = getOriginalImage();
pic.Refresh();
but the image remains the same(Rectangles are still on top of the Image)
I know there's a method graphics.Clear(Color),but it replace the entire Image with a solid color
How do I remove the drawing only from the PictureBox?
Thanks
Edit:
I already saved the original and when I erase I use the original image
You are overwriting the original image. Save the image locally and clone it into the PictureBox.Image property. Then clone again when you want to erase
Draw the background image again using Graphics.DrawImage() or assign the image again to the Image property. Using a Graphics object in this way is writing directly to the image displayed in the PictureBox and it does not keep separate copies of what is written using a Graphics object and the background Image.

Make overlapping picturebox transparent in C#.net

I have two overlapping pictureboxes.The images of both picture boxes have some transparent pixels.I want to see the bottom picture box through the transparent pixels of the overlapping picture box.
I tried setting the background color of both picture boxes as transparent.But it just sets the back color of the picture box to the background color of the form.
Clearly you are using Winforms. Yes, transparency is simulated by drawing the pixels of the Parent. Which is the form, you only see the form pixels, stacking effects don't work. There's a KB article that shows a workaround for this. It is painful. Another approach is to not use PictureBox controls but just draw the images in the form's Paint event.
Consider WPF, it has a very different rendering model that easily supports transparency.
Solutions to that problem might be various, and it mainly depends on your skills and amount of work will depend on kind of images you're dealing with. For example if images are always same resolution, size and overlapping image supports transparency you could try to do manipulation of two Image objects and draw one over another, then display it in PictureBox. Or if you will need to do it multiple times in various places of your app you could even consider creating your own UserContriol.
Code in answer of this question, method ResizeImagein particular, show how to create resized, good quality image, all you need it is to change it a little. Make it to get two Images as input parameters, and change it to draw one image over another.
Changes might look like this
public static Bitmap CombineAndResizeTwoImages(Image image1, Image image2, int width, int height)
{
//a holder for the result
Bitmap result = new Bitmap(width, height);
//use a graphics object to draw the resized image into the bitmap
using (Graphics graphics = Graphics.FromImage(result))
{
//set the resize quality modes to high quality
graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
//draw the images into the target bitmap
graphics.DrawImage(image1, 0, 0, result.Width, result.Height);
graphics.DrawImage(image2, 0, 0, result.Width, result.Height);
}
//return the resulting bitmap
return result;
}
And use it, for example, like this:
pictureBox1.Image = CombineAndResizeTwoImages(Image.FromFile("c:\\a.png"), Image.FromFile("c:\\b.png"), 100,100);
But that its only example, and you must tune it up to your needs.
Good luck.
If it's one PictureBox inside another, you can use:
innerPictureBox.SendToBack();
innerPictureBox.Parent = outerPictureBox;

Categories