How can I get the color of a pixel at the location of the cursor? I know how to get the mouses position using MousePosition but I can not figure out how to get the pixel color at that location. I write the code put I have no result when run
private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
{
s= pictureBox1.PointToClient(Cursor.Position);
bitmap.SetPixel(s.X / 40, s.Y / 40, Color.Red);
}
It is easier to use the e.Location point in the parameter of the Mouseclick event:
Color c = ( (Bitmap)pictureBox1.Image).GetPixel(e.X, e.Y);
This assumes that indeed the bitmap is in the PicturBox's Image, not painted on top of the Control..
Make sure the event is actually hooked up!
To set a clicked pixel to, say red, you would get the Bitmap from the PB's Image and set the pixels, then move the Bitmap back in::
Bitmap bmp = (Bitmap)pictureBox1.Image;
bmp.SetPixel(e.X, e.Y, Color.Red);
pictureBox1.Image = bmp;
also in the MouseClick event.
If you want to get a larger mark you should use the Graphics methods, maybe like this:
using (Graphics G = Graphics.FromImage(pictureBox1.Image))
{
G.DrawEllipse(Pens.Red, e.X - 3, e.Y - 3, 6, 6);
}
Update: To combine getting and setting you could write:
Bitmap bmp = (Bitmap)pictureBox1.Image;
Color target = Color.FromArgb(255, 255, 255, 255);
Color c == bmp .GetPixel(e.X, e.Y);
if (c == target )
{
bmp.SetPixel(e.X, e.Y, Color.Red);
pictureBox1.Image = bmp;
}
else MessageBox.Show("Click only on white spots! You have hit " + c.ToString(),
"Wrong spot! ");
Related
I am developing an application for image processing. To zoom the image, I enlarge PictureBox. But after enlarging I get below image as result.
But I want result like below image
Here is my Code :
picturebox1.Size = new Size((int)(height * zoomfactor), (int)
(width* zoomfactor));
this.picturebox1.Refresh();
The PictureBox by itself will always create a nice and smooth version.
To create the effect you want you need to draw zoomed versions yourself. In doing this you need to set the
Graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
Then no blurring will happen..
Example:
private void trackBar1_Scroll(object sender, EventArgs e)
{
Bitmap bmp = (Bitmap)pictureBox1.Image;
Size sz = bmp.Size;
Bitmap zoomed = (Bitmap)pictureBox2.Image;
if (zoomed != null) zoomed.Dispose();
float zoom = (float)(trackBar1.Value / 4f + 1);
zoomed = new Bitmap((int)(sz.Width * zoom), (int)(sz.Height * zoom));
using (Graphics g = Graphics.FromImage(zoomed))
{
if (cbx_interpol.Checked) g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.PixelOffsetMode = PixelOffsetMode.Half;
g.DrawImage(bmp, new Rectangle( Point.Empty, zoomed.Size) );
}
pictureBox2.Image = zoomed;
}
Of course you need to avoid setting the PBox to Sizemode Zoom or Stretch!
private void timer1_Tick(object sender, EventArgs e)
{
counter--;
DrawLetter();
if (counter == 0)
{
t.Stop();
TakeScreenShot();
}
}
private void DrawLetter()
{
var letter = counter.ToString();
Graphics g = Graphics.FromHdc(GetDC(IntPtr.Zero));
float width = ((float)this.ClientRectangle.Width);
float height = ((float)this.ClientRectangle.Width);
float emSize = height;
Font font = new Font(FontFamily.GenericSansSerif, emSize, FontStyle.Regular);
font = FindBestFitFont(g, letter.ToString(), font, this.ClientRectangle.Size);
SizeF size = g.MeasureString(letter.ToString(), font);
g.DrawString(letter, font, new SolidBrush(Color.White), (width - size.Width) / 2, 0);
}
private Font FindBestFitFont(Graphics g, String text, Font font, Size proposedSize)
{
// Compute actual size, shrink if needed
while (true)
{
SizeF size = g.MeasureString(text, font);
// It fits, back out
if (size.Height <= proposedSize.Height &&
size.Width <= proposedSize.Width) { return font; }
// Try a smaller font (90% of old size)
Font oldFont = font;
font = new Font(font.Name, (float)(font.Size * .9), font.Style);
oldFont.Dispose();
}
}
void TakeScreenShot()
{
bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
gfxScreenshot = Graphics.FromImage(bmpScreenshot);
gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
bmpScreenshot.Save(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + #"\ScreenCaptures\newfile.png", ImageFormat.Png);
}
I am able to draw the string but it is writing on top of itself.
How can I clear it? Basically I want the countdown to appear on the screen then take a screenshot.
Right now the number is overwritten by another.
You can do the following: create an additional transparent form, and it will display timer values. This will allow you to erase the previous value. In addition, this will allow to get rid of the function call GetDC via PInvoke.
Form timerForm; // main form field
// Create and show additional transparent form before starting the timer
timerForm = new Form
{
FormBorderStyle = FormBorderStyle.None,
WindowState = FormWindowState.Maximized,
TransparencyKey = SystemColors.Control,
ShowInTaskbar = false
};
timerForm.Show();
timer.Start();
Change the method DrawLetter as follows
private void DrawLetter()
{
var letter = counter.ToString();
Graphics g = timerForm.CreateGraphics();
float width = ClientRectangle.Width;
float height = ClientRectangle.Width;
float emSize = height;
using (Font font1 = new Font(FontFamily.GenericSansSerif, emSize, FontStyle.Regular))
using (Font font2 = FindBestFitFont(g, letter, font1, ClientRectangle.Size))
using (var brush = new SolidBrush(Color.White))
{
SizeF size = g.MeasureString(letter, font2);
g.Clear(SystemColors.Control);
g.DrawString(letter, font2, brush, (width - size.Width) / 2, 0);
}
}
We must release all used resources like fonts and brushes. For this I applied using.
Change the timer tick event handler as follows
private void timer1_Tick(object sender, EventArgs e)
{
counter--;
DrawLetter();
if (counter == 0)
{
timer.Stop();
TakeScreenShot();
timerForm.Dispose(); // must release
}
}
FindBestFitFont and TakeScreenShot methods remain unchanged.
Draw your font to a different bitmap. Transparent background (or whatever doesn't invert, see below - perhaps black).
(now you could also draw it with a different colored shadow to mitigate drawing on similar colored background - but the natures of SRCINVERT/XOR, below, will mitigate this as well)
Use BitBlt to copy it to the screen
Use the SRCINVERT raster op.
(note: the colors may be different as it is XORing it with pixels underneath)
Now when is is time to erase, just make the same bitblt with the same contents as previous, the double XOR effect caused by SRCINVERT will have the effect of erasing it.
Then draw the next font.
Note: if desktop is updated between calls, all bets are off.
better...
Rather than attempting a transparent background, draw it on a white background. This will eliminate contrast issues with the font, eliminate concern with dynamic updates, and eliminate problems with erasing. Sometimes you have to admit - the method & code isn't the problem, the requirements are the problem. This all depends of course on the source of the requirements, etc.
If it needs to look professional, don't put the content on the screen, draw it after you take the screen capture.
If you end up using the transparent window approach, the screen shot may miss the transparent window. To get it, see this question:
Capture screenshot Including Semitransparent windows in .NET. (could be fixed by newer .net / newer windows versions)
You need to invalidate all the windows on the desktop by using the InvalidateRect function to erase the previously drawn letter.
See additional codes below for the DrawLetter method.
[DllImport("user32")]
private static extern bool InvalidateRect(IntPtr hwnd, IntPtr rect, bool bErase);
private void DrawLetter()
{
var letter = counter.ToString();
Graphics g = Graphics.FromHdc(GetDC(IntPtr.Zero));
float width = ((float)this.ClientRectangle.Width);
float height = ((float)this.ClientRectangle.Width);
float emSize = height;
Font font = new Font(FontFamily.GenericSansSerif, emSize, FontStyle.Regular);
font = FindBestFitFont(g, letter.ToString(), font, this.ClientRectangle.Size);
SizeF size = g.MeasureString(letter.ToString(), font);
// Invalidate all the windows.
InvalidateRect(IntPtr.Zero, IntPtr.Zero, true);
// Sometimes, the letter is drawn before the windows are invalidated.
// To fix that, add a small delay before drawing the letter.
System.Threading.Thread.Sleep(100);
// Finally, draw the letter.
g.DrawString(letter, font, new SolidBrush(Color.White), (width - size.Width) / 2, 0);
}
A solution is:
You must take a snapshot of that area you want to show counter before all things. Then call DrawImage function to draw snapshot image before call DrawString function every time.
I want to zoom picture box along with graphics.
this will Zoom the only image part not the graphics part.
public Image PictureBoxZoom(Image imgP, Size size)
{
Bitmap bm = new Bitmap(imgP, Convert.ToInt32(imgP.Width * size.Width), Convert.ToInt32(imgP.Height * size.Height));
Graphics grap = Graphics.FromImage(bm);
grap.InterpolationMode = InterpolationMode.HighQualityBicubic;
return bm;
}
private void zoomSlider_Scroll(object sender, EventArgs e)
{
if (zoomSlider.Value > 0 && img != null)
{
pictureBox1.SizeMode = PictureBoxSizeMode.CenterImage;
pictureBox1.Image = null;
pictureBox1.Image = PictureBoxZoom(img, new Size(zoomSlider.Value, zoomSlider.Value));
}
}
the source of image is:
img = Image.FromStream(openFileDialog1.OpenFile());
Picture is zooming but when we draw the rectangle outside image then it's not zooming along with image.
See image:
You can do this (rather) easily by scaling the e.Graphics object in the Paint event.. See here for an example!
So to work with you code you probably should add this to the Paint event:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.ScaleTransform(zoom, zoom);
// now do your drawing..
// here just a demo ellipse and a line..
Rectangle rect = panel1.ClientRectangle;
g.DrawEllipse(Pens.Firebrick, rect);
using (Pen pen = new Pen(Color.DarkBlue, 4f)) g.DrawLine(pen, 22, 22, 88, 88);
}
To calculate the zoom factor you need to do a little calculation.
Usually you would not create a zoomed Image but leave that job to the PictureBox with a SizeMode=Zoom.
Then you could write:
float zoom = 1f * pictureBox1.ClientSize.Width / pictureBox1.Image.Width;
To center the image one usually moves the PictureBox inside a Panel. And to allow scrolling one sets the Panel to Autocroll=true;
But since you are creating a zoomed Image you should keep track of the current zoom by some other means.
Note:
But as you use PictureBoxSizeMode.CenterImage maybe your problem is not with the zooming after all?? If your issue really is the placement, not the size of the drawn graphics you need to do a e.Graphics.TranslateTransform to move it to the right spot..
I want to make a bitmap that has a linear opacity applied. (i.e. it is more opaque on the left side and get progressively less opaque as it approaches the right.)
Is this possible? I know its possible to have a constant opacity level.
I know its possible to have a constant opacity level
So don't make it constant, LinearGradientBrush has no trouble interpolating the alpha value. A simple demonstration of a form that has the BackgroundImage set:
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
var rc = new Rectangle(20, 20, this.ClientSize.Width - 40, 50);
using (var brush = new System.Drawing.Drawing2D.LinearGradientBrush(
rc,
Color.FromArgb(255, Color.BlueViolet),
Color.FromArgb(0, Color.BlueViolet),
0f)) {
e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half;
e.Graphics.FillRectangle(brush, rc);
}
}
Produced:
Put the BitMap into a PictureBox control. Then you will have to use the PictureBox's Paint event handler to do the fading. Something like
private void pictureBox_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(pictureBox.Image, 0, 0,
pictureBox.ClientRectangle, GraphicsUnit.Pixel);
Color left = Color.FromArgb(128, Color.Blue);
Color right = Color.FromArgb(128, Color.Red);
LinearGradientMode direction = LinearGradientMode.Horizontal;
LinearGradientBrush brush = new LinearGradientBrush(
pictureBox.ClientRectangle, left, right, direction);
e.Graphics.FillRectangle(brush, pictureBox.ClientRectangle);
}
This example fades the image overlay from blue to red. I am sure you can play with this to get what you want working.
I hope this helps.
I am trying to create an application in C# (WinForms), something similar to this iOS Question
I managed to get part of it working, I can blur an image using this algorithm
Also I am able to draw a selection rectangle, I do not know if I am going wrong with the blurring or passing the rectangle. I have attached the file as shown below.
As seen, the blurring is outside the selection box.
I have pasted the code below:
// Start Rectangle
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
// Determine the initial rectangle coordinates...
RectStartPoint = e.Location;
Invalidate();
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left)
return;
Point tempEndPoint = e.Location;
Rect.Location = new Point(
Math.Min(RectStartPoint.X, tempEndPoint.X),
Math.Min(RectStartPoint.Y, tempEndPoint.Y));
Rect.Size = new Size(
Math.Abs(RectStartPoint.X - tempEndPoint.X),
Math.Abs(RectStartPoint.Y - tempEndPoint.Y));
pictureBox1.Invalidate();
}
// Draw Area
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
// Draw the rectangle...
if (pictureBox1.Image != null)
{
if (Rect != null && Rect.Width > 0 && Rect.Height > 0)
{
e.Graphics.DrawRectangle(selectionPen, Rect);
}
}
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
//Right now I am using right click as a call to blur
if (e.Button == MouseButtons.Right)
{
if (Rect.Contains(e.Location))
{
pictureBox1.Image = Blur(pictureBox1.Image, Rect, 5);
pictureBox1.Refresh();
}
}
}
private void blurPageToolStripMenuItem_Click(object sender, EventArgs e)
{
FullRect = new Rectangle(0, 0, pictureBox1.Image.Width, pictureBox1.Image.Height);
pictureBox1.Image = Blur(pictureBox1.Image, FullRect, 5);
}
private System.Drawing.Image Blur(System.Drawing.Image image, Rectangle rectangle, Int32 blurSize)
{
Bitmap blurred = new Bitmap(image); //image.Width, image.Height);
using (Graphics graphics = Graphics.FromImage(blurred))
{
// look at every pixel in the blur rectangle
for (Int32 xx = rectangle.Left; xx < rectangle.Right; xx += blurSize)
{
for (Int32 yy = rectangle.Top; yy < rectangle.Bottom; yy += blurSize)
{
Int32 avgR = 0, avgG = 0, avgB = 0;
Int32 blurPixelCount = 0;
Rectangle currentRect = new Rectangle(xx, yy, blurSize, blurSize);
// average the color of the red, green and blue for each pixel in the
// blur size while making sure you don't go outside the image bounds
for (Int32 x = currentRect.Left; (x < currentRect.Right && x < image.Width); x++)
{
for (Int32 y = currentRect.Top; (y < currentRect.Bottom && y < image.Height); y++)
{
Color pixel = blurred.GetPixel(x, y);
avgR += pixel.R;
avgG += pixel.G;
avgB += pixel.B;
blurPixelCount++;
}
}
avgR = avgR / blurPixelCount;
avgG = avgG / blurPixelCount;
avgB = avgB / blurPixelCount;
// now that we know the average for the blur size, set each pixel to that color
graphics.FillRectangle(new SolidBrush(Color.FromArgb(avgR, avgG, avgB)), currentRect);
}
}
graphics.Flush();
}
return blurred;
}
Another problem I am facing is, when the form is loaded initially, it starts in minimised mode, now if I use the selection (red rectangle), and then if I maximise the application the selected part of the picture is different.
Thank you for the help/suggestion in advance. If any links to a tool similar is around, please do share as I might have missed it. Thanks
You may be experiencing this issue because your image is stretched in the PictureBox. You can verify this is the issue by setting the SizeMode property of the PictureBox to Normal.
This is the sequence of events:
The selection rectangle is drawn.
The point/rectangle for the selection is determined.
The unstretched image is retrieved from the PictureBox, and is passed to the Blur method, with the calculated rectangle.
The unstretched image is blurred over the area described by the rectangle.
The unstretched image, now blurred, is assigned to the PictureBox.
The PictureBox stretches the image out to according to its SizeMode setting.
This makes the image appear to have blurred in a different location than what you selected.
The code you have looks at the selection rectangle, and uses those points to operate on the original image, not the stretched version of the image. If you want to blur the stretched image, you will need to get the stretched image first, then apply the blur to the rectangle selected on that image. Here is an example:
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
//Right now I am using right click as a call to blur
if (e.Button == MouseButtons.Right)
{
if (Rect.Contains(e.Location))
{
pictureBox1.Image = Blur(getPictureBoxImage(), Rect, 5);
pictureBox1.Refresh();
}
}
}
private Bitmap getPictureBoxImage()
{
Bitmap bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);
using (Graphics g = Graphics.FromImage(bmp))
{
g.DrawImage(pictureBox1.Image,
new Rectangle(0, 0, bmp.Width, bmp.Height));
}
return bmp;
}
Code for retrieving the stretched image is derived from this answer: https://stackoverflow.com/a/8702405/935052