This question already has answers here:
How to set line spacing Graphics.DrawString
(2 answers)
Closed 6 years ago.
CodeA:
Image imageChipsetName = new System.Drawing.Bitmap(photoWidth, photoHeight);
StringFormat strFormat = new StringFormat();
strFormat.Alignment = StringAlignment.Center;
strFormat.LineAlignment = StringAlignment.Center;
Graphics graphics = Graphics.FromImage(imageChipsetName);
graphics.DrawString(stringA + "\n",
new Font("Tahoma", 14, FontStyle.Underline), Brushes.Black,
new RectangleF(0, 0, photoWidth, photoHeight), strFormat);
graphics.DrawString( stringB,
new Font("Tahoma", 14), Brushes.Black,
new RectangleF(0, 0, photoWidth, photoHeight), strFormat);
CodeB:
Image imageChipsetName = new System.Drawing.Bitmap(photoWidth, photoHeight);
StringFormat strFormat = new StringFormat();
strFormat.Alignment = StringAlignment.Center;
strFormat.LineAlignment = StringAlignment.Center;
Graphics graphics = Graphics.FromImage(imageChipsetName);
graphics.DrawString(stringA + "\n"+stringB,
new Font("Tahoma", 14, FontStyle.Underline), Brushes.Black,
new RectangleF(0, 0, photoWidth, photoHeight), strFormat);
I need to draw 2 string within a box. StringA with underline style while StringB don't.
CodeB almost achieve what I want but stringA and stringB sharing the same style. So I tested with CodeA but the program with it is that both string overlapping each other. May I know
The problem with codeA is that both stringA and stringB are drawn at the exact same position.
graphics.DrawString turns string into image and print it on the paper.
"\n" doesn't have any meaning once the string is turned into image. It will not be printed nor will it create a new line. In fact, there is no "lines" on the paper. Just image.
You need to give stringB different position. Use Graphics.MeasureString (String, Font) to measure the size of stringA, then adjust stringB's position according to the result.
Image imageChipsetName = new System.Drawing.Bitmap(photoWidth, photoHeight);
StringFormat strFormat = new StringFormat();
strFormat.Alignment = StringAlignment.Center;
strFormat.LineAlignment = StringAlignment.Center;
Font strFontA = new Font("Tahoma", 14, FontStyle.Underline);//Font used by stringA
Graphics graphics = Graphics.FromImage(imageChipsetName);
graphics.DrawString(stringA + "\n",
strFont_A, Brushes.Black,
new RectangleF(0, 0, photoWidth, photoHeight), strFormat);
SizeF stringSizeA = new SizeF();
stringSizeA = Graphics.MeasureString(stringA, strFont_A);//Measuring the size of stringA
graphics.DrawString(stringB,
new Font("Tahoma", 14), Brushes.Black,
new RectangleF(0, stringSizeA.Height, photoWidth, photoHeight - stringSizeA.Height), strFormat);
Related
I have faced underline missing issue with if I only draw text (only spaces) with underline style. Please refer the below tried code at my end and let me know the solution to resolve this.
Bitmap bitmap = new Bitmap(400, 200);
Graphics graphics = Graphics.FromImage(bitmap);
Brush brush = new SolidBrush(Color.White);
graphics.FillRectangle(brush, 0, 0, 400, 200);
System.Drawing.Font font = new System.Drawing.Font("Arial", 12, FontStyle.Underline);
brush = new SolidBrush(Color.Black);
StringFormat stringformat = new StringFormat(StringFormat.GenericTypographic);
stringformat.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
string text = "Hello";
SizeF sizeF = m_graphics.MeasureString(text, font, new PointF(0, 0), stringformat);
graphics.DrawString(text, font, brush, new RectangleF(0, 0, sizeF.Width, sizeF.Height), stringformat);
text = " ";
float width = sizeF.Width;
sizeF = m_graphics.MeasureString(text, font, new PointF(0, 0), stringformat);
graphics.DrawString(text, font, brush, new RectangleF(width, 0, sizeF.Width, sizeF.Height), stringformat);
text = "World";
width += sizeF.Width;
sizeF = m_graphics.MeasureString(text, font, new PointF(0, 0), stringformat);
graphics.DrawString(text, font, brush, new RectangleF(width, 0, sizeF.Width, sizeF.Height), stringformat);
As far as I can see you have three options:
Use a monospaced font (Courier New and Lucida Sans Typewriter). More info on the monospaced fonts here and here.
System.Drawing.Font font =
new System.Drawing.Font("Courier New", 12, FontStyle.Underline);
Write the text at once. If you only write the spaces then the method won't work, even if you use TextRenderer to draw the string. So if you receive the strings separately then I suggest add them in a StringBuilder and draw the whole text or sentence.
var sb = new StringBuilder();
sb.Append("Hello");
sb.Append(" ");
sb.Append("World!");
var bitmap = new Bitmap(400, 200);
var graphics = Graphics.FromImage(bitmap);
Brush brush = new SolidBrush(Color.White);
graphics.FillRectangle(brush, 0, 0, 400, 200);
var font = new Font("Arial", 12, FontStyle.Underline);
brush = new SolidBrush(Color.Black);
var stringformat = new StringFormat(StringFormat.GenericTypographic);
stringformat.FormatFlags = StringFormatFlags.MeasureTrailingSpaces;
stringformat.Trimming = StringTrimming.None;
var text = sb.ToString();
var sizeF = graphics.MeasureString(text, font, new PointF(0, 0), stringformat);
graphics.DrawString(text, font, brush,
new RectangleF(5, 0, sizeF.Width, sizeF.Height), stringformat);
The hack version: You can draw an invisible character such as (char)127 which is the delete character, like this (you can use the code from point 2 and add this line when initializing the StringBuilder):
sb.Append(new string ((char)127, 5)); //this will create approx. five spaces.
You can use other invisible characters if you need.
The 3rd options is a hack and should be considered as such, I would recommend option 1 if you can change the font otherwise option 2.
I have a windows application that print serial numbers in 3 of 9 bar code font. It is then scanned by RF scanners. The issue is I am not able to scan certain serial numbers like if the serial has number 8, it is not scanning. Any advise would be appreciated!
Font barFont = new Font("3 of 9 Barcode", 10);
Graphics g = ev.Graphics;
g.PageUnit = GraphicsUnit.Millimeter;
SolidBrush br = new SolidBrush(Color.Black);
RectangleF rect = new RectangleF(new PointF(15, 2), new SizeF(45, 4));
RectangleF rect1 = new RectangleF(new PointF(15, 5), new SizeF(45, 3));
RectangleF rect2 = new RectangleF(new PointF(15, 7), new SizeF(45, 4));
StringFormat sf = new StringFormat();
sf.LineAlignment = StringAlignment.Center;
sf.Alignment = StringAlignment.Center;
g.DrawString("*" + printSerial + "*", barFont, br, rect, sf);
The issue was with the bar code font installed in my system fonts. Once I refreshed with the latest version, the bar codes are scanning.
I draw text on a picturebox with:
Point text_point = new Point(0, i);
Font drawFont = new Font("Arial", 12, FontStyle.Regular, GraphicsUnit.Pixel);
SolidBrush drawBrush = new SolidBrush(Color.Black);
g.DrawString(Convert.ToString(i), drawFont, drawBrush, text_point);
... but the text is always drawn 'thick' like this:
84
How can I get it to look like: 84 ?
Try:
Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
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.
I am generating ICards for employees.
I have to write address of the employee on the ICard.
Image blankICard = Image.FromFile(#"C:\Users\admin\Pictures\filename.jpg");
Bitmap outputImage = new Bitmap(blankICard.Width, blankICard.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
System.Drawing.SolidBrush b = new SolidBrush(Color.FromArgb(255, 88, 89, 91));
using (Graphics graphics = Graphics.FromImage(outputImage))
{
graphics.DrawImage(blankICard, new Rectangle(0, 0, blankICard.Width, blankICard.Height),
new Rectangle(new Point(), blankICard.Size), GraphicsUnit.Pixel);
Font stringFont = new Font("FreightSans Medium", 20, FontStyle.Regular);
string address = "Address goes here";
graphics.DrawString(address, new Font("FreightSans Medium", 20, FontStyle.Regular), b, new Point(621, 234));
graphics.DrawString("Employee Code:12345678", new Font("FreightSans Medium", 26, FontStyle.Regular), b, new Point(350, 407));
}
Current Output is shown in the left side of the image.
Here what happens that my string goes out of the box.
I want to bind it in the fix size box.
Example is shown in the right side of the Image.
Use Graphics.DrawString overload that takes Rectangle instead of a point. That way you'll wrap text to fit within specified width.
using (Graphics graphics = Graphics.FromImage(outputImage)){
// Draw whatever you need first
// ....
// Create font...
graphics.DrawString(employeeCode, font, Brushes.Black,
new Rectangle(0, 25, maxWidth, maxHeight);
}
Simple as that :)
I made some changes to your code, commenting 2 lines - I did not have the file C:\Users\admin\Pictures\filename.jpg on my pc - That's why blankICard was disabled and so was its Rectangle:
You must set maxWidth in order to wrap your employee code, for example.
// Image blankICard = Image.FromFile(#"C:\Users\admin\Pictures\filename.jpg");
int width = 500;
int height = 500;
Bitmap outputImage = new Bitmap(width, height,PixelFormat.Format32bppArgb);
SolidBrush b = new SolidBrush(Color.FromArgb(255, 88, 89, 91));
SolidBrush blackBrush = new SolidBrush(Color.Black);
using (Graphics graphics = Graphics.FromImage(outputImage))
{
graphics.DrawRectangle(new Pen(blackBrush), new Rectangle(0, 0, width, height));
// new Rectangle(new Point(), blankICard.Size), GraphicsUnit.Pixel);
Font stringFont = new Font("FreightSans Medium", 20, FontStyle.Regular);
string address = "Address goes here";
string employeeCode = "Employee Code:12345678";
int maxWidth = 30;
SizeF sf = graphics.MeasureString(employeeCode, new Font(new FontFamily("FreightSans Medium"), 26), maxWidth);
graphics.DrawString(address, new Font("FreightSans Medium", 20, FontStyle.Regular), b, new Point(0, 0));
graphics.DrawString(employeeCode, new Font(new FontFamily("FreightSans Medium"), 26), Brushes.Black,new RectangleF(new PointF(0, 25), sf),StringFormat.GenericTypographic);
//graphics.DrawString(, new Font("FreightSans Medium", 26, FontStyle.Regular), b, new Point(10, 20));
}