In C# i have created a function to draw a triangle between a rich-textbox and a RectangleShape object.
below is what i wrote.
Graphics Pointer = this.CreateGraphics();
Pointer.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
Pointer.FillPolygon(new SolidBrush(Color.White), GetTriangle(this.FetchRectangle));
Pointer.Dispose();
The gettriangle() function returns an array of points(3 vertices of the triangle.) But when i try running the pgm, the form's background (which is set to black color) now takes a blurred and distorted background image of wat is shown in the computer screen.
How can i get the triangle image without distorting the form background?
this problem is cause due to http://en.wikipedia.org/wiki/Vertical_blanking_interval
The solution is double buffering. and waiting Vertical retrace. I couldn't find example how to do htis but this is the way to go
see:
http://social.msdn.microsoft.com/Forums/vstudio/en-US/9f07dec1-1b04-419c-b604-44fd74027161/windows-forms-double-buffering-?forum=csharpgeneral
Related
I am using a C# console application project to generate raster frames and then uses
ffmpeg tool to generate the video from those frames. I am using a graphical object g to draw a bmp object and save it to
generate
the frame(s) [The rate of saving is 25 frame per second]. I implemented drawing[writing] on the graphical object fine, erasing
"ON WHITE BACKGROUND", clearing the graphical object very well,
undoing drawn shapes perfectly. 4) I attempted to set background and
import images and that worked so very well as you can write on the
graphical object [whether white paper, background image, imported
image...etc]
The problem that when I attempt to erase portion of the image which has a background [background image, for example lines,
graphical, coordinates..etc]. the graphical object erases the
portion of the image where the stroke of the erase [white color
overlaps]. Sure This [white colors for erasing strokes ] was working
fine with white page background.
I am kind of thinking out loud, logically an it makes perfect sense that the white stroke erasers will mark on the non-white
backgrounds [so it looks as the eraser erased the background].
Is there (a) way(s), mechanism, overlay algorithm, coloring mechanism :) to make show the background image parts under the erasing-strokes' points as it is, non distorted. For example,:
1) Placing the background image on the first layer
2) Perform the drawing on the top layer
3) When erasing [on the top layer], use a transparent color, or stroke mechanism to show the background image-portions' that was/were overlapped before with the background......Is that possible??
Thanks for your help and input in advance.
Note that you may not have the perfect solution. But your thoughts are appreciated.
Resolution:
Masking the original image (source image with all my shapes' drawing) and drawing it on a different destination bmp:
public static Image CropToPath(Image srcImage, List<Point> Points, Pen p, Bitmap bmp)
{
Bitmap mask = bmp;//new Bitmap(Bitmap.FromFile( (new DirectoryInfo(outPutPath)).GetFiles()?.OrderByDescending( f => f.CreationTimeUtc).First()?.FullName));
DrawPoints(Graphics.FromImage(mask), p, Points);
using (var imgattr = new ImageAttributes())
{
// set color key to Line
imgattr.SetColorKey(Color.Gainsboro, Color.Gainsboro);
// Draw non-line portions of mask onto original
using (var g3 = Graphics.FromImage(srcImage))
{
SmoothGraphic(g3).DrawImage(
mask,
new Rectangle(0, 0, srcImage.Width, srcImage.Height),
0, 0, srcImage.Width, srcImage.Height,
GraphicsUnit.Pixel, imgattr
);
return srcImage;
}
}
}
I hope you can help me with this problem, attached videos to explain in a simpler way.
First example
Panel (has a textured background) with labels (the labels have a png image without background)
Events: MouseDown, MouseUp and MouseMove.
As you will notice in the video to drag the label the background turns white panel and regains its background image when I stop dragging the label
Panel controls have a transparent background as property, but changing the background with any color, let the problem occurred related to the substance, I do not understand why this happens and how to fix less.
Second Example
Contains the above, with the only difference that the panel controls instead of having transparent background, I chose black color for that property
You have to use double buffer and you don't have to stop using an image on the background, you can have everything running smoothly.
You have a couple of ways to do this, the fast way (not enough most of the time) is to enable doublebuffer of the panel.
The "slow" but better way is to do your own Double Buffer using a Bitmap object as a buffer.
This example creates a "side buffer" and accepts an image as parameter and draws it using created buffer.
public void DrawSomething(Graphics graphics, Bitmap yourimage)
{
Graphics g;
Bitmap buffer = new Bitmap(yourimage.Width, yourimage.Height, graphics);
g = Graphics.FromImage(buffer);
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.DrawImage(yourimage, 0, 0);
graphics.DrawImage(buffer, 0, 0);
g.Dispose();
}
Call this on your OnPaint event.
BTW... this is just a double buffer example.
Cheers
Change DoubleBuffered to true for both form and panel. I think that should solve your problem.
this is totally normal, because System.Windows.Forms.Control based items were not designed to do this kind of advanced Graphics operations.
in fact the reason that this effect happens here, is that when you assign any value other than 255 to the alpha component of a control BackColor, the form does the following when you change the control size or position:
it sets the new control position
it redraws the parent control
it gets the background of the control's parent as an image
it draws acquired image into the control body to seem as if the control is transparent
the control body gets drawn on top of the previously drawn background
the control children are drawn
* this is is a simplified explanation for the sake of illustration to deliver the idea
steps 1, 2 are responsible for the flickering effect that you see.
but you have two ways to solve this,
-the first is some kinda advanced solution but it's very powerful, which is you would have to create a double buffered custom control that would be your viewport.
the second is to use WPF instead of windows forms, as WPF was designed exactly to do this kind of things.
if you can kindly provide some code, i can show you how to do both.
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;
This is the high level problem I'm trying to solve...
I have a 3rd party plotting/graphing (IoComp Plot), and I want to embed a high quality (at least 600 dpi) bitmap of the Plot control in reports created by another 3rd party report package (Combit List & Label).
This is the approach that seems most promising so far...
---Edit---:
After trying many other approachs, the only one that I think I can make work is to create a hidden instance of the Plot control, with everything scaled up to printer size (approx 5 times screen size). That includes width and height, font sizes, line widths - every visible component of the control. Yuck!
------
I can get a Graphics object of the proper resolution from the plot control's PrintPage event, but converting it to a Bitmap so the report package will be happy is proving to be the major stumbling block. Several hours of searching has led to other people who asked the same question, but no viable answers.
The only promising lead I've found suggested using one of the Bitmap constructors, which takes a Graphics instance as a parameter.
However, it's not working for me. It creates Bitmap, but with no content from the Plot control - it is a pure black image.
Here's my code (edited to show drawing of red line to Graphics object):
void PrintDocument_PrintPage(object sender, PrintPageEventArgs e)
{
// Draw a red line on the Graphics object. When printed, this
// line is shown as part of the normal Plot graphics.
Pen myPen;
myPen = new Pen(Color.Red);
e.Graphics.DrawLine(myPen, 0, 0, 200, 200);
myPen.Dispose();
// Create a bitmap from the Graphics object
Bitmap bm = new Bitmap(1000, 1000, e.Graphics);
// Save to disk
// DOES NOT WORK - CREATES FILE THAT IS PURE BLACK (VIEWED
// WITH "PAINT" PROGRAM)
bm.Save(#"C:\Bicw_Dev\Bic.Net\FrontEnd\GraphicsToBmp.bmp", ImageFormat.Bmp);
bm.Dispose();
}
Can anyone suggest why this doesn't work? Is this even a valid approach?
Also, please note:
As far as I can determine (and I've spent quite a bit of time looking) there is no way to get a high resolution, print quality Bitmap from the Plot control directly!
I stress this because several others who asked the question got code samples in response that solved the opposite problem - converting a Bitmap to a Graphics.
I need to convert a Graphics object to a Bitmap object.
And if anyone can suggest an alternate approach that allows me to get a print quality image of my plots into my reports, please feel free. (For example, I can get a low quality (72 bpi) Bitmap from the Plot control, and have considered trying to stretch it - but I've never seen that approach work well in other applications).
Thanks,
-Tom Bushell
Edit in response to comment:
As an experiment, I added the following:
Pen myPen;
myPen = new Pen(Color.Red);
e.Graphics.DrawLine(myPen, 0, 0, 200, 200);
myPen.Dispose();
This caused a red line to be drawn over the plot graphics when I printed my plot. But it had no effect on the Bitmap - it's still pure black.
However, it's not working for me. It
creates Bitmap, but with no content
from the Plot control - it is a pure
black image.
Well you never do paint to the graphics, what do you expect?
You are suppose to do the actual drawing for the output in that event.
The constructor you're using does not copy any graphics, only sets the resolution equal to the graphics resolution. See msdn. As Leppie points out, you have to actually draw something to the bitmap. I suggest getting another graphics object for the item you just created.
Graphics g = Graphics.FromImage(bmp);
//Make the background white
g.FillRectangle(Brushes.White, 0, 0, 1000, 1000);
It is not easy to control the DPI in the Print(Preview) system.
But maybe you are going about it the wrong way. What you want is to create a (large) bitmap and then 'trick' the control in to using that bitmap as if it was the screen. See this list of links.
No need for PrintDocument.
I am using FillPolygon with a semi-transparent color to draw a triangle (an arrow pointer). I have noticed that FillPolygon gives awkward results with an isocel triangle. One of the sides is overlapping DrawPolygon's side, while the two others aren't. I would have expected none or all, but not something in between.
Here's a sample: DrawPolygon uses a semi-transparent red, while FillPolygon uses a semi-transparent green. You can see one side is brown, the two other sides are red.
alt text http://www.slimcode.com/downloads/arrow.png
The coordinates for this example are: {X=36,Y=201}, {X=42,Y=207}, {X=30,Y=207}.
Using an opaque color would solve everything as I could call both DrawPolygon and FillPolygon, but I need to use a semi-transparent color. I'm drawing into an image if it can make a difference.
You want use a bitmap and do something like this. Note this is not runnable code.
Dim image As New Bitmap(<my_Xsize>, <my_Ysize>)
Dim gr As Graphics = Graphics.FromImage(image)
<Draw your FillPolygon>
<Erase the leftside of the polygon>
<Draw your Polygon>
gr.DrawImage(image, <myXcoor>, <myYcoor>)
By using a bitmap you can fiddle down to the pixel level to get the exact thing you want.
Hack: Draw the whole arrow as opaque in an intermediate buffer, then draw the whole buffer onto your image using the appropriate transparency.