How to generate shadow under words on an image - c#

public static System.Drawing.Image GenerateGiftCard(String text, Font font, Color textColor)
{
System.Drawing.Image img = Bitmap.FromFile(#"G:\xxx\images\gift-card.jpg");
Graphics drawing = Graphics.FromImage(img);
//measure the string to see how big the image needs to be
SizeF textSize = drawing.MeasureString(text, font);
//create a brush for the text
Brush textBrush = new SolidBrush(textColor);
float x, y;
x = img.Width / 2 - textSize.Width / 2;
y = img.Height / 2 - textSize.Height / 2;
drawing.DrawString(text, font, textBrush, x, y);
drawing.Save();
textBrush.Dispose();
drawing.Dispose();
return img;
}
But the text generated by this code is "plain" not dimensional and no shadow beneath it.
This is the font style I want:
Is there anything I can do to generate the same style via my code?
Does anyone know how to use SiteMapPath or ResolveURL objects to transfer a relative path to a physical one? cheers,

First render the shadow by drawing the text with a darker, optionally translucent brush at an offset. After the shadow is rendered, overlay the regular text.
Example:
public static System.Drawing.Image GenerateGiftCard(String text, Font font, Color textColor, Color shadowColor, SizeF shadowOffset)
{
System.Drawing.Image img = Bitmap.FromFile(#"G:\xxxx\images\gift-card.jpg");
Graphics drawing = Graphics.FromImage(img);
//measure the string to see how big the image needs to be
SizeF textSize = drawing.MeasureString(text, font);
//create a brush for the text
Brush shadowBrush = new SolidBrush(shadowColor); // <-- Here
Brush textBrush = new SolidBrush(textColor);
float x, y;
x = img.Width / 2 - textSize.Width / 2;
y = img.Height / 2 - textSize.Height / 2;
drawing.DrawString(text, font, shadowBrush, x + shadowOffset.Width, y + shadowOffset.Height); // <-- Here
drawing.DrawString(text, font, textBrush, x, y);
drawing.Save();
textBrush.Dispose();
drawing.Dispose();
return img;
}

Related

Bitmap inside a bitmap

I am trying to insert an image 800x500 inside a blank bitmap of 850x610 in the center. The inner image should be in the center and It also has a title on the top. I am attaching an image to illustrate my idea:
public static Bitmap AddBorder(Bitmap srcImage)
{
Bitmap bmp = new Bitmap(srcImage.Width + 45, srcImage.Height + 100);
Graphics g = Graphics.FromImage(bmp);
g.DrawImage(srcImage, 0, 0);
g.DrawImage(srcImage, new Rectangle(bmp.Width - 1, 0, 1, bmp.Height));
g.DrawImage(srcImage, new Rectangle(0, bmp.Height - 1, bmp.Width, 1));
return bmp;
}
I have tried to draw it using drawRectangle, drawImage etc. But, I cannot pad it properly as illustrated in the above image. I also cannot add the border to inner image.
I want to get an idea about how to do that.
The below sample sets the new bitmap size, it fills it with a background (black), draws the image in the center and finally after measuring the text will align it in the center (width check only).
public static Bitmap AddBorder(Bitmap srcImage, string text)
{
Bitmap bmp = new Bitmap(850, 610);
using(Graphics g = Graphics.FromImage(bmp))
{
// Background
g.FillRectangle(Brushes.White, new Rectangle(0, 0, bmp.Width, bmp.Height));
// Source Image
Rectangle rect = new Rectangle(25, 55, 800, 500);
g.DrawImage(srcImage, rect);
// Border
int borderThickness = 2;
using(Pen pen = new System.Drawing.Pen(Brushes.Black, borderThickness))
{
pen.Alignment = System.Drawing.Drawing2D.PenAlignment.Inset;
g.DrawRectangle(pen, new Rectangle(rect.X - borderThickness, rect.Y - borderThickness, rect.Width + borderThickness, rect.Height + borderThickness));
}
// Text String
using (Font font = new Font("Arial", 16))
{
SizeF size = g.MeasureString(text, font);
g.DrawString(text, font, Brushes.Black, new PointF((bmp.Width / 2) - (size.Width / 2), rect.Top - (size.Height + borderThickness)));
}
}
return bmp;
}
Updated based on comments (Added also text above the centered image)!

How to align watermark in an image

I'm trying to add multiple watermarks to an image with some gap in between. I have been able to achieve this with two small caveats though.
What I want is:
Watermark should be vertically center aligned.
The program need to stop adding watermark when there is no sufficient width and/or height left in the image (so that there is no cutting of text).
My code is:
static void WatermarkedImage(string path, string fileName, string message, string destFileName)
{
using (Image image = Image.FromFile(path + fileName))
{
Graphics graphics = Graphics.FromImage(image);
Font font = new Font("Arial", 20, FontStyle.Bold);
SolidBrush brush = new SolidBrush(Color.FromArgb(150, 255, 0, 0));
StringFormat format = new StringFormat();
format.Alignment = StringAlignment.Center;
format.FormatFlags = StringFormatFlags.MeasureTrailingSpaces;
int index = 0;
float offsetX = image.Width / 3;
float offsetY = image.Height / 3;
int increment = Convert.ToInt32(image.Height * 0.15);
while (offsetY * 1.25 < image.Height)
{
Matrix matrix = new Matrix();
matrix.Translate(offsetX, offsetY);
matrix.Rotate(-45.0f);
graphics.Transform = matrix;
graphics.DrawString(message, font, brush, 0, 50, format);
offsetX += increment;
offsetY += increment;
index++;
}
image.Save(path + destFileName);
}
}
This is what I'm getting with this:
Desired Output.
Any help is much appreciated.
Thank You!
Update-1
To check if all of the text is inside the image, use MeasureString to see how large the string will be. From this you can construct a rectangle, transform each corner of said rectangle using the matrix, and check if they are all inside the image.
Your desired output does not have any offset on the x-axis, so you shouldn't increment x offset at all.
offsetY += increment;
index++;
}
while (offsetY * 1.25 < image.Height);
image.Save(path + destFileName);

How to add shape to an existent Picturebox image C#

I have created an Image and I want to add a rectangle around the image and recreate it as Image again to be drawn in a PictureBox
but I'm getting out of memory exception
How can I modify the image.
public void Draw(SizeF size)
{
int scale = 100;
Graphics refGraph = this.CreateGraphics();
IntPtr hdc = refGraph.GetHdc();
SolidBrush brush = new SolidBrush(Color.Black);
Pen pen = new Pen(Color.Black, 4);
try
{
Metafile image = new Metafile(hdc, EmfType.EmfOnly, "Shapes");
using (Graphics g = Graphics.FromImage(image))
{
PointF center = new PointF((float)base.Width / 2, base.Height / 2);
//Draw a rect
RectangleF Block = new RectangleF(new PointF(center.X - size.Width * scale / 2, center.Y - size.Height * scale / 2), new SizeF(size.Width * scale, size.Height * scale));
g.FillRectangle(brush, Block);
}
//Image = image;
ModifyImage(image);
}
finally
{
refGraph.ReleaseHdc(hdc);
refGraph.Dispose();
pen.Dispose();
brush.Dispose();
}
Invalidate();
}
public void ModifyImage(Metafile image)
{
Graphics g = Graphics.FromImage(image);
PointF center = new PointF((float)Image.Width / 2, Image.Height / 2);
int bufferAmount = 5;
g.DrawRectangle(Pens.White, center.X - (Image.Width + bufferAmount) / 2, center.Y - (Image.Height + bufferAmount) / 2, Image.Width + bufferAmount, Image.Height + bufferAmount);
pictureBox.Image = image;
}
Thanks
You can create a Graphics from the image using the FromImage method, then use Graphics drawing methods to draw whatever you like. Here is a code sample:
System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(yourImage);
//you may use any pen
graphics.DrawRectangle(System.Drawing.Pens.Blue,0,0,yourImageWidth,yourImageHeight)
yourPictureBox.Image = yourImage;
Create a Graphics object from your image and draw onto it by using a Pen defining the border strength and its color:
using (var gfx = Graphics.FromImage(img))
{
using (var pen = new Pen(MYCOLOR, 3)
gfx.DrawRectangle(pen, MYRECT)
}
Note, this will manipulate your source image directly. If you want to have two images, one with and another without a border, you should clone your image before you draw over it:
var imgWithBorder = img.Clone();
// work with imgWithBorder ...

DrawString - unwanted vertical offset in some fonts

I'm drawing some texts on a graphic object. With some fonts drawn text has some unwanted vertical offset.
Here is the code:
Bitmap img = new Bitmap(Width, Height);
Graphics GraphicObject = Graphics.FromImage(img);
GraphicObject.TextRenderingHint = TextRenderingHint.AntiAlias;
GraphicObject.DrawRectangle(Pens.Red, X, Y, Width, Height);
StringFormat format = new StringFormat();
format.FormatFlags = StringFormatFlags.NoClip;
GraphicObject.DrawString(
"SampleText",
new FontFamily("Font_Name"),
Color.White,
new RectangleF(X, Y, Width, Height),
format
);
And here is the result:
As you see, position of two fonts are wrong
How I can fix this issue?
After some hard works, I fixed the problem with a little dirty solution.
First I draw text on an empty Graphics object. then I'll scan for first pixel of text in y axis. This point is the y offset of font. Then I'll draw the text in my Graphics object at y - yOffset
Bitmap img = new Bitmap(Width, Height);
Graphics GraphicObject = Graphics.FromImage(img);
GraphicObject.TextRenderingHint = TextRenderingHint.AntiAlias;
GraphicObject.DrawRectangle(Pens.Red, X, Y, layer.Width, layer.Height);
StringFormat format = new StringFormat();
format.FormatFlags = StringFormatFlags.NoClip;
int yOffset = GetYOffset(layer.Width,layer.Height,TextFont,layer.Text, format);
GraphicObject.DrawString(
"SampleText",
new FontFamily("Font_Name"),
Color.White,
new RectangleF(X, Y - yOffset, layer.Width, layer.Height),
format
);
...
private int GetYOffset(int Width, int Height, System.Drawing.Font TextFont, string Text, StringFormat format)
{
Bitmap img = new Bitmap(1000, 1000);
Graphics testGaraphic = null;
testGaraphic = Graphics.FromImage(img);
testGaraphic.FillRectangle(Brushes.White, 0, 0, Width, Height);
testGaraphic.DrawString(Text, TextFont, Brushes.Black, 0, 0, format);
for (int y = 0; y < Height; y++)
for (int x = 0; x < Width; x++)
if (img.GetPixel(x, y).Name != "ffffffff")
return y;
return 0;
}
The Result:
The solution above by Ali Gonabadi saved my day. I made some modification in order to be more precise in case of anti-aliasing text. Below is the function I adapted to get X offset coordinate with a couple of modifications related to the size of the Bitmap and the SmoothingMode:
private int GetXOffset(int Width, int Height, System.Drawing.Font TextFont, string Text, StringFormat format)
{
Bitmap image = new Bitmap(Width, Height);
Graphics g = Graphics.FromImage(image);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.FillRectangle(Brushes.Black, 0, 0, Width, Height);
g.DrawString(Text, TextFont, Brushes.White, 0, 0, format);
for (int x = 0; x < Width; x++)
for (int y = 0; y < Height; y++)
if (image.GetPixel(x, y).Name != "ff000000")
return x;
return 0;
}

(C#) How to draw an "a" with Tahoma with height = 6

I've been trying to do this, but for some reason this is just giving me weird results:
int bpp = Screen.PrimaryScreen.BitsPerPixel;
string fontName = "Tahoma";
Font font = new Font(fontName, 10 * bpp, GraphicsUnit.Point);
Bitmap bm = new Bitmap(20 * bpp, 20 * bpp);
Graphics g = Graphics.FromImage(bm);
TextRenderer.DrawText(g, "a", font, new Rectangle(0, 0, 5 * bpp, 6 * bpp), Color.Black);
g.Flush();
pictureBox1.Image = bm;
What am I doing wrong here? I don't see anything printed on the picture. If I remove all bpp references, I can see it, but it's pretty small.
You are aware that BitsPerPixel describes the color depth (the number of memory bits that are used to describe the color of a pixel), and has nothing to do with resolution?
I assume that what you want to do is to draw the text in a size that is related to the resolution, which you can do by referring to the DpiX and DpiY properties of the Graphics object.
Update
I am not sure if yo need to bring Dpi into the calculation for this. All you need to do is to create a Rectangle that defines the desired size of your text, and then calculate the correct font size to make the text fit inside the rectangle. The following does that (but maximizes the text size both vertical and horizontal direction). It might give you some pointers to solve your problem:
Bitmap bm = new Bitmap(50, 50);
using (Font font = new Font(fontName, 10, GraphicsUnit.Point))
using (Graphics g = Graphics.FromImage(bm))
{
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
StringFormat stringFormat = new StringFormat()
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Near
};
Rectangle rect = new Rectangle(0, 0, bm.Width, bm.Height);
// measure how large the text is on the Graphics object with the current font size
SizeF s = g.MeasureString(text, font);
// calculate how to scale the font to make the text fit
float fontScale = Math.Max(s.Width / rect.Width, s.Height / rect.Height);
using (Font fontForDrawing = new Font(font.FontFamily, font.SizeInPoints / fontScale, GraphicsUnit.Point))
{
g.DrawString(text, fontForDrawing, Brushes.Black, rect, stringFormat);
}
}
And if you want to print the text with a given point size, you don't need to go about measuring; just set the font size:
Bitmap bm = new Bitmap(20, 20);
using (Font font = new Font(fontName, 6, GraphicsUnit.Point))
using (Graphics g = Graphics.FromImage(bm))
{
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
StringFormat stringFormat = new StringFormat()
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Near
};
Rectangle rect = new Rectangle(0, 0, bm.Width, bm.Height);
g.DrawString(text, font, Brushes.Black, rect, stringFormat);
}
I would try:
int ImgQual = 600;
int Width = 50;
int Height = 50;
Font TextFont = New Font("Tahoma", 14, FontStyle.Bold)
Bitmap bmp = New Bitmap(Width, Height);
bmp.SetResolution(ImgQual, ImgQual);
System.Drawing.Graphics g = Graphics.FromImage(bmp);
System.Drawing.StringFormat sf = New System.Drawing.StringFormat();
sf.Alignment = StringAlignment.Center;
g.DrawString("a", NumberTextFont, Brushes.Black, New RectangleF(0, 0, Width, Height), sf);
return bmp;
There are two primary reasons the "a" is small:
The height of a font is measured using a point size (which is 1/72nd of a inch, quite different from a number of pixels because different computer screens have different numbers of pixels per inch).
Font height is measured from the top of a line of text to the bottom. As some letters have ascenders (the tall bar in "h") and others have descenders (the dangly bit of a "g"), an "a" will occupy only about a third of the height of the font.
If you wish your "a" to fill the image, then you will need to draw it into a larger rectangle and "clip off" the empty regions above and below the "a". If you're not too worried about screen DPI on different computers, then you can just experiment until you find a font size (and position to draw at) that works.

Categories

Resources