I have a RichTextBox that is a letterbox view of a long set of data. This means I have the vertical scroll bar to move what I see up and down. What I am trying to do is save the whole data as a bitmap even that not visible in the control. I can save the control as a bitmap but that is only part of the data.
Code to save control is borrowed from someone else which does indeed save the control view (thanks to whoever wrote it):
private void btn_SaveBitmap_Click(object sender, EventArgs e)
{
SaveControlToBitmap(rchtxtbx_braille, "MyBitmap.bmp");
}
public void SaveControlToBitmap(Control control, string fileName)
{
//Get graphics from the control
Graphics g = control.CreateGraphics();
Bitmap bitmap = new Bitmap(control.Width, control.Height);
control.DrawToBitmap(bitmap, new Rectangle(0, 0, control.Width, control.Height));
bitmap.Save(fileName);
bitmap.Dispose();
}
This bitmap does not contain the data that is not visible in the control. I think somehow I need to find the start of the data and the end and turn that into a bitmap rather than turning the control itself into a bitmap but I am probably wrong. How can I do this please?
I have my laptops display set to 125% and this in itself may cause some issue. Please ask if this is not clear and I will try explain different way.
Related
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()..
I am trying to update the image by drawing circles every time mouse pointer is moved. The pixelBuffer is stored in map object and updated with CircleFilledWithGradientMethod(). I load the pixel buffer in to WriteableBitmap Bitmap and then try to display it by setting image source of an image element in my XAML UI to Bitmap. What happens, is that when I first move my mouse, I see the very first 2 circles drawn but then as I move the mouse, the image does not get updated. Why could that be? Is there a method I should call on Image to force it to redraw? The reason I use stream.WriteAsync two times, when I could have just used it one, is just to show that it is working properly.
private async void TextArea_PointerMoved(object sender, PointerRoutedEventArgs e)
{
Pixel pixel1 = new Pixel(255, 0, 0);
Pixel pixel2 = new Pixel(255, 255, 255);
map.CircleFilledWithGradient((int) pointer.Position.X, (int)pointer.Position.Y, 100, pixel1, pixel2);
using (Stream stream = Bitmap.PixelBuffer.AsStream())
{
stream.WriteAsync(map.pixelData, 0, map.pixelData.Length);
}
map.CircleFilledWithGradient((int)pointer.Position.X+100, (int)pointer.Position.Y, 100, pixel1, pixel2);
using (Stream stream = Bitmap.PixelBuffer.AsStream())
{
stream.WriteAsync(map.pixelData, 0, map.pixelData.Length);
}
this.Image.Source = Bitmap;
}
What I think is happening, is that as soon as I draw the image on the screen, it caches it, and then keeps using the old image. Or is it that the standard Image element does not support redrawing?
Update:
My Bitmap was a private class variable. If I do
WriteableBitmap Bitmap = new WriteableBitmap((int)this.ActualWidth, (int)this.Grid.RowDefinitions[1].ActualHeight);
It all starts to work, but isn't that memory inefficient? Aren't I allocating memory for each new WriteableBitmap each time I move my mouse. And as I have found out, the issue is definitely with with Image component. Why wouldn't it update when I just make changes to it's source, but updates when I change its source to a different object.
`
Is there a method I should call on Image to force it to redraw?
Close. There's a method on WriteableBitmap.
Call WriteableBitmap.Invalidate after you update it to request the refresh.
Assuming the Bitmap was already set as Image.Source, replace the line:
this.Image.Source = Bitmap;
With:
Bitmap.Invalidate();
Why wouldn't it update when I just make changes to its source, but updates when I change its source to a different object.
Setting the Image.Source to the same thing it's already set to is a noop. Most complex Properties ignore "changes" which don't change the existing value. Creating a new WriteableBitmap each time works (very inefficiently) because it's different.
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!
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.
I'm currently writing a little paint application where the user is able to draw on a Panel. I am working on the select tool and want to be able to select a certain area of the Panel, and then paste this selected area directly into a PictureBox that I have just to the right of the Panel.
My problem is that my code at the moment is not working correctly, when I try to paste the Bitmap that I am creating from the panel I am getting a big red X in the PictureBox instead of the actual image. I know that the image is copying to the Bitmap correctly because I tried putting some code around it to save it to disk as a jpeg and then look at the image, and it is all displaying fine.
Here is my code:
private void tbCopy_Click(object sender, EventArgs e)
{
int width = selectList[0].getEnd().X - selectList[0].getInitial().X;
int height = selectList[0].getEnd().Y - selectList[0].getInitial().Y;
using (Bitmap bmp = new Bitmap(width, height))
{
pnlDraw.DrawToBitmap(bmp, new System.Drawing.Rectangle(
selectList[0].getInitial().X,
selectList[0].getInitial().Y,
width, height));
pbPasteBox.Image = bmp;
}
}
the width and height are just the dimensions of the area that I want to copy, and selectList is a List that contains one object which contains the coordinates of the area I want to copy.
Any help would be greatly appreciated.
Your problem is the using(){} when the code inside the using braces has completed the object inside the () is disposed of as it is deemed no longer needed.
Simply removing the brace to just have Bitmap bmp = new Bitmap(width, height) should solve your problem