Making scribbles on a monochrome image - c#

Imagine there's a picturebox which loads a monochrome image. And there is a need to make few color scribbles on it. I have no background with graphics. Would it be just a pen drawing pixels or something more complex I don't know.
Target language is C#. Technology: WinForms.

I think the easiest way to achieve what you want would be to create a very lightweight retained mode drawing system. Keep track of all the positions where the user has scribbeled and draw dots/circles/lines/rubberducks/whatever at these positions in the PictureBox's Paint event. On mousedown+move events, call the PictureBox' Invalidate() function. The original picture must either be painted underneath or in the class' OnPaintBackground (which IMO is more elegant).
This tutorial should get you started:
https://web.archive.org/web/20121006140255/http://www.bobpowell.net/backtrack.htm

Related

C# Removing a certain line in Graphics/Drawing

Is it possible to remove some lines in my graphic panel without erasing the rest?
PanelGraphics.Clear(Color.Black); erases all the graphics but I only want to remove one line, or a certain color.
Is this possible?
Is it possible to remove some lines in my graphic panel without erasing the rest?
Not really. The Graphics does not tell you anything about the actual context, it can be the screen, a printer, a bitmap, a metafile, the surface of a control or something similar. If you draw a Panel or a control you must always re-draw the whole content once it is invalidated. Otherwise, you will get a messy result. Just try to move your window partly out of the screen, the custom-drawn content will be "erased" unless you redraw it.
However, if you have a concrete image, such as a Bitmap, you can replace its colors; however, you must know the exact PixelFormat of the image. See my answer here if you are interested: https://stackoverflow.com/a/33562891/5114784

How can I capture as bitmap only what a picturebox is displaying, without using "copy from screen"?

Specifically: I need to capture as a bitmap a specific region of what a picturebox is actually displaying. The coordinates of the region are specified by the bounds of a control that I have overlayed on top of the picturebox (but that belongs to the picturebox). The control is hidden when I make the "snapshot" of the region.
I tried using normal screen capture methods (CopyFromScreen), but you can't really control the timing there. So it was capturing "interstitial" states, like transitions between photos in my picturebox. Frequently it was only capturing purely black images (the background color of the picture box).
So I tried just converting the image (picturebox.image property) being displayed to a bitmap. The problem there is that the picture box is rarely showing exactly the image. It's displaying some PORTION of the image, scaled and clipped as appropriate to it's sizemode (which is zoom). So the I can't just take my control coordinates and clip them from the image as a whole.
So I tried to estimate what portion of the image was being displayed, and correcting my rectangle based on that. Turns out that I was basically re-creating the "zoom" code of the picturebox to do this (using aspect ratio of the picturebox, the aspect ratio of the image, guessing at what level of scaling is currently happening to the image if it's larger or smaller than the picturebox, etc). It was not pretty.
So: now I need a method of just capturing only the bitmap currently being displayed in the client area of the picturebox, including the photo and any black "letterboxing" currently being displayed around it. Anybody got one?
Remember that I can't rely on using CopyFromScreen. It's not reliable enough for my purposes. I think I need a method of getting picturebox to TELL me the bits it is displaying.
This will copy and save the currently shown content of the PictureBox including a BackgroundImage (if there is one and if it shines through) and also all Controls that belong to the PictureBox, like Labels etc.. Also included are elements drawn in the Paint event. Things drawn outside the Paint event are non-persistent and will not be included.
using (Bitmap bmp = new Bitmap(pictureBox1.ClientSize.Width,
pictureBox1.ClientSize.Height))
{
pictureBox1.DrawToBitmap(bmp, pictureBox1.ClientRectangle);
bmp.Save(yourfilename, ImageFormat.Png);
}
Note: On my test Form the PicureBox is sitting inside an AutoScroll Panel pan_PBscroll. The PictureBox is displaying pixels 1:1 and is therefore, with a photograph loaded, much bigger than the Panel, the Form or even the Screen. So to clip to the actually visible parts I could not use the pictureBox1.ClientSize and pictureBox1.ClientRectangle but used the dimensions of that Panel. This may well apply to you, too.
I'm not sure about your timing issues. But since you mentioned CopyFromScreen here are a few differences:
CopyFromScreen makes a 1:1 copy of each screen pixel
This includes non-persistent drawings and excludes anything covered or hidden
Control.DrawToBitmap makes the Control draw itself onto a Bitmap, just as it draws itself during Paint
This excludes anything that doesn't belong to the Control but includes all members of its Controls collection
This also excludes non-persistent drawings but includes the full Size of the Control, whether it fits on the Form or Screen or not and whether it is hidden or covered or not.
For Controls with active Scrollbars only the visible parts are copied. To copy all you need to resize it temporarily. Then you can get a complete image of a listbox even if it has a thousand items..
Since you're using a PictureBox I would say to take a look PictureBox.Image where you can get the Bitmap object.
Hope it helps.

Graphics FillEllipse in Picturebox save state

I create graphics thru Graphics.FillEllipse(...) which is drawn on Picturebox. After all drawing is done I would like to save current state of Picturebox with points drawn. Can someone point me to right direction, or what is the best approach to achieve desired functionality?
Thanks in advance ;)
Windows Forms painting on controls (including of course PictureBox) is immediate mode drawing. Whatever you are drawing must be repainted in some event handler, or it is lost on the next repaint. Typically the Control.Paint event. Perhaps you should move the drawing logic into some method that takes a Graphics instance as a parameter. When you want to draw to a bitmap, for example, you can create a graphics object from the bitmap using Graphics.FromImage(...) and pass it to the painting method. Whatever you "paint" in the bitmap stays in the bitmap: no need to repaint. Then you can save or do whatever you want with the bitmap.
See immediate versus retained mode:
http://msdn.microsoft.com/en-us/library/windows/desktop/ff684178%28v=vs.85%29.aspx

c# winform drawn image flashing

I have a image drawn in an winform app and i designed a brush that moves after the cursor. The Brush is drawn every time so the image keeps flashing because the image is also redrawn . How can i avoid this ?
Regards,
Alex Badescu
Use double-buffering. Draw each frame to some kind of memory bitmap representing the back buffer and once it's drawn show it on the first.
For more info read here:
http://msdn.microsoft.com/en-us/library/b367a457.aspx
Simply set the form's DoubleBuffered property to true. That should solve the flickering.
No reason to make it more advanced than this, in such a simple scenario.

Creating Overlay Control in winforms

I am using c# winforms to show an Image. The displaying of the image is done using a user control. Now I want to provide the user to draw lines, put other small images, write text etc over the image on an overlay control. How can I provide this functionality? If I use another user control to show the overlay control with transparent back, will that work?? any other solution will be welcome.
You might try approaching this with a canvas (Panel) that handles painting the image as the background and all the annotations/markup afterwards. This will make the foreground appear to be transparent. I expect you'll want to set Control.DoubleBuffer for performance.
You might experiment with setting the style ControlStyles.AllPaintingInWmPaint. Also, try overriding Control.OnPaintBackground and do nothing, and override Control.OnPaint and do all your painting inside there.
If performance is still unacceptable, pay close attention to the PaintEventArgs.ClipRect property. This is the only area you need to paint. The trick is figuring out which of your annotations/overlays intersect with this rectangle and painting them in the correct order.
Either this canvas or a higher level control will need to track mouse movement so you know where to draw the lines, paste images, etc.

Categories

Resources