White bar, and then text watermark? - c#

I would like to apply a watermark to images.
At the moment, I am trying to use this code, but it's failing on different sized images:
public void AddWaterMark(string filePath, string watermarkText)
{
Image img = Image.FromFile(
MapPath(GlobalVariables.UploadPath + "/" + filePath));
Graphics gr = Graphics.FromImage(img);
Font font = new Font("Alial Black", 40);
Color color = Color.FromArgb(50, 241, 235, 105);
StringFormat stringFormat = new StringFormat
{
Alignment = StringAlignment.Near,
LineAlignment = StringAlignment.Near
};
gr.SmoothingMode = SmoothingMode.AntiAlias;
gr.DrawString(watermarkText, font, new SolidBrush(color),
new Point(20, img.Height - 60), stringFormat);
img.Save(MapPath(GlobalVariables.UploadPath + "/w_" + filePath));
}
Sometimes the font goes off the bottom. I want it to be text along the bottom of the image.
How do I ensure it doesn't go off the bottom?
Also, I want to enhance it slightly. I want to make a white, but transparent bar across the full length of the bottom of the image, and then write black text over it. Is this possible with drawing? So, a bar across the bottom of the image, maybe 60 pixels high, and in the middle of the 60px, I want text written (left aligned).
I am also finding the text moves arounf, depending on the file size
Here's an image that works:
http://www.listerhome.com/fulldisplay.aspx?imageid=100055
Bur sometimes, when I uploaded higher resolution images, I get this:
http://www.listerhome.com/fulldisplay.aspx?imageid=100060

You can use MeasureString function to calculate string size.
SizeF stringSize = gr.MeasureString(watermarkText, font, img.Width - 40);
gr.DrawString(watermarkText, font, new SolidBrush(color),
new RectangleF(20, img.Height - stringSize.Height, img.Width - 40, stringSize.Height),
stringFormat);

Related

How to compute the correct width of a digit in pixels?

I have a custom control that may have user customizable Font in future (the zoom is already implemented). I must fill a rectangle under two digits that form a base-10 number. I have different colors for zero, one or both of the digits.
With the font {Name = Microsoft Sans Serif Size=16} and the following Graphics.MeasureString method calls:
g.MeasureString("00", Font);
g.MeasureString("0", Font);
I get:
The size of "00" is {Width = 31.5486088 Height = 26.8124962}
The size of "0" is {Width = 19.3298588 Height = 26.8124962}
The width of "0" is a lot bigger that half of the width of "00".
I know of the methods Graphics.MeasureString, it has many overloads, and I also know of the StringFormat class. How can I correctly compute the width of the '0' char?
Because the font will be user-customizable, I do not want to solve the problem using a monospace font.
If I use the following calls:
g.MeasureString("00", Font, 999, StringFormat.GenericTypographic);
g.MeasureString("0", Font, 999, StringFormat.GenericTypographic);
The width of "0" seems to be half of the width of "00", but the digits overlap when drawn with a smaller font size:
Update: In the OnPaint method of an UserControl I have this code:
Graphics g = e.Graphics;
int[] indices = { 0, 1 };
CharacterRange[] charRanges = new CharacterRange[indices.Length];
for (int chx = 0; chx < indices.Length; ++chx)
{
charRanges[chx] = new CharacterRange(indices[chx], 1);
}
StringFormat sf = new StringFormat(StringFormat.GenericDefault);
sf.SetMeasurableCharacterRanges(charRanges);
Region[] regions = e.Graphics.MeasureCharacterRanges("01", Font, e.ClipRectangle, sf);
RectangleF[] r = new RectangleF[regions.Length];
int i = 0;
foreach (Region rr in regions)
{
r[i] = rr.GetBounds(g);
g.DrawRectangle(Pens.Blue, r[i].X, r[i].Y, r[i].Width, r[i].Height);
++i;
}
g.DrawString("0", Font, Brushes.Black, r[0], sf);
g.DrawString("1", Font, Brushes.Black, r[1], sf);
The font is {Name = "Microsoft Sans Serif" Size=25}. When running the program, this is what is visible:
I want to make the digits centered in the blue rectangles. The rectangles must be as big as possible in the UserControl but also leaving space for a percent of the Height of the UserControl. The Font should adapt to the rectangles.
Small adjustments are required to make this work as intended:
TextRenderingHint.ClearTypeGridFit gives a better result when rendering the Text.
It's more precise and works well with the grid-fitting nature of Graphics.DrawString.
See the notes you can find in the answer linked below for more informations on this matter.
StringFormat alignment in both horizontal and vertical dimensions.
A modified method that allows to draw strings of any length.
If the string is larger than the container, it will be wrapped, with the current settings.
Irrelevant: Brush and Pen are declared outside the Paint event, to allow their re-definition when required.
Different implementations of MeasureCharacterRanges here:
How to highlight wrapped text in a control
About Graphics.DrawString and TextRenderingHint.ClearTypeGridFit:
Drawing a Long String on to a Bitmap results in Drawing Issues
Font 48em:
Font 16em:
Font 9em:
Pen pen = new Pen(Color.LightGreen, 1);
Brush brush = new SolidBrush(Color.White);
string sourceDigits = "010011001";
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
CharacterRange[] charRanges = new CharacterRange[sourceDigits.Length];
for (int chx = 0; chx < sourceDigits.Length; ++chx) {
charRanges[chx] = new CharacterRange(chx, 1);
}
using (StringFormat sf = new StringFormat())
{
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
sf.SetMeasurableCharacterRanges(charRanges);
Region[] regions = e.Graphics.MeasureCharacterRanges(sourceDigits, Font, e.ClipRectangle, sf);
for (int i = 0; i < regions.Length; i++) {
RectangleF rect = regions[i].GetBounds(e.Graphics);
e.Graphics.DrawRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height);
e.Graphics.DrawString(char.ToString(sourceDigits[i]), Font, brush, rect, sf);
}
}
}

