Actually i am wondering to erase an image to transparency. like i have an image on page background and another image above that. Now i want that if i erase above image by finger then lower image should be appear, simply means to say image will become transparent.i'm doing something like this but its not meet my requirements.
Your suggestions are Welcome :)
private void Canvas_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
currentPoint = e.GetPosition(this.canvas);
//Initialize line according to currentpoint position.
Line line = new Line()
{
X1 = currentPoint.X,
Y1 = currentPoint.Y,
X2 = oldPoint.X,
Y2 =oldPoint.Y
};
line.StrokeDashCap = PenLineCap.Round;
line.StrokeEndLineCap = PenLineCap.Round;
line.StrokeLineJoin = PenLineJoin.Round;
line.StrokeThickness = 20;
line.Stroke = new SolidColorBrush(Colors.Black) ;
////////////////////////////////
//Set color & thickness of line.
//Line add in canvas children to draw image & assign oldpoint.
this.canvas.Children.Add(line);
oldPoint = currentPoint;
}
You can do it with 3 different ways:
Using opaque overlay and UIElement.Clip property. But you need to deal with Geometry. And I'm afraid it will be very CPU cost.
Using WriteableBitmap and changing an alpha channel of image. You can do it using WriteableBitmapEx.
Using opaque overlay and UIElement.OpacityMask property. I think it's the best way to accomplish that, as you're not limited to use bitmap (so you can place any XAML control below overlay) as in the second way.
Related
I've seen few questions about this problem, I tried every solution but none of them worked for my case.
My code is working; this image shows what happens when I click on Draw button.
I need to zoom on that drawing.Is it possible to code something like autocad feature "zoom/extent"?
Pen myPen = new Pen(Color.Black);
int centerpointx, centerpointy;
private void pictureBoxDraw_Paint(object sender, PaintEventArgs e)
{
centerpointx = pictureBoxDraw.Size.Width/2;
centerpointy = pictureBoxDraw.Size.Height/2;
myPen.Width = 2;
if (binary > 0)
{
var sizecrestgeo = 40;
var distancearraycrestgeo = new float[sizecrestgeo];
var elevationarraycrestgeo = new float[sizecrestgeo];
for (int i = 0; i < sizecrestgeo; i++)
{
distancearraycrestgeo[i] = float.Parse(dataGridViewCrestGeo.Rows[i].Cells[0].Value.ToString());
elevationarraycrestgeo[i] = float.Parse(dataGridViewCrestGeo.Rows[i].Cells[1].Value.ToString())*-1;
}
for (int i=0; i < sizecrestgeo-1; i++)
{
e.Graphics.DrawLine(myPen, distancearraycrestgeo[i]+centerpointx, elevationarraycrestgeo[i]+centerpointy, distancearraycrestgeo[i + 1]+centerpointx, elevationarraycrestgeo[i + 1]+centerpointy);
}
}
else
{
}
}
private void buttonDraw_Click_1(object sender, EventArgs e)
{
if (Hd > 0.0001)
{
binary = 1;
pictureBoxDraw.Invalidate();
}
else
{
MessageBox.Show("No data to draw, perform analysis first.");
}
}
private void buttoncleardraw_Click(object sender, EventArgs e)
{
binary = 0;
pictureBoxDraw.Invalidate();
}
}
This is not so hard, provided you know all the puzzle pieces.
Let's start with the obvious one:
You can scale the Graphics object to create zoomed graphics with ScaleTransform.
As I mentioned, this will include the widths of pens, font sizes and also any images you draw (though not the hatches of a HatchBrush).
You also asked about keeping the drawing 'centered'. This is a non-obvious concept: Just what is the center of your drawing surface??
When zooming (just like rotating) you always need to know the center point of the zoom (or the rotation.) By default this is the origin (0,0). I chose the center of the Panel. You may want to pick some other point..
Once you do you can move the origin of the graphics viewport to this point with TranslateTransform.
Once you have achieved all this you almost certainly will want to allow scrolling.
To do so you have two options:
You can keep AutoScroll = false and nest the canvas control inside another control, usually a Panel, which has AutoScroll = true; next make the canvas control big enough to always hold your drawing and you're done.
Or you can turn on AutoScroll for the canvas control and also set a large enough AutoScrollMinSize. If you then add the current scrolling position to the translation you are also done. Let's see this solution in action:
This is the code in the Paint event:
Size sz = panel3.ClientSize;
Point center = new Point(sz.Width / 2, sz.Height / 2);
Graphics g = e.Graphics;
// center point for testing only!
g.DrawEllipse(Pens.Orange, center.X - 3, center.Y - 3, 6, 6);
// you determine the value of the zooming!
float zoom = (trackBar1.Value+1) / 3f;
// move the scrolled center to the origon
g.TranslateTransform(center.X + panel3.AutoScrollPosition.X,
center.Y + panel3.AutoScrollPosition.Y);
// scale the graphics
g.ScaleTransform(zoom, zoom);
// draw some stuff..
using(Pen pen = new Pen(Color.Yellow, 0.1f))
for (int i = -100; i < 100; i+= 10)
g.DrawEllipse(Pens.Yellow, i-22,i-22,44,44);
A few notes:
I draw an orange circle in the center to show this point is invariant.
My coordinates go from the negative to the positive so you can see that this works nicely.
I draw with a tiny pen width; so the width of the drawing only changes once the resulting pen goes over 1 pixel. Anything draw will always be draw with 1 pxiel width, though.
I first translate and then scale so I don't have to calculate scaled poitions.
The only line in the TrackBar's Scroll event is to trigger the Paint event: panel3.Invalidate();
The only settings needed for the Panel are
panel3.AutoScroll = true;
panel3.AutoScrollMinSize = new Size(500, 500); // use the size you want to allow!
However to avoid flicker it is highly recommended to use a DoubleBuffered control, maybe a Panel subclass like this:
class DrawPanel : Panel
{
public DrawPanel() { DoubleBuffered = true; }
}
Update: Instead of a Panel, which is a Container control and not really meant to draw onto you can use a Picturebox or a Label (with Autosize=false); both have the DoubleBuffered property turned on out of the box and support drawing better than Panels do.
Graphics.ScaleTransform() is how you can zoom. Try using something like this inside your paint event handler:
e.Graphics.ScaleTransform(2.0F, 2.0F);
I want to create 2 transparent overlays for pictureBox in WinFrom application so I can separately draw on both and I can also clear it when I want to blank transparent overlay.
On one overlay I draw rectangles. I want these rectangles there all time.
On second overlay I draw circles but I just want to draw 1 circle and after user input clear this circle and draw another.
For now I'm using
var transparentOverlay = pictureBox.createGraphics();
But I don't know how to clear an overlay to blank transparent graphics.
I tried
transparentOverlay.Clear(Color.Transparent) which turned all overlay to black
pictureBox.Invalidate() which cleared all graphics from both overlays so my rectangles remain where they were
use some backup graphics which I created before any drawing and clear my overlay by assigning this graphics to it transparentOverlay = transparentOverlayBackup but this did nothing, all rectangles and all circles remain at their places
Is there a way to create clearable transparent graphics sticked to pictureBox?
EDIT:
I have a picture with text in that picture box. And what I want to do is to draw rectangles around words of the text and this rectangles should remain all the time over the picture.
Than I want to draw a single circle and wait for user to click on a screen. This is all ok but when user click on a screen, I want to clear that circle and draw another.
//this method I call by click on a button to start annotation
private void ExpertAnnotate(object sender, EventArgs e)
{
var pen = new Pen(Color.Black, 1);
if (!annotationIsRunning) //check if annotation is in process or not
{
annotationIsRunning = true;
annotationOverlay = pictureBox.CreateGraphics(); //create transparent overlay for drawing
//draw rectangles around all words in text (AOIs)
annotationAOIs.ForEach(a =>
{
annotationOverlay.DrawRectangle(pen, a.Start.X, a.Start.Y, (a.End.X - a.Start.X), (a.End.Y - a.Start.Y));
});
//subscribe mouseMove and mouseClick events on pictureBox
pictureBox.MouseMove += HighlightAOI;
pictureBox.MouseClick += SelectAOI;
}
//define brushes for drawing circles (fixations)
var brush = new SolidBrush(Color.FromArgb(128, Color.BlueViolet));
var dotBrush = new SolidBrush(Color.DarkBlue);
pen.Color = Color.Blue;
long sizeOfFixation;
var f = Fixations[fixationCounter - 1]; //get current fixation to draw
sizeOfFixation = (int)f.Length / FIX_SIZE_COEFICIENT; //compute size of circle
annotationOverlay.FillEllipse(dotBrush, f.PosX - 1, f.PosY - 1, 3, 3);
//draw fixation on overlay
annotationOverlay.FillEllipse(brush, (f.PosX - sizeOfFixation), (f.PosY - sizeOfFixation), sizeOfFixation * 2, sizeOfFixation * 2);
}
//eventHandler for mouseMove - this method color rectangle over which mouse hover to red border
private void HighlightAOI(object sender, EventArgs e)
{
//this just draw last highlighted rect to black when we not yet hover mouse above it
if (lastHighlightedAOI != null)
{
annotationOverlay.DrawRectangle(new Pen(Color.Black, 1), lastHighlightedAOI.Start.X, lastHighlightedAOI.Start.Y, (lastHighlightedAOI.End.X - lastHighlightedAOI.Start.X), (lastHighlightedAOI.End.Y - lastHighlightedAOI.Start.Y));
}
//get position of mouse sursor
var x = pictureBox.PointToClient(Cursor.Position).X;
var y = pictureBox.PointToClient(Cursor.Position).Y;
var tempFix = new Fixation() { PosX = x, PosY = y };
//get rectangle over which mouse hover
lastHighlightedAOI = tempFix.LiesIn(annotationAOIs).FirstOrDefault();
if (lastHighlightedAOI != null)
{
//highlight rectangle by painting red border
annotationOverlay.DrawRectangle(new Pen(Color.Red, 1), lastHighlightedAOI.Start.X, lastHighlightedAOI.Start.Y, (lastHighlightedAOI.End.X - lastHighlightedAOI.Start.X), (lastHighlightedAOI.End.Y - lastHighlightedAOI.Start.Y));
}
}
//eventHandler for mouse click
private void SelectAOI(object sender, EventArgs e)
{
//get position of cursor
var x = MousePosition.X;
var y = MousePosition.Y;
var tempFix = new Fixation() { PosX = x, PosY = y };
//get rectangle which we selected by a mouse click
var aoi = tempFix.LiesIn(annotationAOIs).FirstOrDefault();
//assign last shown fixation to selected rectangle
if (aoi != null)
{
aoi.AssignedFixations.Add(Fixations[fixationCounter - 1]);
}
//if it wasn't last fixation again call ExpertAnnotation function to draw another Fixation over image (!!! here I need to clear last drawn fixation (circle) disappear and draw next fixation in ExpertAnnotate method)
if (fixationCounter != Fixations.Count)
{
ExpertAnnotate(sender, e);
}
else
{
TerminateExpertAnnotation("regular");
}
}
Thanks to #Reza Aghaei who guided me in chat to solution.
For me acceptable solution was in building multilayer image and assigning it to pictureBox.Image attribute.
I built image by loading image from file:
Image im = new Bitmap(path); // loads image from file
Then create graphics from this image:
var g = Graphics.FromImage(im); // creates graphics from loaded image
Draw all needed rectangles to this image and backup this image to some global Image instance:
var pen = new Pen(Color.Black, 1);
// draws all rectangles on the image
annotationAOIs.ForEach(a =>
{
g.DrawRectangle(pen, a.Start.X, a.Start.Y, (a.End.X - a.Start.X), (a.End.Y - a.Start.Y));
});
g.Dispose(); // disposes used graphics
ImageBackup = new Bitmap(im); // backup image with rectangles
In above part I created a static part of an image, which will not change and I backed it up so next time I will just create new Image instance from backup without any rectangle drawing.
Then when I want to show up new circle over this image I just:
var image = new Bitmap(ImageBackup); // creates new instance of image with rectangles from backup
var g = Graphics.FromImage(image); // creates graphics from image
// in this part draw circle at specific point
var f = Fixations[fixationIndex];
sizeOfFixation = (int)f.Length / FIX_SIZE_COEFICIENT;
g.FillEllipse(dotBrush, f.PosX - 1, f.PosY - 1, 3, 3);
g.FillEllipse(brush, (f.PosX - sizeOfFixation), (f.PosY - sizeOfFixation), sizeOfFixation * 2, sizeOfFixation * 2);
pictureBox.Image.Dispose(); // dispose old pictureBox image
pictureBox.Image = image; // set new image
imageOverlay = pictureBox.CreateGraphics(); // get transparent graphics overlay for pictureBox so we can draw anything else over picture (in my case highlighting rectangles over which I hover a mouse)
g.Dispose(); // dispose used graphics
Your best approach would be to use the OnPaint event handler for the PictureBox control and place all your drawing calls in there.
You can use the Graphics object passed to the event handler to get the surface you want to draw on (i.e. the Picture box) and then use the various methods to draw the shapes that you are after.
To draw a 'transparent' shape simply draw an outline rather than a filled shape.
I wrote a little Program that should display a Ellipse at the exact mouse position. The Problem is that, the way Iam doing it right now , The Mouse and Ellipse Position are only exact at the center of the Screen. If I put the mouse further away to the windowborder they drift further and further away.
I use the MouseOver Element to Update the Mouse Position.
Here is my code:
private void Window_MouseMove(object sender, MouseEventArgs e)
{
Main_Grid.Children.Clear();
MousePos_Ellipse = new Ellipse();
Point MousePos_Point = new Point();
MousePos_Point = Mouse.GetPosition(Main_Grid);
Main_Grid.Children.Remove(MousePos_Ellipse);
SolidColorBrush mySolidColorBrush = new SolidColorBrush();
mySolidColorBrush.Color = Color.FromArgb(55, 255, 255, 0);
MousePos_Ellipse.Fill = mySolidColorBrush;
MousePos_Ellipse.StrokeThickness = 2;
MousePos_Ellipse.Stroke = Brushes.Black;
// Set the width and height of the Ellipse.
MousePos_Ellipse.Width = 15;
MousePos_Ellipse.Height = 15;
// At this Point I do my Positioning
MousePos_Ellipse.Margin = new Thickness(left: MousePos_Point.X - ( Main_Grid.ActualWidth / 2) , top: MousePos_Point.Y - ( Main_Grid.ActualHeight / 2 ), right: 0 , bottom: 0);
//base.AddVisualChild(_circle);
// Add the Ellipse to the Grid
Main_Grid.Children.Add(MousePos_Ellipse);
}
I propose to use a Canvas instead of a grid.
With a canvas you can simply set the ellipse position like that:
Canvas.SetLeft(MousePos_Ellipse, MousePos_Point.X);
Canvas.SetTop(MousePos_Ellipse, MousePos_Point.Y);
The Grid control will do automatic positioning and sizing of child elements and is therefore not so suitable for your goal.
Disclaimer; while the answers above will fix your issue, the actual question is not properly resolved. The problem you are facing derives from your interpretation of the issue compared to how the computer sees it.
The position of your cursor relative to the grid is not the same as the position relative to your screen (i.e. different resolutions return different values). This is why our x and y values will be further off the further you get off center. You could fix this by defining that you want your X and Y position relative to the form, f.ex, like so:
var relativePoint = this.PointToClient(Cursor.Position);
The noticable difference here is that here, we Point to the client, and therefore get the Cursor's relative position within the form.
Using a standard Label I aligned my image to the right side.
However there is a small indent (marked in red) that I cannot remove.
So my question: Is there an easy way to correctly align/snap an image to the right edge of a label? Or do I need to edit the label paint method so I can manually draw the image?
The label in question sits inside a "Panel", the following is my code:
label1.BackColor = System.Drawing.Color.Red;
label1.Image = global::TestProject.Properties.Resources.Header;
label1.ImageAlign = System.Drawing.ContentAlignment.MiddleRight;
label1.Size = new System.Drawing.Size(200, 40);
The simple answer appears to be: No there is no easy way to correctly align the image.
The "PictureBox" seems like the preferred component for working with images, however the image can be correctly aligned by editing the paint method of the label:
label1.Paint += new System.Windows.Forms.PaintEventHandler(this.label1_Paint);
And the paint method:
private void label1_Paint(object sender, PaintEventArgs e)
{
Image image = global::TestProject.Properties.Resources.Header;
Graphics g = e.Graphics;
//Align to far right: label width - image width
g.DrawImage(image, this.label1.Width - image.Width, 0);
}
Drawing a polygon according to the input coordinates
i got some code from here, i just take..
void pictureBox1_Paint(object sender, PaintEventArgs e) {
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
List<Point> polyPoints = new List<Point>();
polyPoints.Add(new Point(30, 30));
polyPoints.Add(new Point(36, 105));
polyPoints.Add(new Point(66, 105));
polyPoints.Add(new Point(72, 66));
using (SolidBrush br = new SolidBrush(Color.FromArgb(100, Color.Yellow)))
{
e.Graphics.FillPolygon(br, polyPoints.ToArray());
}
e.Graphics.DrawPolygon(Pens.DarkBlue, polyPoints.ToArray());
}
note : SmoothingMode use header using System.Drawing.Drawing2D
then i got problem about click area, i just want the click area at the visible area, in this case the picturebox1 have size 1366 x 768
this is example of picturebox, i want the red area be clickable and the gray is not clickable area
by default all area in the box is clickable
Have you looked at the Documentation on PictureBox?
I'm looking at it and it seems there's many ways of resizing aspects of the PixtureBox object. Take a look at using the DefaultSize Property or setting the Size property. In either case, you have to wrap the size in a Size object and set the according PictureBox size property.
Such as:
pictureBox1.Size = new Size(xSize, ySize);
or
pictureBox1.DefaultSize = new Size(xSize, ySize);