Circle Cut Off in PictureBox C# - c#

i created a function which is drawing a circle with a letter inside.
i write it into a stream and set it to picture box in Zoom Mode.
It looks nice but some pieces of the circle are cut off.
Here is the Code for the Circle:
public MemoryStream GenerateCircle(string name)
{
var avatarString = string.Format("{0}", name[0]).ToUpper();
var bgColour = ColorTranslator.FromHtml("#007FBC");
var bmp = new Bitmap(70, 70);
var sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
var font = new Font("Arial", 34, FontStyle.Bold, GraphicsUnit.Pixel);
var graphics = Graphics.FromImage(bmp);
graphics.Clear(Color.White);
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
Rectangle rect = new Rectangle(0, 0, 70, 70);
Brush b = new SolidBrush(bgColour);
Pen pen = new Pen(bgColour);
graphics.DrawEllipse(pen, rect);
graphics.FillEllipse(b, rect);
graphics.DrawString(avatarString, font, new SolidBrush(Color.WhiteSmoke), 35, 35, sf);
graphics.Flush();
var ms = new MemoryStream();
bmp.Save(ms, ImageFormat.Png);
return ms;
}
i set it like that:
avatarpicturebox.Image = Image.FromStream(GenerateCircle("Test"));
That is what it looks like:
Circle Cuts Off
Can someone help here please?