How to generate an image based on text with given width and no padding in C#

I want to save a given text as an image. The image should have a fixed width (200px in my example). Around the text there should be no spacing, padding or whatever. Regardless what text is entered, the width should not change, only the height of the text. This works. However, there is still white padding around the text and the text is truncated on the right side.
I have already tried to change StringFormat.GenericTypographic and also tried without AntiAlias, but I do not get it to work. Can anyone help me to get this working?
private void button1_Click(object sender, EventArgs e)
{
Font font = new Font("Arial", 1000, FontStyle.Regular);
Image i = DrawText("TEST MY STRING", font, Color.Red, Color.White);
i.Save("test.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
}
private Image DrawText(String text, Font font, Color textColor, Color backColor)
{
Image img = new Bitmap(1, 1);
Graphics drawing = Graphics.FromImage(img);
drawing.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
SizeF sz = drawing.MeasureString(text, font, 0, StringFormat.GenericTypographic);
img.Dispose();
drawing.Dispose();
/* Set maximum width of string. */
int textWidth = 200;
float sf = textWidth / sz.Width;
int textHeight = (int)(sz.Height * sf);
img = new Bitmap(textWidth, textHeight);
drawing = Graphics.FromImage(img);
drawing.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
drawing.Clear(backColor);
drawing.ScaleTransform(sf, sf);
drawing.DrawString(text, font, Brushes.Black, 0, 0, new StringFormat(StringFormatFlags.NoWrap | StringFormatFlags.NoClip));
drawing.Save();
drawing.Dispose();
return img;
}

is it possible to achieve bevelled text and drop shadows using GDI in c#?

I'm looking to expand my 'simple' photography events system to add the ability to add custom text to images we've shot. I technically have this aspect working using the existing picturebox control to display the image and a text box in which text can be entered and this will be added to the image being displayed.
However, being a photographer, I'd like the text to look a little nicer and as such am looking to emulate what I can do in Photoshop, i.e. bevel/emboss, add inner glows and drop shadows to this text but I'm struggling to find any references to this.
I may be simply limited by the fact I'm using winforms and this may have been achievable via WPF, but WPF wasn't about when I stopped being a programmer for a profession and as such stuck to technology I knew... I'm also far too far down the line in the system to re-write it all in WPF, so if its a limitation I'll just look at adding in pre-determined overlays rather than custom text which I know I can achieve.
The code I have so far is as follows and any tips on how to expand this to perform the bevel/emboss, glows etc would be much appreciated.
public static Bitmap addTexttoImage(string imagename, string textnya)
{
float fontSize = 80;
string imagepath = imagename;
Image image = Image.FromStream(new MemoryStream(File.ReadAllBytes(imagepath)));
//read the image we pass
Bitmap bmp = (Bitmap)Image.FromFile(imagepath);
Graphics g = Graphics.FromImage(bmp);
//this will centre 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();
gp.AddString(textnya, f.FontFamily, (int)FontStyle.Bold, fontSize, r, sf);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.DrawPath(p, gp);
g.FillPath(b, gp);
//cleanup
gp.Dispose();
b.Dispose();
b.Dispose();
f.Dispose();
sf.Dispose();
g.Dispose();
return bmp;
}

Bold a part of string in generated barcode

I am generating a barcode as an image. The barcode consists of few different values, such as amount, length, width and m2. These numbers are displaying below the barcode as a summary of all user entries. Is there a way to either bold or underline the m2 (square meters) in the summary under the barcode? Please see below sample of what is needed:
Here's the code I use to generate the barcode:
private void generate_Click(object sender, EventArgs e)
{
String barcode = summary.Text;
Bitmap bitmap = new Bitmap(barcode.Length * 40, 150);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
Font ofont = new System.Drawing.Font("IDAutomationHC39M", 20);
PointF point = new PointF (2f, 2f);
SolidBrush black = new SolidBrush(Color.Black);
SolidBrush White = new SolidBrush(Color.White);
graphics.FillRectangle(White, 0, 0, bitmap.Width, bitmap.Height);
graphics.DrawString("*" + barcode + "*", ofont, black, point);
}
using (MemoryStream ms = new MemoryStream())
{
bitmap.Save(ms, ImageFormat.Png);
box4.Image = bitmap;
box4.Height = bitmap.Height;
box4.Width = bitmap.Width;
}
}
You can use the constructor of Font that accepts a font style (docs)
new System.Drawing.Font("IDAutomationHC39M", 20, FontStyle.Bold);
The problem comes in determining what part of the text should be bold which means you will have to split the text up at a certain point, and ascertain the offset of the bold text
Since the font you're using (IDAutomationHC39M), renders the bar code also, this won't work unless you find a different font that will allow you to render the bars separately to the text. This leaves you with a few options.
Separate fonts
Don't make the text you want to bold
Make it stand out in a different way, colour the text in a different colour that will make it stand out / draw a line under it / etc
If this was just text
You need to break the text up into 2 parts,
string barcode1; //the normal bit
string barcode2; //the bold/underlined bit
Font ofont = new System.Drawing.Font("IDAutomationHC39M", 20);
Font ofontBold = new System.Drawing.Font("IDAutomationHC39M", 20, FontStyle.Bold);
Then render text in 3 stages, measuring the offset of each previous part:
graphics.DrawString("*" + barcode1, ofont, black, point);
var point2 = new PointF(point.X + graphics.MeasureString("*" + barcode1, ofont).Width, point.Y);
graphics.DrawString(barcode2, ofontBold, black, point2);
var point3 = new PointF(point2.X + graphics.MeasureString(barcode2, ofontBold).Width, point2.Y);
graphics.DrawString("*", ofont, black, point3);
However the font includes the lines
So I think the best you can do is to draw an underline using the same string measuring techniques:
string barcode1; //the normal bit
string barcode2; //the underlined bit
var lineStartX = point.X + graphics.MeasureString("*" + barcode1, ofont).Width;
var lineWidth = graphics.MeasureString(barcode2).Width;

Right-Aligning printed text

I'm working on printing a receipt right now, but I can't figure out how to right align text in graphics mode. I've tried a couple different things, but they're either really inefficient or don't work in my situation. Is there a way I can easily align text like to the right? Here's my code right now.
using (Font printFont = new Font("Courier New", 9.0f))
{
e.Graphics.DrawString("Subtotal:", printFont, Brushes.Black, leftMargin + 80, HeightToPrint, new StringFormat());
e.Graphics.DrawString(subtotal.ToString(), printFont, Brushes.Black, leftMargin + 150, HeightToPrint, new StringFormat());
}
In order for it to be able to right align the text, you need to specify a layout rectangle:
var format = new StringFormat() { Alignment = StringAlignment.Far };
var rect = new RectangleF( x, y, width, height );
e.Graphics.DrawString( text, font, brush, rect, format );
And it will then align the string within that rectangle.
Use the Graphics.MeasureString Method to get how long the rendered string will be and draw it at rightMargin - measuredStringWidth.

Categories

Resources