I've run into an issue with drawing text and basic graphic drawing operations not having the proper placement & quality when the drawing matrix has large offset values. I've tried number SmoothMode, InterpolationMode, & TextRenderingHint options with no luck.
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
public void RenderImageClosePointDrawing()
{
float x = 68336, y = 99460;
PointF anchorPoint = new PointF(17494176, 25461836);
PointF anchorPoint2= new PointF(17494076, 25461836);
string textLabel = "9318";
float textFontSize = 20;
float symbolsize = 34;
string fontFamly = "Arial";
Bitmap bitmap = new Bitmap(256, 256);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
graphics.Transform = new Matrix(1, 0, 0, 1, -x * 256, -y * 256);
//Draw the circle
Pen polyPen = new Pen(new SolidBrush(Color.Black), 2);
Brush polyBrush = new SolidBrush(Color.Teal);
graphics.DrawEllipse(polyPen, anchorPoint.X, anchorPoint.Y, symbolsize, symbolsize);
graphics.FillEllipse(polyBrush, anchorPoint.X, anchorPoint.Y, symbolsize, symbolsize);
RectangleF drawnArea = new RectangleF(anchorPoint.X, anchorPoint.Y, symbolsize, symbolsize);
Pen polyPen2 = new Pen(new SolidBrush(Color.Black), 1);
Brush polyBrush2 = new SolidBrush(Color.Teal);
graphics.DrawEllipse(polyPen2, anchorPoint2.X, anchorPoint2.Y, symbolsize, symbolsize);
graphics.FillEllipse(polyBrush2, anchorPoint2.X, anchorPoint2.Y, symbolsize, symbolsize);
RectangleF drawnArea2 = new RectangleF(anchorPoint2.X, anchorPoint2.Y, symbolsize, symbolsize);
Pen polyPen3 = new Pen(new SolidBrush(Color.Red), 1);
graphics.DrawRectangle(polyPen3, drawnArea.X, drawnArea.Y, drawnArea.Width, drawnArea.Height);
graphics.DrawRectangle(polyPen3, drawnArea2.X, drawnArea2.Y, drawnArea2.Width, drawnArea2.Height);
//Draw the text
Pen textOutlinePen = new Pen(new SolidBrush(Color.Orange), (float)4);
textOutlinePen.EndCap = LineCap.Round;
textOutlinePen.LineJoin = LineJoin.Round;
textOutlinePen.MiterLimit = 0;
Brush textFillBrush = new SolidBrush(Color.Teal);
FontFamily textFontFamily = new FontFamily(fontFamly);
PointF textAnchor = new PointF(anchorPoint.X, anchorPoint.Y);
ShiftTextAnchor_NW(textLabel, textFontSize, ref drawnArea, textFontFamily, ref textAnchor);
var textPath = new GraphicsPath();
textPath.AddString(textLabel,
textFontFamily,
(int)FontStyle.Bold,
textFontSize,
textAnchor,
new StringFormat()
);
graphics.DrawPath(textOutlinePen, textPath);
graphics.FillPath(textFillBrush, textPath);
//Draw the text2
Pen textOutlinePen2 = new Pen(new SolidBrush(Color.Orange), (float)1);
textOutlinePen.EndCap = LineCap.Round;
textOutlinePen.LineJoin = LineJoin.Round;
textOutlinePen.MiterLimit = 0;
PointF textAnchor2 = new PointF(anchorPoint2.X, anchorPoint2.Y);
ShiftTextAnchor_NW(textLabel, textFontSize, ref drawnArea2, textFontFamily, ref textAnchor2);
var textPath2 = new GraphicsPath();
textPath2.AddString(textLabel,
textFontFamily,
(int)FontStyle.Bold,
textFontSize,
textAnchor2,
new StringFormat()
);
graphics.DrawPath(textOutlinePen2, textPath2);
graphics.FillPath(textFillBrush, textPath2);
}
bitmap.Save(#"C:\ClosePointDrawing.png", ImageFormat.Png);
}
private static void ShiftTextAnchor_NW(string textLabel, float textFontSize, ref RectangleF drawnArea, FontFamily textFontFamily, ref PointF textAnchor)
{
GraphicsPath tempPath = new GraphicsPath();
tempPath.AddString(
textLabel,
textFontFamily,
(int)FontStyle.Bold,
textFontSize,
textAnchor,
new StringFormat()
);
var textBounds = tempPath.GetBounds();
var offsetX = textBounds.X - textAnchor.X;
var offsetY = textBounds.Y - textAnchor.Y;
textAnchor = new PointF(drawnArea.Left - (textBounds.Width + offsetX), drawnArea.Top - (textBounds.Height + offsetY));
}
When you run this code you'll get this for output: ClosePointDrawing.png
You'll notice that the text doesn't not look nice (distorted some) and also that the Black stroke outline around the circle is only lined up properly with its Teal color filled circle with the one on the left when using a 1 pixel stroke. The one on the right uses a 2 pixel stroke. You'll also see that the Red Squares are not lined up with the Teal Circle, they should be completely encapsulating it.
Now if you change the first few values in the code so that it doesn't use a large offset as follows:
float x = 0, y = 0;
PointF anchorPoint = new PointF(150, 50);
PointF anchorPoint2 = new PointF(50, 50);
You'll get this for output: ClosePointDrawing2.png
Notice that the Text looks much better, and that the strokes are perfectly lined up with the filled circles as well as the red squares.
Is there anything that can be done, so that it will render it properly with the larger matrix?
Related
I'm writing a simple application in c# .net core 6 and winform to "assemble" some pngs and write some text on it.
This is the Photoshop output. The Title "Baldur the invincible" is wrote in Diablo Light when i'm writing it with DrawString with Font("Diablo", 30, FontStyle.Regular)
and this is my output with the Font.
In photoshop i used Diablo Light font but in the list of system fonts, from C# code, i see just Diablo Regular.. and the result is different.
How i can set the fontweight ?
here some code:
// ---------------------------------------------------------------------------------------------- +
// All TEXT ------------------------------------------------------------------------------------- +
// ---------------------------------------------------------------------------------------------- +
{
//string familyName;
//string familyList = "";
//FontFamily[] fontFamilies;
//InstalledFontCollection installedFontCollection = new InstalledFontCollection();
//fontFamilies = installedFontCollection.Families;
Font title_font = new Font("Diablo", 30, FontStyle.Regular);
Font sub_font = new Font("Diablo", 25, FontStyle.Regular);
List<Font> list_fonts = new List<Font>();
list_fonts.Add(title_font);
list_fonts.Add(sub_font);
RectangleF tit_rect = new RectangleF(165, 70, w - (165 * 2), h);
//RectangleF sub_rect = new RectangleF(165, 82 + 30, w - (165 * 2), h);
var v = m_dict_titles["Title"];
string curr_string = tabbed_value[v].ToUpper();
float offsety = WriteTitleTextf2(map_back, 0, TL(curr_string, false), tit_rect, list_fonts, StringAlignment.Near, 5);
}
public void WriteOnBitmapf(Bitmap bmp, int col, Font font, String text, RectangleF rectf, StringAlignment st_align, float stringi = 0.0f)
{
float size = font.Size;
Graphics g = Graphics.FromImage(bmp);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
StringFormat format = new StringFormat()
{
Alignment = st_align,
LineAlignment = StringAlignment.Near
};
Brush br = col == 0 ? new SolidBrush(Color.FromArgb(0, 0, 0)) : new SolidBrush(Color.FromArgb(255, 255, 255));
g.DrawString(text, font, br, rectf, format);
g.Flush();
}
Here's what I do to Rotate and Scale. But so far, if the rotation is working, the scaling isn't and vice versa. So how do I combine rotation and scaling in one method? I feels like they can't coexist using my code.
....................................................................................................................................................................
Here's what I have for now:
Image Drawing:
public LayerClass ImageDrawing(LayerClass.Type img, Bitmap bm, Rectangle imgRect, String filepath, int angle, PaintEventArgs e)
{
bm = ImageClass.GrayscaleImage(bm);
bm = MakeTransparentImage(bm);
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
bm = RotateImage(bm, angle, imgRect);
imgRect = new Rectangle((int)(Shape.center.X - (bm.Width / 2)), (int)(Shape.center.Y - (bm.Height / 2)), (int)bm.Width, (int)bm.Height);
e.Graphics.DrawImage(bm, imgRect);
this.imageBitmap = bm;
this.filePath = filePath;
this.rotationAngle = angle;
this.location = location;
this.imageRect = imgRect;
return new LayerClass(LayerClass.Type.Image, this, filePath, imgRect);
}
Rotation:
public static Bitmap RotateImage(Bitmap bitmap, float angle, Rectangle rect)
{
Matrix matrix = new Matrix();
matrix.Translate(bitmap.Width / -2, bitmap.Height / -2, MatrixOrder.Append);
matrix.RotateAt(angle, new System.Drawing.Point(0, 0), MatrixOrder.Append);
using (GraphicsPath graphicsPath = new GraphicsPath())
{
graphicsPath.AddPolygon(new System.Drawing.Point[] { new System.Drawing.Point(0, 0), new System.Drawing.Point(bitmap.Width, 0), new System.Drawing.Point(0, bitmap.Height) });
graphicsPath.Transform(matrix);
System.Drawing.PointF[] points = graphicsPath.PathPoints;
rect = boundingBox(bitmap, matrix);
Bitmap resultBitmap = new Bitmap(rect.Width, rect.Height);
using (Graphics g = Graphics.FromImage(resultBitmap))
{
Matrix matrix2 = new Matrix();
matrix2.Translate(resultBitmap.Width / 2, resultBitmap.Height / 2, MatrixOrder.Append);
g.Transform = matrix2;
g.DrawImage(bitmap, points);
return resultBitmap;
}
}
}
Scaling:
private void trackBar_ScaleImg_Scroll(object sender, EventArgs e)
{
if(rb_BothImage.Checked)
{
if (imgRect.Width > imgRect.Height)
{
imgRect.Width = trackBar_ScaleImg.Value;
imgRect.Height = (int)(trackBar_ScaleImg.Value / aspect);
ImageBitmap = new Bitmap(ImageBitmap, new Size(imgRect.Width, imgRect.Height));
}
else if (imgRect.Height > imgRect.Width)
{
imgRect.Height = trackBar_ScaleImg.Value; //64mm
imgRect.Width = (int)(trackBar_ScaleImg.Value / aspect);
ImageBitmap = new Bitmap(ImageBitmap, new Size(imgRect.Width, imgRect.Height));
}
else if (imgRect.Width == imgRect.Height)
{
imgRect.Width = trackBar_ScaleImg.Value;
imgRect.Height = trackBar_ScaleImg.Value;
}
imgRect.X = (int)(Shape.center.X - (imgRect.Width / 2));
imgRect.Y = (int)(Shape.center.Y - (imgRect.Height / 2));
ImageBitmap = new Bitmap(ImageBitmap, new Size(imgRect.Width, imgRect.Height));
}
pictureBox_Canvass.Invalidate();
}
You can add another matrix transformation for scaling: matrix.Scale(2, 2, MatrixOrder.Append);
Matrix matrix = new Matrix();
matrix.Translate(bitmap.Width / -2, bitmap.Height / -2, MatrixOrder.Append);
matrix.RotateAt(angle, new System.Drawing.Point(0, 0), MatrixOrder.Append);
matrix.Scale(2, 2, MatrixOrder.Append);
using (GraphicsPath graphicsPath = new GraphicsPath())
I have a function that I use to createan array of points, so I can draw a polygon, I want to label inside of this polygons, I know it can be done using drawstring or label control, but I want to make sure I have the same orientation of the polygon in my case they are rectangles also control the font size depend on the shape size.
I tried to create a rect inside the Draw string didn't work, any Ideas
private void BuildImage()
{
Graphics refGraph = this.CreateGraphics();
IntPtr hdc = refGraph.GetHdc();
Metafile image = new Metafile(hdc, EmfType.EmfOnly, "Shapes");
using (var g = Graphics.FromImage(image))
{
g.SmoothingMode = SmoothingMode.AntiAlias;
SolidBrush myBrush = new SolidBrush(Color.Black);
Pen p = new Pen(Color.Red, 0.2f);
foreach (CircuitData.ResistorRow resistorRow in ResistorData.Resistor)
{
RectangleF rec = new RectangleF((float)(resistorRow.CenterX - resistorRow.Length / 2), (float)(resistorRow.CenterY - resistorRow.Width / 2), (float)resistorRow.Length, (float)resistorRow.Width);
float orientation = 360 - (float)resistorRow.Orientation;
PointF center = new PointF((float)resistorRow.CenterX, (float)resistorRow.CenterY);
PointF[] points = CreatePolygon(rec, center, orientation);
if (!Double.IsNaN(resistorRow.HiX) && !Double.IsNaN(resistorRow.HiY))
{
g.FillEllipse(myBrush, (float)resistorRow.HiX - 0.5f, (float)resistorRow.HiY - 0.5f, 1, 1);
g.DrawLine(p, new PointF((float)resistorRow.HiX, (float)resistorRow.HiY), center);
}
g.FillPolygon(myBrush, points);
Font drawFont = new Font("cursor", 1);
SolidBrush textBrush = new SolidBrush(Color.Blue);
//g.Transform = matrix;
g.DrawString(resistorRow.ComponentName, drawFont, textBrush, points[0]);
}
}
refGraph.ReleaseHdc(hdc);
refGraph.Dispose();
Image = image;
}
private PointF[] CreatePolygon(RectangleF rec, PointF center, float orientation)
{
PointF TL = new PointF(rec.Left, rec.Top);
PointF TR = new PointF(rec.Right, rec.Top);
PointF BL = new PointF(rec.Left, rec.Bottom);
PointF BR = new PointF(rec.Right, rec.Bottom);
PointF[] points = new PointF[] { BL, TL, TR, BR, BL };
matrix = new System.Drawing.Drawing2D.Matrix();
matrix.RotateAt(orientation, center);
matrix.TransformPoints(points);
return points;
}
Apply your rotation matrix to the graphic context you're working with:
e.Graphics.Transform = matrix;
e.Graphics.FillPolygon(textBrush, points);
e.Graphics.DrawString(resistorRow.ComponentName, drawFont, textBrush2, TL);
EDIT: Some sample code:
public class ResistorWithLabel
{
public string ComponentName { get; set; }
public RectangleF Rect { get; set; }
public float Orientation { get; set; }
public Color BackgroundColor { get; set; }
public Color ForegroundColor { get; set; }
public int FontSize { get; set; }
public void Draw(Graphics g)
{
Matrix contextMatrix = g.Transform;
Matrix matrix = new Matrix();
matrix.RotateAt(Orientation, new PointF((Rect.Left+Rect.Right)/2, (Rect.Top+Rect.Bottom)/2));
SolidBrush polygonBrush = new SolidBrush(BackgroundColor);
SolidBrush textBrush = new SolidBrush(ForegroundColor);
Font font = new Font("Courier", FontSize);
PointF TL = new PointF(Rect.Left, Rect.Top);
PointF TR = new PointF(Rect.Right, Rect.Top);
PointF BL = new PointF(Rect.Left, Rect.Bottom);
PointF BR = new PointF(Rect.Right, Rect.Bottom);
PointF[] points = new PointF[] { BL, TL, TR, BR };
g.Transform = matrix;
g.FillPolygon(polygonBrush, points);
g.DrawString(ComponentName, font, textBrush, TL);
g.Transform = contextMatrix;
}
}
private void Form3_Paint(object sender, PaintEventArgs e)
{
ResistorWithLabel r1 = new ResistorWithLabel();
r1.ComponentName = "Resistor 1";
r1.Rect = new RectangleF(50, 100, 100, 50);
r1.Orientation = 25;
r1.BackgroundColor = Color.Blue;
r1.ForegroundColor = Color.Yellow;
r1.FontSize = 16;
r1.Draw(e.Graphics);
ResistorWithLabel r2 = new ResistorWithLabel();
r2.ComponentName = "Resistor 2";
r2.Rect = new RectangleF(200, 100, 200, 100);
r2.Orientation = 75;
r2.BackgroundColor = Color.Gray;
r2.ForegroundColor = Color.Orange;
r2.FontSize = 32;
r2.Draw(e.Graphics);
}
I want to auto crop the image which I took it from tablet camera. Actually I want to take the picture of id cards and need to auto corp it, I am using black background but sometimes it is too glaze and there is a reflection also, at that time its not cropped properly. Can anyone assist me with c# code to crop the images(Note : I am using phone cameras to take the image of id cards, mostly the background will be black and sometime it will be some other things).
Below I mentioned my code also:
private void ProcessImage(Bitmap bitmap)
{
// lock image
BitmapData bitmapData = bitmap.LockBits(
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, bitmap.PixelFormat);
// step 1 - turn background to black
ColorFiltering colorFilter = new ColorFiltering();
colorFilter.Red = new IntRange(0, 64);
colorFilter.Green = new IntRange(0, 64);
colorFilter.Blue = new IntRange(0, 64);
colorFilter.FillOutsideRange = false;
colorFilter.ApplyInPlace(bitmapData);
// step 2 - locating objects
BlobCounter blobCounter = new BlobCounter();
blobCounter.FilterBlobs = true;
blobCounter.MinHeight = 5;
blobCounter.MinWidth = 5;
blobCounter.ProcessImage(bitmapData);
Blob[] blobs = blobCounter.GetObjectsInformation();
bitmap.UnlockBits(bitmapData);
// step 3 - check objects' type and highlight
SimpleShapeChecker shapeChecker = new SimpleShapeChecker();
Graphics g = Graphics.FromImage(bitmap);
Pen yellowPen = new Pen(Color.Yellow, 2); // circles
Pen redPen = new Pen(Color.Red, 2); // quadrilateral
Pen brownPen = new Pen(Color.Brown, 2); // quadrilateral with known sub-type
Pen greenPen = new Pen(Color.Green, 2); // known triangle
Pen bluePen = new Pen(Color.Blue, 2); // triangle
for (int i = 0, n = blobs.Length; i < n; i++)
{
List<IntPoint> edgePoints = blobCounter.GetBlobsEdgePoints(blobs[i]);
DoublePoint center;
double radius;
List<IntPoint> corners;
// is triangle or quadrilateral
if (shapeChecker.IsConvexPolygon(edgePoints, out corners))
{
// get sub-type
PolygonSubType subType = shapeChecker.CheckPolygonSubType(corners);
Pen pen;
if (subType == PolygonSubType.Rectangle)
{
pen = (corners.Count == 4) ? redPen : bluePen;
}
else
{
pen = (corners.Count == 4) ? brownPen : greenPen;
}
//g.DrawPolygon( pen, ToPointsArray( corners ) );
if (pen.Color.Name == "Red")
{
int intdummy = 0;
g.DrawRectangle(pen, corners[0].X, corners[0].Y, 1150, 750);
//Code for corpping///////
pictureBox2.Image = bitmap;
pictureBox2.SizeMode = PictureBoxSizeMode.StretchImage;
Bitmap croppedBitmap = new Bitmap("E:\\xxx\\Vicas Tablet\\WinImager\\cropimage\\cropimage\\Testing Images\\Image1.jpg");
//croppedBitmap = croppedBitmap.Clone(new Rectangle(corners[0].X, corners[0].Y,1150,750),System.Drawing.Imaging.PixelFormat.DontCare);
croppedBitmap = croppedBitmap.Clone(
new Rectangle(corners[0].X, corners[0].Y, ((int)corners[1].X - (int)corners[0].X), ((int)corners[2].Y - (int)corners[1].Y)), System.Drawing.Imaging.PixelFormat.DontCare);
pictureBox2.Image = croppedBitmap;
////End code for cropping///////////
}
}
The following code will draw an ellipse on an image and fill that ellipse with the Tomato colour
string imageWithTransEllipsePathToSaveTo = "~/Images/imageTest.png";
Graphics g = Graphics.FromImage(sourceImage);
g.FillEllipse(Brushes.Tomato, 50, 50, 200, 200);
sourceImage.Save(Server.MapPath(imageWithTransEllipsePathToSaveTo), ImageFormat.Png);
If I change the brush to Transparent it obviously will not show because the ellipse will be transparent and the image underneath will show.
How do I set the 'background' of the ellipse to be transparent so that the image contains a transparent spot?
EDIT:
Sorry for the confusion but like this...
This is my second answer and works with an Image instead of a color brush. Unfortunately there is no RadialImageBrush (known to me). I've included code to save the image to the disk, and included usings to ensure you import the correct components. This does use WPF but it should work as part of a library or console app.
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Shapes;
namespace WpfApplication30
{
class ImageEditor
{
public static void processImage(string loc)
{
ImageSource ic = new BitmapImage(new Uri(loc, UriKind.Relative));
ImageBrush brush = new ImageBrush(ic);
Path p = new Path();
p.Fill = brush;
CombinedGeometry cb = new CombinedGeometry();
cb.GeometryCombineMode = GeometryCombineMode.Exclude;
EllipseGeometry ellipse = new EllipseGeometry(new Point(50, 50), 5, 5);
RectangleGeometry rect = new RectangleGeometry(new Rect(new Size(100, 100)));
cb.Geometry1 = rect;
cb.Geometry2 = ellipse;
p.Data = cb;
Canvas inkCanvas1 = new Canvas();
inkCanvas1.Children.Add(p);
inkCanvas1.Height = 96;
inkCanvas1.Width = 96;
inkCanvas1.Measure(new Size(96, 96));
inkCanvas1.Arrange(new Rect(new Size(96, 96)));
RenderTargetBitmap targetBitmap =
new RenderTargetBitmap((int)inkCanvas1.ActualWidth,
(int)inkCanvas1.ActualHeight,
96d, 96d,
PixelFormats.Default);
targetBitmap.Render(inkCanvas1);
using (System.IO.FileStream outStream = new System.IO.FileStream( loc.Replace(".png","Copy.png"), System.IO.FileMode.Create))
{
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(targetBitmap));
encoder.Save(outStream);
}
}
}
}
Here is the result:
You need to create a brush using a semi-transparent color.
You do that with Color.FromArgb(alpha, r, g, b), where alpha sets the opacity.
Example copied from MSDN:
public void FromArgb1(PaintEventArgs e)
{
Graphics g = e.Graphics;
// Transparent red, green, and blue brushes.
SolidBrush trnsRedBrush = new SolidBrush(Color.FromArgb(120, 255, 0, 0));
SolidBrush trnsGreenBrush = new SolidBrush(Color.FromArgb(120, 0, 255, 0));
SolidBrush trnsBlueBrush = new SolidBrush(Color.FromArgb(120, 0, 0, 255));
// Base and height of the triangle that is used to position the
// circles. Each vertex of the triangle is at the center of one of the
// 3 circles. The base is equal to the diameter of the circles.
float triBase = 100;
float triHeight = (float)Math.Sqrt(3*(triBase*triBase)/4);
// Coordinates of first circle's bounding rectangle.
float x1 = 40;
float y1 = 40;
// Fill 3 over-lapping circles. Each circle is a different color.
g.FillEllipse(trnsRedBrush, x1, y1, 2*triHeight, 2*triHeight);
g.FillEllipse(trnsGreenBrush, x1 + triBase/2, y1 + triHeight,
2*triHeight, 2*triHeight);
g.FillEllipse(trnsBlueBrush, x1 + triBase, y1, 2*triHeight, 2*triHeight);
}
You need to use a RadialGradientBrush:
RadialGradientBrush b = new RadialGradientBrush();
b.GradientOrigin = new Point(0.5, 0.5);
b.Center = new Point(0.5, 0.5);
b.RadiusX = 0.5;
b.RadiusY = 0.5;
b.GradientStops.Add(new GradientStop(Colors.Transparent,0));
b.GradientStops.Add(new GradientStop(Colors.Transparent,0.25));
b.GradientStops.Add(new GradientStop(Colors.Tomato, 0.25));
g.FillEllipse(b, 50, 50, 200, 200);