Just reduce the circle's width and height 1 pixel each to avoid clipping the right and bottom sides due to the pixels offset. Use Rectangle.Inflate method and pass negative width and height values to shrink the destination rectangle to fit.
Modifying your function to return a Bitmap instead of MemoryStream.
public Bitmap GenerateCircle(string name)
{
var bgColour = ColorTranslator.FromHtml("#007FBC");
var bmp = new Bitmap(70, 70, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using (var graphics = Graphics.FromImage(bmp))
using (var sf = new StringFormat())
using (var font = new Font("Arial", 34, FontStyle.Bold, GraphicsUnit.Pixel))
using (var b = new SolidBrush(bgColour))
using (var pen = new Pen(bgColour))
{
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
graphics.Clear(Color.White);
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
graphics.PixelOffsetMode = PixelOffsetMode.Half;
Rectangle rect = new Rectangle(Point.Empty, bmp.Size);
rect.Inflate(-2, -2);
graphics.DrawEllipse(pen, rect);
graphics.FillEllipse(b, rect);
graphics.DrawString(name.ToUpper(), font, Brushes.WhiteSmoke, rect, sf);
}
return bmp;
}
And the caller:
private void SomeButton_Click(object sender, EventArgs e)
{
avatarpicturebox.Image?.Dispose();
avatarpicturebox.Image = GenerateCircle("T");
}
Side Notes
Always dispose of the graphics objects you create either by calling explicitly the .Dispose method or by creating them with using keyword.
Use the Graphics.DrawString overloads that take a Rectangle and StringFormat params to draw the strings. Use the later to dictate how and where the string should be drawn in the given Rectangle. See also StringFormatFlags enum.

Related

Bitmap.MeasureString not working as expected

I need to generate a single image, with a single character (letter) in it, which completely fills the image. I found a Bitmap.MeasureString option.
So what I tried to do was measure the size the string would be using this function, and then resizing the image to match, and then draw the letter.
But I am getting loads of white space all around the letter. I need the border of the image to be on the edges of the letter.
So a W would be a wide image, but an I would be a very narrow image.
I drew a line from the top left to bottom right to show what's happening.
Can you spot an issue with my code? Am I maybe misunderstanding this function? Or, it doesn't work as I'd hoped?
In the example image I posted, I want the top border of the image to be on the top border of the A. And the left border touching the bottom right hand of the A. And the bottom being right on the bottom edge of the A.
Here's what I am trying:
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
namespace SpikeFontToImage
{
class Program
{
static void Main(string[] args)
{
Bitmap source = new Bitmap(1, 1);
Bitmap destination;
Font stringFont = new Font("Tohoma", 1024);
string text = "A";
using (var measure = Graphics.FromImage(source))
{
var size = measure.MeasureString(text, stringFont);
Console.WriteLine($"{text} is {size} in size");
destination = new Bitmap( (int)size.Width, (int)size.Height);
RectangleF rectf = new RectangleF(0, 0, destination.Width, destination.Height);
StringFormat format = new StringFormat()
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center
};
//RectangleF rectf = new RectangleF(70, 90, 90, 50);
Graphics g = Graphics.FromImage(destination);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
g.DrawString(text, stringFont, Brushes.Black, rectf, format);
Pen pen = new Pen(Color.GreenYellow, 3);
g.DrawLine(pen, new Point(0, 0), new Point((int)size.Width, (int)size.Height));
g.Flush();
destination.Save(#"c:\temp\ccl.jpg");
}
}
}
}

created image from code, looks pixelated when printing it

I am trying to print 40x40mm labels from a programmatically created image.
The label must have text on it, and a logo. Since the label is fairly small I am finding myself fiddling with how to do proper smooting, antialias and such.
I have tried multipl settings but I am not sure it's even the right way to go about it.
First I draw the container Bitmap:
private Bitmap DrawLabelCircle()
{
var labelImage = new Bitmap(152, 152);
using (Graphics gfx = Graphics.FromImage(labelImage))
{
var pen = new Pen(Color.Black, 1);
gfx.SmoothingMode = SmoothingMode.AntiAlias;
gfx.DrawEllipse(pen, 1, 1, 150, 150);
}
return labelImage;
}
Then I overlay different text snippets on that container Bitmap
private Bitmap DrawDistributorTextRectangle(string text)
{
var bitmap = new Bitmap(113, 113);
var rectangle = new Rectangle(0, 0, 110, 110);
using (Graphics gfx = Graphics.FromImage(bitmap))
{
gfx.SmoothingMode = SmoothingMode.AntiAlias;
gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
gfx.PixelOffsetMode = PixelOffsetMode.HighQuality;
var font = new Font(FontFamily.GenericSansSerif, 5, FontStyle.Regular, GraphicsUnit.Point);
var brush = new SolidBrush(Color.Black);
gfx.TextRenderingHint = TextRenderingHint.AntiAlias;
gfx.DrawString(text, font, brush, rectangle);
}
bitmap.RotateFlip(RotateFlipType.Rotate270FlipNone);
return bitmap;
}
Overlay that text on the previous created Bitmap.
private Bitmap DistributorTextOverlay(Bitmap source, Bitmap overlay)
{
var result = new Bitmap(source.Width, source.Height);
var graphics = Graphics.FromImage(result);
graphics.CompositingMode = CompositingMode.SourceOver;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.DrawImage(source, 0, 0);
graphics.DrawImage(overlay, 120, 0);
return result;
}
And the I save it.
var imageCodecInfo = ImageCodecInfo.GetImageEncoders().First(encoder => encoder.MimeType == "image/png");
var encoderInfo = new EncoderParameters() { Param = { [0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L) } };
image.SetResolution(203, 203);
image.Save("img.png", imageCodecInfo, encoderInfo);
The big challenge here is that the image I get is actually looking alright, all things considered.
But when I print it, it looks terrible pixelated.
I would really like to give some pointers for what settings I should apply to all these bitmaps before saving the final result, and what settings should apply for the final image I save.
I am by no means a .NET graphics expert so all help is much appreciated.
40mm is 1.5748 inches. So if you plan to print it at 300 dpi resolution, your bitmap should be 1.5748*300 = 472 pixels instead of 152.

WinForms: Button with two lines, one above the other

I need to put two lines as text in a WinForms button so I have found this solution. I need first line, that above, to be printed in black color, and second line, that under the first one, to be printed in red color. My problem is that background rectangle is not transparent. I need background rectangle to be transparent so I have done some improvements but without success. Also first line is printed at the top not at center (vertical) and the distance between two lines (line spacing) there is too much separation. I would like to reduce it as well and center in vertical the two lines within the button. Below the code.
private void TextButton(Button btn, string line1, string line2)
{
btn.Text = String.Empty;
Bitmap bmp = new Bitmap(btn.ClientRectangle.Width, btn.ClientRectangle.Height);
using (Graphics G = Graphics.FromImage(bmp))
{
G.Clear(btn.BackColor);
StringFormat SF = new StringFormat();
SF.Alignment = StringAlignment.Center;
SF.LineAlignment = StringAlignment.Near;
using (Font tahoma = new Font("Tahoma", 15.75F, System.Drawing.FontStyle.Bold))
{
Rectangle RC = btn.ClientRectangle;
RC.Inflate(-5, -5);
G.FillRectangle(Brushes.Transparent,RC.X,RC.Y,RC.Width,RC.Height);
G.DrawString(line1, tahoma, Brushes.Black, RC, SF);
}
using (Font tahoma2 = new Font("Tahoma", 12))
{
SF.LineAlignment = StringAlignment.Center;
G.FillRectangle(Brushes.Transparent,btn.ClientRectangle.X,btn.ClientRectangle.Y,btn.ClientRectangle.Width,btn.ClientRectangle.Height);
G.DrawString(line2, tahoma2, Brushes.Red, btn.ClientRectangle, SF);
}
}
btn.Image = bmp;
btn.ImageAlign = ContentAlignment.MiddleCenter;
}
Finally I have solved. Below my solution.
private void TextButton(Button btn, string line1, string line2)
{
btn.Text = String.Empty;
Bitmap bmp = new Bitmap(btn.ClientRectangle.Width, btn.ClientRectangle.Height);
using (Graphics G = Graphics.FromImage(bmp))
{
G.Clear(Color.Transparent); <----- I have set this
G.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit; <--- This to avoid bad text within bitmap
G.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; <--- Also this to avoid bad text within bitmap
StringFormat SF = new StringFormat();
SF.Alignment = StringAlignment.Center;
SF.LineAlignment = StringAlignment.Near;
using (Font tahoma = new Font("Tahoma", 15.75F, System.Drawing.FontStyle.Bold))
{
Rectangle RC = new Rectangle(btn.ClientRectangle.X, btn.ClientRectangle.Y + 30, btn.ClientRectangle.Width, btn.ClientRectangle.Height-30);
RC.Inflate(-5, -5);
G.DrawString(line1, tahoma, Brushes.Black, RC, SF);
}
using (Font tahoma2 = new Font("Tahoma", 12))
{
Rectangle RC = new Rectangle(btn.ClientRectangle.X, btn.ClientRectangle.Y + 30, btn.ClientRectangle.Width, btn.ClientRectangle.Height-30);
RC.Inflate(-5, -5);
SF.LineAlignment = StringAlignment.Center;
G.DrawString(line2, tahoma2, Brushes.Red, RC, SF);
}
}
btn.Image = bmp;
btn.ImageAlign = ContentAlignment.MiddleCenter;
}

How to Drawing Text with Outline onto Images?

I have been searching and looking for Drawing text with outline onto images?
Here my code
private static void tulisnamafile(string imagepath, string textnya)
{
Image image = Image.FromStream(new MemoryStream(File.ReadAllBytes(imagepath)));
Bitmap newImage = new Bitmap(640, 380);
using (Graphics g = Graphics.FromImage(newImage))
{
// Draw base image
g.DrawImageUnscaled(image, 0, 0);
//Static is HERE
SolidBrush brushing = new SolidBrush(Color.White);
Font font = new Font(("Comic Sans MS"), 20.0f);
int napoint = newImage.Height - 90;
int napointa = image.Width - 200;
FontFamily ff = new FontFamily("Times New Roman");
int fontSize = 24;
Font f = new Font(ff, fontSize, FontStyle.Regular);
StringFormat sf = new StringFormat();
Rectangle displayRectangle = new Rectangle(new Point(5, napoint), new Size(newImage.Width - 1, newImage.Height - 1));
g.DrawEllipse(Pens.Magenta, new Rectangle(0, 0, 1, 1));
GraphicsPath gp = new GraphicsPath();
gp.AddString(textnya, ff, (int)FontStyle.Bold, fontSize + 4, new Point(0, 0), sf);
g.FillPath(Brushes.White, gp);
g.DrawPath(Pens.Black, gp);
g.Flush(FlushIntention.Sync);
g.Dispose();
}
image.Dispose();
string fileName = "ab.jpg";
string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName);
MessageBox.Show(path);
newImage.Save(path, System.Drawing.Imaging.ImageFormat.Jpeg);
newImage.Dispose();
}
and Its the trigger
private void button3_Click(object sender, EventArgs e)
{
string imagename = "C:\\Documents and Settings\\admin\\My Documents\\Visual Studio 2008\\Projects\\template\\template\\bin\\Debug\\bg.jpg";
tulisnamafile(imagename, "SlimPort® SP1002; Connect mobile devices to any big screen. High Speed micro USB");
}
Check the Code result:
Such messing result, UNWRAPPED and with white color
This what I want, and with wrapping?
I found in CodeProject but not luck, its using C++. Based someone in neowin and tried this one too..
But still not luck.
UPDATE:
Here my working code, for who maybe need it... based from Abdias Software's code ( check the answers ), I make small changes ( there some error in those code).
private static void tulisnamafile(string imagepath, string textnya)
{
float fontSize = 22;
Image image = Image.FromStream(new MemoryStream(File.ReadAllBytes(imagepath)));
//some test image for this demo
Bitmap bmp = (Bitmap)Image.FromFile(imagepath);
Graphics g = Graphics.FromImage(bmp);
//this will center align our text at the bottom of the image
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Far;
//define a font to use.
Font f = new Font("Impact", fontSize, FontStyle.Bold, GraphicsUnit.Pixel);
//pen for outline - set width parameter
Pen p = new Pen(ColorTranslator.FromHtml("#77090C"), 8);
p.LineJoin = LineJoin.Round; //prevent "spikes" at the path
//this makes the gradient repeat for each text line
Rectangle fr = new Rectangle(0, bmp.Height - f.Height, bmp.Width, f.Height);
LinearGradientBrush b = new LinearGradientBrush(fr,
ColorTranslator.FromHtml("#FF6493"),
ColorTranslator.FromHtml("#D00F14"),
90);
//this will be the rectangle used to draw and auto-wrap the text.
//basically = image size
Rectangle r = new Rectangle(0, 0, bmp.Width, bmp.Height);
GraphicsPath gp = new GraphicsPath();
//look mom! no pre-wrapping!
gp.AddString(textnya, f.FontFamily, (int)FontStyle.Bold, fontSize, r, sf);
//these affect lines such as those in paths. Textrenderhint doesn't affect
//text in a path as it is converted to ..well, a path.
g.SmoothingMode = SmoothingMode.AntiAlias;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
//TODO: shadow -> g.translate, fillpath once, remove translate
g.DrawPath(p, gp);
g.FillPath(b, gp);
//cleanup
gp.Dispose();
b.Dispose();
b.Dispose();
f.Dispose();
sf.Dispose();
g.Dispose();
string fileName = "ab.jpg";
string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName);
bmp.Save(path, System.Drawing.Imaging.ImageFormat.Jpeg);
bmp.Dispose();
}
Just to sum up:
Define a GraphicPath and then use DrawPath to draw outlined version of text, FillPath to draw a filled version.
For the second image with the woman, a second (filled) version is drawn first at a small offset.
For the gradient use LinearGradientBrush for brush. Thickness of the outline is defined by the Pen's thickness.
For wrapping define a StringFormat and use a Rectangle to define the region you want the text to be in.
To center the text you can define the rectangle to have the same width as the image, then set strformat.Alignment to Center.
UPDATE: To replicate the text in the second image you can use this code:
float fontSize = 52;
//some test image for this demo
Bitmap bmp = (Bitmap)Image.FromFile(s"test.jpg");
Graphics g = Graphics.FromImage(bmp);
//this will center align our text at the bottom of the image
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Far;
//define a font to use.
Font f = new Font("Impact", fontSize, FontStyle.Bold, GraphicsUnit.Pixel);
//pen for outline - set width parameter
Pen p = new Pen(ColorTranslator.FromHtml("#77090C"), 8);
p.LineJoin = LineJoin.Round; //prevent "spikes" at the path
//this makes the gradient repeat for each text line
Rectangle fr = new Rectangle(0, bmp.Height - f.Height, bmp.Width, f.Height);
LinearGradientBrush b = new LinearGradientBrush(fr,
ColorTranslator.FromHtml("#FF6493"),
ColorTranslator.FromHtml("#D00F14"),
90);
//this will be the rectangle used to draw and auto-wrap the text.
//basically = image size
Rectangle r = new Rectangle(0, 0, bmp.Width, bmp.Height);
GraphicsPath gp = new GraphicsPath();
//look mom! no pre-wrapping!
gp.AddString("Demo for Stack Overflow",
f.FontFamily, (int)f.Style, fontSize, r, sf);
//these affect lines such as those in paths. Textrenderhint doesn't affect
//text in a path as it is converted to ..well, a path.
g.SmoothingMode = SmoothingMode.AntiAlias;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
//TODO: shadow -> g.translate, fillpath once, remove translate
g.DrawPath(p, gp);
g.FillPath(b, gp);
//cleanup
gp.Dispose();
b.Dispose();
b.Dispose();
f.Dispose();
sf.Dispose();
g.Dispose();
bmp.Save(s"test_result.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
bmp.Dispose();
This will produce this result:
To produce the extra "shadow" just translate the gfirst, draw filled, then remove the translation.
The FromHtml is used here as I picked the colors from your image and was to lazy to convert. Just use Color.FromARGB() or a fixed color - as you want.
VB version:
Dim fontSize As Single = 52
Dim bmp As Bitmap = Bitmap.FromFile("c:\test.jpg")
Dim g As Graphics = Graphics.FromImage(bmp)
Dim sf As New StringFormat(StringFormatFlags.NoClip)
sf.Alignment = StringAlignment.Center
sf.LineAlignment = StringAlignment.Far
Dim f As New Font("Impact", fontSize, FontStyle.Bold, GraphicsUnit.Pixel)
Dim p As New Pen(ColorTranslator.FromHtml("#77090C"), 4)
p.LineJoin = LineJoin.Round
'rectangle for font to repeat gradient for each line
Dim fr As New Rectangle(0, bmp.Height - f.Height, bmp.Width, f.Height)
Dim b As New LinearGradientBrush(fr,
ColorTranslator.FromHtml("#FF6493"),
ColorTranslator.FromHtml("#D00F14"),
90)
Dim r As New Rectangle(0, 0, bmp.Width, bmp.Height)
Dim gp As New GraphicsPath
gp.AddString("Demo for Stack Overflow",
f.FontFamily,
f.Style,
fontSize,
r,
sf)
g.SmoothingMode = SmoothingMode.AntiAlias
g.PixelOffsetMode = PixelOffsetMode.HighQuality
g.DrawPath(p, gp)
g.FillPath(b, gp)
gp.Dispose() 'path
b.Dispose() 'b
b.Dispose() 'p
f.Dispose() 'font
sf.Dispose() 'stringformat
g.Dispose() 'g
bmp.Save("c:\test_result.jpg", Imaging.ImageFormat.Jpeg)
bmp.Dispose()
A simple way to get "better" results could be to draw the text twice. Draw the shadow first, for example some pixels to the right and to the bottom, if you want the classic drop-shadow look, in gray color. You may also want to consider using a different font, any font without serifs will look better i would guess.
For the gradient effect see the msdn page or google how on how to use it.
Also, play around with the SmoothingMode and TextRenderingHint of the graphics object, HighQuality and Antialias should produce better looking results.

How can I draw a small image over an image using Graphics library C# ?

When I try to draw an image over another one using Graphics library C# it scale the small one and cover the first one:
public Form1()
{
//InitializeComponent();
read_file();
InitializeComponent1();
SetStyle(ControlStyles.Opaque, true);
// theImage = new Bitmap("F:/4th year/1st Term/sensor network/proj/reconstructscene/reconstructscene/images/tryImage.jpg");
theImage2 = new Bitmap("F:/4th year/1st Term/sensor network/proj/reconstructscene/reconstructscene/images/1.jpg");
// theImage = new Bitmap(newImage);
theImage = new Bitmap("F:/4th year/1st Term/sensor network/proj/reconstructscene/reconstructscene/images/tryImage.jpg");
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
//e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
//e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
//e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.DrawImage(theImage, ClientRectangle);
// Create pen.
g.FillRectangle(new SolidBrush(Color.Red), 50, 50, 50, 50);
RectangleF recto = new System.Drawing.RectangleF(50, 50, 50, 50);
Pen blackPen = new Pen(Color.Black,1);
g.DrawRectangle(blackPen, 50, 50, 50, 50);
g.DrawImage(theImage2, ClientRectangle); //this will cover the 1st one
}
Have this instead:
g.DrawImage(theImage2, 0, 0, theImage2.Width, theImage2.Height);
This should draw the image in the "proper" place without stretching it.
look at draw on image
insteed DrawString you should use DrawImage

Categories

Resources