Related
How can I get the color of an area that has 5x5px inside an image.
int xPixel = 200; int yPixel = 100;
Bitmap myBitmap = new Bitmap(“C:/Users/admin/Desktop/image.png");
Color pixelColor = myBitmap.GetPixel(xPixel, yPixel, 5, 5);
MessageBox.Show(pixelColor.Name);
This code does not work!.
You can use something this extension method to get dominant color in a region of an image in case they are not all the same
public static Color GetDominantColor(this Bitmap bitmap, int startX, int startY, int width, int height) {
var maxWidth = bitmap.Width;
var maxHeight = bitmap.Height;
//TODO: validate the region being requested
//Used for tally
int r = 0;
int g = 0;
int b = 0;
int totalPixels = 0;
for (int x = startX; x < (startX + width); x++) {
for (int y = startY; y < (startY + height); y++) {
Color c = bitmap.GetPixel(x, y);
r += Convert.ToInt32(c.R);
g += Convert.ToInt32(c.G);
b += Convert.ToInt32(c.B);
totalPixels++;
}
}
r /= totalPixels;
g /= totalPixels;
b /= totalPixels;
Color color = Color.FromArgb(255, (byte)r, (byte)g, (byte)b);
return color;
}
You can then use it like
Color pixelColor = myBitmap.GetDominantColor(xPixel, yPixel, 5, 5);
there is room for improvement, like using a Point and Size, or even a Rectangle
public static Color GetDominantColor(this Bitmap bitmap, Rectangle area) {
return bitmap.GetDominantColor(area.X, area.Y, area.Width, area.Height);
}
but this should be enough to get started.
A solution that uses the actual drawing methods provided by System.Drawing to resize the given area to 1x1 and get its pixel value:
public static Color GetRectangleColor(Bitmap sourceBitmap, Int32 x, Int32 y, Int32 width, Int32 height)
{
using(Bitmap onePix = new Bitmap(1,1, PixelFormat.Format24bppRgb))
{
using (Graphics pg = Graphics.FromImage(onePix)){
pg.DrawImage(sourceBitmap,
new Rectangle(0, 0, 1, 1),
new Rectangle(x, y, width, height)),
GraphicsUnit.Pixel);
return onePix.GetPixel(0, 0);
}
}
Though, if you are consistently working with squares of a uniform colour, I personally wouldn't bother. Just avoid any potential fades at the edges and you're fine:
public static Color GetRectangleCenterColor(Bitmap sourceBitmap, Int32 x, Int32 y, Int32 width, Int32 height)
{
return sourceBitmap.GetPixel(x + (width / 2), y + (height / 2));
}
About
I’m using WinForms. In my form, I have a picturebox. The picturebox size mode is set to zoom. I use the picturebox to view TIF images. The TIF images are grayscale (Black and White ONLY).
What My App Does
My application finds the first black pixel and the last black pixel in the document and draws a red rectangle around it. In hopes that it would draw the rectangle around the content of the image.
The Problem
Sometimes the TIF documents have spots/dots around the content of the image. This throws my application off. It doesn't know where the content of the image begins and ends. How can I find the content of the TIF documents and draw a rectangle around it if the document has spots/dots?
About the Document
Black and white only (1 bit depth)
TIF document
Document always has letters and numbers
The letters and numbers are always bigger than the spots/dots
There can be multiple spots all over the image even in the content
The background is always white
The content is always black
The spots are also black
Download Test Image Links:
• File Dropper: http://www.filedropper.com/test-tifs
• Rapid Share: https://ufile.io/2qiir
What I Found
Upon my research, I found AForge.Imaging library which has many imaging filters that may potentially help me achieve my goal. I'm thinking about removing the spots/dots using the median filter or use the other filters to achieve the desired result.
What I Tried
I tried applying the median filter from AForge library to get rid of the spots but that only got rid of some of the spots. I had to repeat replying the filter multiple times to get rid of MOST of the spots to find the content and it still had a hard time finding the content. That method didn't work too well for me.
Link to AForge Filters: http://www.aforgenet.com/framework/docs/html/cdf93487-0659-e371-fed9-3b216efb6954.htm
Code
private void btn_Draw_Click(object sender, EventArgs e)
{
// Wrap the creation of the OpenFileDialog instance in a using statement,
// rather than manually calling the Dispose method to ensure proper disposal
using (OpenFileDialog dlg = new OpenFileDialog())
{
if (dlg.ShowDialog() == DialogResult.OK)
{
pictureBox1.Image = new Bitmap(dlg.FileName);
int xMax = pictureBox1.Image.Width;
int yMax = pictureBox1.Image.Height;
startX = Int32.MaxValue;
startY = Int32.MaxValue;
endX = Int32.MinValue;
endY = Int32.MinValue;
using (Bitmap bmp = new Bitmap(pictureBox1.Image))
{
for (var y = 0; y < yMax; y+=3)
{
for (var x = 0; x < xMax; x+=3)
{
Color col = bmp.GetPixel(x, y);
if(col.ToArgb() == Color.Black.ToArgb())
{
// Finds first black pixel
if (x < startX)
startX = x;
if(y < startY)
startY = y;
// Finds last black pixel
if (x > endX)
endX = x;
if (y > endY)
endY = y;
}
}
}
int picWidth = pictureBox1.Size.Width;
int picHeight = pictureBox1.Size.Height;
float imageRatio = xMax / (float)yMax; // image W:H ratio
float containerRatio = picWidth / (float)picHeight; // container W:H ratio
if (imageRatio >= containerRatio)
{
// horizontal image
float scaleFactor = picWidth / (float)xMax;
float scaledHeight = yMax * scaleFactor;
// calculate gap between top of container and top of image
float filler = Math.Abs(picHeight - scaledHeight) / 2;
//float filler = 0;
startX = (int)(startX * scaleFactor);
endX = (int)(endX * scaleFactor);
startY = (int)((startY) * scaleFactor + filler);
endY = (int)((endY) * scaleFactor + filler);
}
else
{
// vertical image
float scaleFactor = picHeight / (float)yMax;
float scaledWidth = xMax * scaleFactor;
float filler = Math.Abs(picWidth - scaledWidth) / 2;
startX = (int)((startX) * scaleFactor + filler);
endX = (int)((endX) * scaleFactor + filler);
startY = (int)(startY * scaleFactor);
endY = (int)(endY * scaleFactor);
}
//var scaleX = picWidth / (float)xMax;
//var scaleY = picHeight / (float)yMax;
//startX = (int)Math.Round(startX * scaleX);
//startY = (int)Math.Round(startY * scaleY);
//endX = (int)Math.Round(endX * scaleX);
//endY = (int)Math.Round(endY * scaleY);
}
}
}
}
private bool _once = true;
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (_once)
{
//Rectangle ee = new Rectangle(35, 183, 405, 157);
Rectangle ee = new Rectangle(startX, startY, endX - startX, endY - startY);
System.Diagnostics.Debug.WriteLine(startX + ", " + startY + ", " + (endX - startX) + ", " + (endY - startY));
using (Pen pen = new Pen(Color.Red, 2))
{
e.Graphics.DrawRectangle(pen, ee);
}
//_once = false;
}
}
Tif document that DOES NOT HAVE any spots and dots around content
Tif document that HAS spots and dots around content
Example Image 1:
Example Image 2
:
Example Image 3
Following experiment seems to meet all your requirements.
I put following controls onto Form1
A MenuStrip: Docking=Top, with 2 MenuItems - one to open a file, second to run an algorithm
A progressbar: Docking=Top, to watch performance of loading and algorithm
A panel with Docking=Fill and AutoScroll=true
A picture into the panel, Point(0,0), the rest by default. SizeMode=Normal.
Update
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// Opens an image file.
private void openToolStripMenuItem_Click(object sender, EventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();
if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
this.image = Image.FromFile(dlg.FileName) as Bitmap;
this.pictureBox1.Image = image;
this.pictureBox1.Invalidate();
}
}
Bitmap image;
// finds top, left, right and bottom bounds of the content in TIFF file.
//
private void findBoundsToolStripMenuItem_Click(object sender, EventArgs e)
{
int contentSize = 70;
this.left = 0;
this.top = 0;
this.right = this.pictureBox1.Width - 1;
this.bottom = this.pictureBox1.Height - 1;
int h = image.Height;
int w = image.Width;
this.progressBar1.Value = 0;
this.progressBar1.Maximum = 4;
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
if (this.image.GetPixel(x, y).ToArgb() == Black)
{
int size = this.image.GetBlackRegionSize(x, y);
if (this.image.GetBlackRegionSize(x, y) > contentSize)
{
this.top = y;
goto label10;
}
}
}
}
label10:
this.progressBar1.Increment(1);
for (int y = h - 1; y >= 0; y--)
{
for (int x = 0; x < w; x++)
{
if (this.image.GetPixel(x, y).ToArgb() == Black)
{
if (this.image.GetBlackRegionSize(x, y) > contentSize)
{
this.bottom = y;
goto label11;
}
}
}
}
label11:
this.progressBar1.Increment(1);
for (int x = 0; x < w; x++)
{
for (int y = 0; y < h; y++)
{
if (this.image.GetPixel(x, y).ToArgb() == Black)
{
if (this.image.GetBlackRegionSize(x, y) > contentSize)
{
this.left = x;
goto label12;
}
}
}
}
label12:
this.progressBar1.Increment(1);
for (int x = w - 1; x >= 0; x--)
{
for (int y = 0; y < h; y++)
{
if (this.image.GetPixel(x, y).ToArgb() == Black)
{
if (this.image.GetBlackRegionSize(x, y) > contentSize)
{
this.right = x;
goto label13;
}
}
}
}
label13:
this.progressBar1.Increment(1);
this.pictureBox1.Invalidate();
}
internal static readonly int Black = Color.Black.ToArgb();
internal static readonly int White = Color.White.ToArgb();
int top;
int bottom;
int left;
int right;
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (pictureBox1.Image == null)
{
return;
}
int xMax = pictureBox1.Image.Width;
int yMax = pictureBox1.Image.Height;
int startX = this.left;
int startY = this.top;
int endX = this.right;
int endY = this.bottom;
int picWidth = pictureBox1.Size.Width;
int picHeight = pictureBox1.Size.Height;
float imageRatio = xMax / (float)yMax; // image W:H ratio
float containerRatio = picWidth / (float)picHeight; // container W:H ratio
if (imageRatio >= containerRatio)
{
// horizontal image
float scaleFactor = picWidth / (float)xMax;
float scaledHeight = yMax * scaleFactor;
// calculate gap between top of container and top of image
float filler = Math.Abs(picHeight - scaledHeight) / 2;
//float filler = 0;
startX = (int)(startX * scaleFactor);
endX = (int)(endX * scaleFactor);
startY = (int)((startY) * scaleFactor + filler);
endY = (int)((endY) * scaleFactor + filler);
}
else
{
// vertical image
float scaleFactor = picHeight / (float)yMax;
float scaledWidth = xMax * scaleFactor;
float filler = Math.Abs(picWidth - scaledWidth) / 2;
startX = (int)((startX) * scaleFactor + filler);
endX = (int)((endX) * scaleFactor + filler);
startY = (int)(startY * scaleFactor);
endY = (int)(endY * scaleFactor);
}
//if (_once)
//Rectangle ee = new Rectangle(35, 183, 405, 157);
Rectangle ee = new Rectangle(startX, startY, endX - startX, endY - startY);
System.Diagnostics.Debug.WriteLine(startX + ", " + startY + ", " + (endX - startX) + ", " + (endY - startY));
using (Pen pen = new Pen(Color.Red, 2))
{
e.Graphics.DrawRectangle(pen, ee);
}
//_once = false;
}
}
static class BitmapHelper
{
internal static int GetBlackRegionSize(this Bitmap image, int x, int y)
{
int size = 0;
GetRegionSize(image, new List<Point>(), x, y, 0, ref size);
return size;
}
// this constant prevents StackOverFlow exception.
// also it has effect on performance.
// It's value must be greater than the value of contentSize defined in findBoundsToolStripMenuItem_Click(object sender, EventArgs e) method.
const int MAXLEVEL = 100;
static void GetRegionSize(this Bitmap image, List<Point> list, int x, int y, int level, ref int size)
{
if (x >= image.Width || x < 0 || y >= image.Height || y < 0 || list.Contains(x, y) || image.GetPixel(x, y).ToArgb() != Form1.Black || level > MAXLEVEL)
{
return;
}
if (size < level)
{
size = level;
}
list.Add(new Point(x, y));
image.GetRegionSize(list, x, y - 1, level + 1, ref size);
image.GetRegionSize(list, x, y + 1, level + 1, ref size);
image.GetRegionSize(list, x - 1, y, level + 1, ref size);
image.GetRegionSize(list, x + 1, y, level + 1, ref size);
}
static bool Contains(this List<Point> list, int x, int y)
{
foreach (Point point in list)
{
if (point.X == x && point.Y == y)
{
return true;
}
}
return false;
}
}
}
"this.pictureBox1.Size = image.Size;" has been removed. Paint event handler's code changed. PictureBox size mode can be set to Zoom now.
Update 2
I tried to simplify code and increase performance.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApplication3
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.pictureBox1.Paint += new PaintEventHandler(this.pictureBox1_Paint);
}
// Opens an image file
// and runs "FindBounds()" method
private void openToolStripMenuItem_Click(object sender, EventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();
if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
this.image = Image.FromFile(dlg.FileName) as Bitmap;
FindBounds();
this.pictureBox1.Image = image;
this.pictureBox1.Invalidate();
}
}
Bitmap image;
// Possible maximum side of a spot or a dot in the image
int maxSpotOrDotSide = 7;
// Finds top, left, right and bottom bounds of the content in TIFF file.
private void FindBounds()
{
// Possible maximum area of a spot or a dot in the image
int maxSpotOrDotArea = maxSpotOrDotSide * maxSpotOrDotSide;
this.left = 0;
this.top = 0;
this.right = this.pictureBox1.Width - 1;
this.bottom = this.pictureBox1.Height - 1;
int h = image.Height;
int w = image.Width;
int num = w * h;
// Incrementers. I tested with greater values
// like "x = 2", "x = 5" and it increased performance.
// But we must be carefull as this may cause skipping content.
int dx = 1; // Incrementer for "x"
int dy = 1; // Incrementer for "y"
// Initialization of "progressBar1"
this.progressBar1.Value = 0;
this.progressBar1.Maximum = num;
// Content of the image
BlackContent imageContent = null;
// Here we will scan pixels of the image
// starting from top left corner and
// finishing at bottom right
for (int y = 0; y < h; y += dx)
{
for (int x = 0; x < w; x += dy)
{
int val = y * w + x;
this.progressBar1.Value = val > num ? num : val;
// This block skips scanning imageContent
// thus should increase performance.
if (imageContent != null && imageContent.Contains(x, y))
{
x = imageContent.Right;
continue;
}
// Interesting things begin to happen
// after we detect the first Black pixel
if (this.image.GetPixel(x, y).ToArgb() == Black)
{
BlackContent content = new BlackContent(x, y);
// Start Flood-Fill algorithm
content.FloodFill(this.image);
if (content.Area > maxSpotOrDotArea)
{
if (imageContent == null)
{
imageContent = content;
}
imageContent.Include(content.Right, content.Bottom);
imageContent.Include(content.Left, content.Top);
}
else
{
// Here it's better we increase values of the incrementers.
// Depending on size of spots/dots.
// It should increase performance.
if (dx < content.Width) dx = content.Width;
if (dy < content.Height) dy = content.Height;
}
}
}
}
// Everything is done.
this.progressBar1.Value = this.progressBar1.Maximum;
// If image content has been detected
// then we save the information
if (imageContent != null)
{
this.left = imageContent.Left;
this.top = imageContent.Top;
this.right = imageContent.Right;
this.bottom = imageContent.Bottom;
}
this.pictureBox1.Invalidate();
}
internal static readonly int Black = Color.Black.ToArgb();
internal static readonly int White = Color.White.ToArgb();
int top;
int bottom;
int left;
int right;
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (pictureBox1.Image == null)
{
return;
}
int xMax = pictureBox1.Image.Width;
int yMax = pictureBox1.Image.Height;
int startX = this.left;
int startY = this.top;
int endX = this.right;
int endY = this.bottom;
int picWidth = pictureBox1.Size.Width;
int picHeight = pictureBox1.Size.Height;
float imageRatio = xMax / (float)yMax; // image W:H ratio
float containerRatio = picWidth / (float)picHeight; // container W:H ratio
if (imageRatio >= containerRatio)
{
// horizontal image
float scaleFactor = picWidth / (float)xMax;
float scaledHeight = yMax * scaleFactor;
// calculate gap between top of container and top of image
float filler = Math.Abs(picHeight - scaledHeight) / 2;
//float filler = 0;
startX = (int)(startX * scaleFactor);
endX = (int)(endX * scaleFactor);
startY = (int)((startY) * scaleFactor + filler);
endY = (int)((endY) * scaleFactor + filler);
}
else
{
// vertical image
float scaleFactor = picHeight / (float)yMax;
float scaledWidth = xMax * scaleFactor;
float filler = Math.Abs(picWidth - scaledWidth) / 2;
startX = (int)((startX) * scaleFactor + filler);
endX = (int)((endX) * scaleFactor + filler);
startY = (int)(startY * scaleFactor);
endY = (int)(endY * scaleFactor);
}
//if (_once)
//Rectangle ee = new Rectangle(35, 183, 405, 157);
Rectangle ee = new Rectangle(startX, startY, endX - startX, endY - startY);
System.Diagnostics.Debug.WriteLine(startX + ", " + startY + ", " + (endX - startX) + ", " + (endY - startY));
using (Pen pen = new Pen(Color.Red, 2))
{
e.Graphics.DrawRectangle(pen, ee);
}
//_once = false;
}
}
// This class is similar to System.Drawing.Region class
// except that its only rectangular.
// Because all we need is to draw a rectagnle
// around the image this property must
// make it faster, at least I hope so.
class BlackContent
{
internal void FloodFill(Bitmap image)
{
FloodFillPrivate(image, this.left + 1, this.top, 0);
}
// Legendary Flood-Fill algorithm.
// Quite often it ends up with StackOverFlow exception.
// But this class and its rectangularity property
// must prevent this disaster.
// In my experiments I didn't encounter incidents.
void FloodFillPrivate(Bitmap image, int x, int y, int level)
{
if (x >= image.Width || x < 0 || y >= image.Height || y < 0 || this.Contains(x, y) || image.GetPixel(x, y).ToArgb() != Form1.Black)
{
return;
}
this.Include(x, y);
FloodFillPrivate(image, x, y - 1, level + 1);
FloodFillPrivate(image, x, y + 1, level + 1);
FloodFillPrivate(image, x - 1, y, level + 1);
FloodFillPrivate(image, x + 1, y, level + 1);
}
internal BlackContent(int x, int y)
{
this.left = x;
this.right = x;
this.top = y;
this.bottom = y;
}
internal void Include(int x, int y)
{
if (x < this.left)
{
this.left = x;
}
if (this.right < x)
{
this.right = x;
}
if (this.bottom < y)
{
this.bottom = y;
}
if (y < this.top)
{
this.top = y;
}
}
internal bool Contains(int x, int y)
{
return !(x < this.left || x > this.right || y < this.top || y > this.bottom);
}
int left;
internal int Left { get { return this.left; } }
int top;
internal int Top { get { return this.top; } }
int right;
internal int Right { get { return this.right; } }
int bottom;
internal int Bottom { get { return this.bottom; } }
internal int Area
{
get
{
return Width * Height;
}
}
internal int Width
{
get
{
return (this.right - this.left + 1);
}
}
internal int Height
{
get
{
return (this.bottom - this.top + 1);
}
}
}
}
I watched the performance with ProgressBar. This one's quite faster.
I must also mention that your images are too big.
A solution could be to find areas of black pixels. When a black pixel is found, check the colour of the neighbouring pixels and create an area of black pixels. When the area is big enough, it can be considered as content. The pseudo code below illustrates this. But it is a very resource intensive solution and should at least be optimized.
private List<List<Point>> areas = new List<List<Point>>();
public void PopulateAreas()
{
//Find all the areas
for (var y = 0; y < yMax; y += 3)
{
for (var x = 0; x < xMax; x += 3)
{
Color col = bmp.GetPixel(x, y);
if (col.ToArgb() == Color.Black.ToArgb())
{
//Found a black pixel, check surrounding area
var area = new List<Point>();
area.Add(new Point(x, y));
areas.Add(area);
AppendSurroundingPixelsToArea(area, x, y);
}
}
}
var startX = Int32.MaxValue;
var startY = Int32.MaxValue;
var endX = Int32.MinValue;
var endY = Int32.MinValue;
//Loop through list of areas.
foreach (var area in areas)
{
//Minimum size of area
if (area.Count > 5)
{
var minx = area.Min(p => p.X);
if (area.Min(p => p.X) < startX)
startX = minx;
//Do the same for the others...
}
}
}
public void AppendSurroundingPixelsToArea(List<Point> area, int startX, int startY)
{
for(var x = startX - 1; x <= startX + 1; x++)
for (var y = startY - 1; y <= startY + 1; y++)
{
if ((x != 0 || y != 0) && IsBlackPixel(bmp, x, y))
{
//Add to the area
if (PointDoesNotExistInArea(area, x, y))
{
area.Add(new Point(x, y));
AppendSurroundingPixelsToArea(area, x, y);
}
}
}
}
I have solution for this,
And I suggest "kodak imaging professional". This is the viewer to display multi-page tiff files. with many features like: Annotation, invert color, rotate image... etc., and these are inbuilt functionalities.
I am using visual studio c# windows form, I need help to draw a circle using the Mouse click.. first click will give me the center of the circle equal to the cursor position and the second click will give me a point on the border of the circle equal to the second position of the cursor, the distance between the to points will give me the radius..now I have radius and point ..I can draw a circle ..The code doesn't work because I only can get one position of the cursor no matter how many times I click the mouse
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
int lastX = Cursor.Position.X;//the first click x cursor position
int lastY = Cursor.Position.Y;//the first click y cursor position,
//is there any way to reuse the Cursor.Position for different point ??
int x = Cursor.Position.X;//the second click x cursor position
int y = Cursor.Position.Y;//the second click y cursor position
Graphics g;
double oradius=Math.Sqrt(((lastX-x)^2) +((lastY-y)^2));
//double newy = Math.Sqrt(lastY);
// int newxv = Convert.ToInt32(newx);
int radius= Convert.ToInt32(oradius);
g = this.CreateGraphics();
Rectangle rectangle = new Rectangle();
PaintEventArgs arg = new PaintEventArgs(g, rectangle);
DrawCircle(arg, x, y,radius,radius);
}
private void DrawCircle(PaintEventArgs e, int x, int y, int width, int height)
{
System.Drawing.Pen pen = new System.Drawing.Pen(System.Drawing.Color.Red, 3);
e.Graphics.DrawEllipse(pen, x - width / 2, y - height / 2, width, height);
}
}
You need to store the first click as well before you start doing the calculations. One way to do this is to create a class that simply throws an event every second time you pass it x and y coordinates like this:
public class CircleDrawer
{
private int _firstX;
private int _firstY;
private int _secondX;
private int _secondY;
private bool _isSecondClick;
private event EventHandler OnSecondClick;
public void RegisterClick(int x, int y)
{
if(_isSecondClick)
{
_secondX = x;
_secondY = y;
if(OnSecondClick != null)
OnSecondClick(this, null);
}
else
{
_firstX = x;
_firstY = y;
_isSecondClick = true;
}
}
}
You can then in your code simply call your methods:
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
int lastX = Cursor.Position.X;//the first click x cursor position
int lastY = Cursor.Position.Y;//the first click y cursor position,
_circleDrawer.RegisterClick(lastX, lastY);
}
And in your constuctor:
public MyForm()
{
_circleDrawer = new CircleDrawer();
_circleDrawer.OnSecondClick += DrawCircle();
}
public void DrawCircle()
{
// Your drawing code
}
Your lastX and lastY are local variables, and you initialize them in the beginning of the MouseDown event handler. They should be class level variables and should be populated at the end of the MouseDown event handler.
Also, you should test if they already have a value, and only if they have value then draw the circle and then clear them (so that the next circle will have it's own center).
Here is an improvement of your code. Note I've used the using keyword with the graphics object and with the pen - get used to use it every time you are using an instance of anything that's implementing the IDisposable interface.
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (_lastPosition != Point.Empty)
{
var currentPosition = Cursor.Position;
var oradius = Math.Sqrt(((_lastPosition.X - currentPosition.X) ^ 2) + ((_lastPosition.Y - currentPosition.Y) ^ 2));
var radius = Convert.ToInt32(oradius);
using (var g = this.CreateGraphics())
{
var arg = new PaintEventArgs(g, new Rectangle());
DrawCircle(arg, currentPosition, radius, radius);
}
_lastPosition = Point.Empty;
}
else
{
_lastPosition = Cursor.Position;
}
}
private void DrawCircle(PaintEventArgs e, Point position, int width, int height)
{
using (var pen = new System.Drawing.Pen(System.Drawing.Color.Red, 3))
{
e.Graphics.DrawEllipse(pen, position.X - width / 2, position.Y - height / 2, width, height);
}
}
Note: This code can be improved even further.
There are many things fundamentally wrong with this code, here is a complete, working example.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private Point clickCurrent = Point.Empty;
private Point clickPrev = Point.Empty;
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
clickPrev = clickCurrent;
clickCurrent = this.PointToClient(Cursor.Position);
if (clickPrev == Point.Empty) return;
Graphics g;
double oradius = Math.Sqrt((Math.Pow(clickPrev.X - clickCurrent.X, 2)) + (Math.Pow(clickPrev.Y - clickCurrent.Y, 2)));
int radius = Convert.ToInt32(oradius);
g = this.CreateGraphics();
Rectangle rectangle = new Rectangle();
PaintEventArgs arg = new PaintEventArgs(g, rectangle);
DrawCircle(arg, clickPrev.X, clickPrev.Y, radius * 2, radius * 2);
clickCurrent = Point.Empty;
}
private void DrawCircle(PaintEventArgs e, int x, int y, int width, int height)
{
System.Drawing.Pen pen = new System.Drawing.Pen(System.Drawing.Color.Red, 3);
e.Graphics.DrawEllipse(pen, x - width / 2, y - height / 2, width, height);
}
}
private int _firstX;
private int _firstY;
private int _secondX;
private int _secondY;
private bool _isSecondClick;
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (_isSecondClick)
{
_secondX = Cursor.Position.X;
_secondY = Cursor.Position.Y;
var radious1 = Math.Pow(_firstX - _secondX, 2);
var radious2 = Math.Pow(_firstY - _secondY, 2);
var radious = Math.Sqrt(radious1 + radious2);
Graphics g = this.CreateGraphics();
Rectangle rectangle = new Rectangle();
PaintEventArgs arg = new PaintEventArgs(g, rectangle);
DrawCircle(arg, _secondX, _secondY, radious, radious);
}
else
{
_firstX = Cursor.Position.X;
_firstY = Cursor.Position.Y;
_isSecondClick = true;
}
}
private void DrawCircle(PaintEventArgs arg, int x, int y, double width, double height)
{
System.Drawing.Pen pen = new System.Drawing.Pen(System.Drawing.Color.Red, 3);
var xL = Convert.ToInt32(x - width / 2);
var yL = Convert.ToInt32(y - height / 2);
var hL = Convert.ToInt32(height);
var wL = Convert.ToInt32(width);
arg.Graphics.DrawEllipse(pen, xL, yL, wL, hL);
}
I am trying to create textboxes and draw circles dynamically within a user control. The circle is visible but the textboxes are not visible when I run my application. Am I missing something in the code?
Please find the code below,
public partial class uscCircle : UserControl
{
public uscCircle()
{
InitializeComponent();
}
public void DrawCircle(PaintEventArgs args, int x, int y, int width, int height)
{
Pen pen = new Pen(Color.Red, 3);
Brush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Red);
args.Graphics.FillEllipse(myBrush, x - width / 2, y - height / 2, width, height);
}
public void AddTextBox(string text, int x, int y, int width, int height)
{
markerlabel.Size = new Size(40, 15);
markerlabel.Text = text;
markerlabel.TextAlign = HorizontalAlignment.Center;
markerlabel.BorderStyle = BorderStyle.FixedSingle;
markerlabel.ForeColor = Color.White;
markerlabel.BackColor = Color.Red;
markerlabel.Location = new Point(x - (width + 14), y + height / 2);
markerlabel.Visible = true;
this.Controls.Add(markerlabel);
}
}
public partial class CalibrationForm : Form
{
private CalibrationForm_Click(object sender, EventArgs e)
{
int x = e.X;
int y = e.Y;
DrawTextBox(X, Y, 25, 25, "1234", "abcd");
}
private void DrawCircle(int x, int y, int width, int height, string MarkerID, string type)
{
PaintEventArgs arg = new PaintEventArgs(this.CreateGraphics(), new Rectangle());
uscCircle circle = new uscCircle();
circle.DrawCircle(arg, x, y, width, height);
circle.AddTextBox(ID, x, y, width, height);
circle.AddTextBox(type, x + 40, y, width, height);
}
}
I don't see where you add uscCircle to the form. If that isn't displayed, neither will the textbox be.
Such as:
private void DrawCircle(int x, int y, int width, int height, string MarkerID, string type)
{
uscCircle circle = new uscCircle();
circle.AddTextBox(ID, x, y, width, height);
circle.AddTextBox(type, x+40, y, width, height);
this.Controls.Add(circle);
}
You are adding your TextBox into a new User control which is then not used.
uscCircle circle = new uscCircle();
circle.AddTextBox(ID, x, y, width, height);
circle.AddTextBox(type, x+40, y, width, height);
You either need to add your 'uscCircle' into the controls of the Form
this.Controls.Add(uscCircle); // Must be in your Form file
or you move the TextBox-Generation code into your form
Here is my code and I want to implement DDA algorithm without using drawLine method in c# . I tried to use PutPixel method but it did not work . There is nothing in my window. Is there any way to draw line without using drawLine method in c# ?
private void Form1_Paint(object sender, PaintEventArgs e)
{
grafik = e.Graphics;
DDACiz(ilk.X, ilk.Y, ikinci.X, ikinci.Y, grafik, Color.DarkRed);
}
void PutPixel(Graphics g, int x, int y, Color c) // sadece bir pixel icin
{
System.Drawing.Bitmap bm = new System.Drawing.Bitmap(10, 10);
bm.SetPixel(0, 0, Color.DarkRed);
g.DrawImageUnscaled(bm, x, y);
}
void DDACiz(int x1, int y1, int x2, int y2,Graphics grafik, Color renk)
{
int PikselSayisi;
int dx, dy;
float x, xFark;
float y, yFark;
dx = x2 - x1;
dy = y2 - y1;
PikselSayisi = Math.Abs(dx) > Math.Abs(dy) ? Math.Abs(dx) : Math.Abs(dy);
xFark = (float)dx / (float)PikselSayisi;
yFark = (float)dy / (float)PikselSayisi;
x = (float)x1;
y = (float)y1;
while (PikselSayisi!=0)
{
PutPixel(grafik,(int)Math.Floor(x + 0.5F),(int) Math.Floor(y + 0.5f),renk);
x += xFark;
y += yFark;
PikselSayisi--;
}
}
}
}
There is no Graphics.DrawPoint method, so to draw a single pixel with a Graphics object you need to use Graphics.FillRectangle
Change
void PutPixel(Graphics g, int x, int y, Color c) // sadece bir pixel icin
{
System.Drawing.Bitmap bm = new System.Drawing.Bitmap(10, 10);
bm.SetPixel(0, 0, Color.DarkRed);
g.DrawImageUnscaled(bm, x, y);
}
to
void PutPixel(Graphics g, int x, int y, Color c) // sadece bir pixel icin
{
g.FillRectangle(Brushes.DarkRed, x, y, 1, 1);
}
or if you want to use the Color c:
void PutPixel(Graphics g, int x, int y, Color c) // sadece bir pixel icin
{
using (SolidBrush brush = new SolidBrush(c) )
g.FillRectangle(brush , x, y, 1, 1);
}
You could also use your appoach of drawing a bitmap but you need to make it either 1x1 pixels wide or make sure it is transparent and also use CompositingMode.SourceOver.
Writing a line draw method is an interesting exercise; much harder than it seems and really tough for PenWidths other than 1.0, let alone for alpha channels other than fully opaque..