I'm drawing a string on a Bitmap with transparent background using Graphics.DrawString() and I get text with a black contour, when the Font size is smaller than 23 millimeters (the Font is created with GraphicsUnit.Millimeter).
Code:
Bitmap bmp = new Bitmap(2000, 2000);
Color alpha = Color.FromArgb(0, 0, 0, 0);
for (int x = 0; x < bmp.Width; x++)
for (int y = 0; y < bmp.Height; y++)
bmp.SetPixel(x, y, alpha);
Graphics g = Graphics.FromImage(bmp);
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.SmoothingMode = SmoothingMode.HighQuality;
Font labelFont = new Font("Cascadia Mono SemiBold", 23/*22*/, FontStyle.Regular, GraphicsUnit.Millimeter);
Brush brush = new SolidBrush(Color.White);
g.DrawString("Some text", labelFont, brush, 200, 200);
23 Millimeters-Units font:
22 Millimeters-Units font:
I tried to use TextRenderer, but this draws text without transparent background.
The code presented here has multiple problems:
The initial loop is counter-productive for multiple reasons:
Tries to fill a Bitmap with a transparent color, but this is already the non-color associated with a newly created Bitmap (Color.FromArb(0, 0, 0, 0))
Uses the SetPixel() method, the slowest possible tool for the task
If needed, a Bitmap can be filled with a Color using the Graphics.Clear() method, which calls a native GDI+ function to perform the task
Setting an InterpolationMode in this context is not useful, this property selects the algorithm used to scale or rotate images
The SmoothingMode property selects the algorithm used to anti-aliasing lines, curves and the edges of filled areas. It doesn't apply to the rendering of Fonts, so has no effect on the drawn text. It applies to text rendered with a GraphicsPath, since the text is converted to curves
None of the disposable objects (Graphics, Font, Brush) is either disposed explicitly or declared with using statements (which is pretty bad). It's not clear when the Bitmap is disposed, but could be the duty of the code that uses it
To specify the rendering mode of Fonts, the TextRenderingHint property is used instead. Since it's not specified, the System default smoothing of Font is used, usually ClearType.
About this rendering form, see the notes in:
Drawing a Long String on to a Bitmap results in Drawing Issues
ClearType uses intra-pixel smoothing, designed initially for LCD screens, to blend text with a background; it's especially effective with small Fonts sizes. It doesn't support alpha colors (not in this context, at least).
The device context in which the text is rendered, a GDI+ MemoryBitmap, doesn't use or understand this type of hinting (smoothing), so the pixels that fail to render are filled with an empty color, which notoriously appears as black
A black-ish contour might manifests with different Font sizes (not just the measures reported in the question), when the ClearType hinting fill is less than one pixel
To fix the rendering, remove the clutter, specify a suitable TextRenderingHint mode and declare correctly all disposable objects.
I'm not including the Bitmap, because I don't know how it's used. It must be disposed at some point, of course (very important, it allocates unmanaged resources, the Garbage Collector cannot help you)
var bmp = new Bitmap(2000, 2000);
using (var g = Graphics.FromImage(bmp))
using (var font = new Font("Cascadia Mono SemiBold", 22, FontStyle.Regular, GraphicsUnit.Millimeter))
using (var brush = new SolidBrush(Color.White)) {
g.CompositingQuality = CompositingQuality.HighQuality;
g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
g.DrawString("Some text", font, brush, 200, 200);
}
TextRenderingHint.AntiAliasGridFit is appropriate here (see also the linked notes), the characters are drawn using their anti-aliased glyph bitmap and hinting (smoothing)
TextRenderingHint.AntiAlias can also be used in this context (and costs slightly less)
CompositingQuality.HighQuality is not actually used here, there isn't really any composition, since no image is rendered against a background (which may require gamma correction), but also has no cost. You can keep it, in case you decide to draw a bitmap onto the current, at some point; or simply remove it.
About TextRenderer draws text without transparent background
This is not correct. TextRenderer (GDI) can of course render text with a transparent background, it just doesn't support an alpha color (in this context)
As mentioned, we're working with an in-memory GDI+ Device Context
But, if you draw the same text in a different Device Context, e.g., the surface of a Control, then things change.
Also note that TextRenderer cannot be used to render text when printing (for the same reasons previously described).
Test this code, subscribing to the Paint event of a PictureBox, also adding a background Image (without a background image the result doesn't change, it's just more visible)
Graphics.DrawString() is used to render text with a semi-transparent (ARGB) Color
TextFormatFlags flags = TextFormatFlags.Left | TextFormatFlags.Top;
private void someControl_Paint(object sender, PaintEventArgs e)
{
using (var font = new Font("Segoe UI", 22, FontStyle.Regular, GraphicsUnit.Millimeter))
using (var brush = new SolidBrush(Color.White)) {
TextRenderer.DrawText(e.Graphics, "Some text", font,
new Rectangle(new Point(0, 10), pictureBox1.ClientSize), Color.White, Color.Transparent, flags);
e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
e.Graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
e.Graphics.DrawString("Some text", font, brush, 0, 130);
}
using (Font font1 = new Font("Segoe UI", 8.0f, FontStyle.Regular, GraphicsUnit.Millimeter))
using (Font font2 = new Font("Segoe UI", 5.5f, FontStyle.Regular, GraphicsUnit.Millimeter))
using (var brush = new SolidBrush(Color.FromArgb(100, Color.Black))) {
e.Graphics.DrawString("← TextRenderer", font1, brush, 610, 70);
e.Graphics.DrawString("ForeColor: White, BackColor: Transparent", font2, brush, 610, 110);
e.Graphics.DrawString("← GDI+ Graphics", font1, brush, 610, 190);
e.Graphics.DrawString("ForeColor: White, Hinting: AntiAliasGridFit", font2, brush, 610, 230);
}
}
Resulting in (enlarge it):
Heey. I wanna write a program for a report system. I wanna Show up the result in a .jpg image.
I have many variable for name, age, sex etc etc etc.
Here comes the question..
Why not do in Word?
Ya. This result should be in .jpg not .docx for because the image will be post on websites.
How should "put" variables onto image?
Heres a example for what i want: http://prntscr.com/s8bgze
You can do it like this:
// load your photo
var photo = new Bitmap("photo.jpg");
// create an image of the desired size
var bitmap = new Bitmap(200, 300);
using (var graphics = Graphics.FromImage(bitmap))
{
// specify the desired quality of the render and text, if you wish
//graphics.CompositingQuality = CompositingQuality.HighQuality;
//graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
// set background color
graphics.Clear(Color.White);
// place photo on image in desired location
graphics.DrawImageUnscaled(photo, 0, 0);
using (var font = new Font("Arial", 12))
{
// draw some text on image
graphics.DrawString("Name: X Y", font, Brushes.Black, 0, 200);
graphics.DrawString("Age: 19", font, Brushes.Black, 0, 230);
// etc
}
}
// save image to file or stream
bitmap.Save("edited.phg", ImageFormat.Png);
Instead of Graphics.DrawString method you can use TextRenderer.DrawText (they have small differences in the drawing of the text).
Also, do not use jpg format for images containing text. Instead, take png.
I'm using C# to write a text in a certain format. My problem is that when I edit font size both width and height are changing while I just want to change the font height.
My code:
using (Graphics graphics = Graphics.FromImage(bitmap))
{
using (System.Drawing.Font romanfont = new System.Drawing.Font("Times New Roman",11, FontStyle.Bold))
//using (System.Drawing.Font romanfont = new System.Drawing.Font("Times New Roman", 11, FontStyle.Bold))
{
SolidBrush transBrush = new SolidBrush(Color.FromArgb(65, 79, 79));
StringFormat format = new StringFormat(StringFormatFlags.DirectionRightToLeft);
graphics.DrawString(firstname, romanfont, transBrush, firstnameLocation, format);
graphics.DrawString(secondname, romanfont, transBrush, secondnameLocation, format);
graphics.DrawString(finalfirstadd, romanfont, transBrush, firstaddresslocation, format);
graphics.DrawString(finalsecondadd, romanfont, transBrush, secondaddresslocation, format);
}
}
You can achieve this effect by setting a transform on the Graphics object.
For example, if you want to make the text twice as tall but still the same width, you can do this:
graphics.scaleTransform(1, 2);
You would put this anywhere above the place where you draw your strings. Note that this change will make everything twice as tall, so you may need to adjust your positions and sizes of your rectangles (such as firstnameLocation; in this case you'd probably want to divide the top and height of the rectangle by 2.)
I'd like to take a bitmap with an ARGB 32 pixel format and clip it so that the contents within its inscribed ellipse remain, and anything outside the ellipse turns into ARGB(0,0,0,0).
I could do it programmatically using GetPixel and SetPixel and some trigonometry to figure out which pixel is out of bounds - but I suspect there's a better, more built-in way to do it.
Any ideas?
Thanks to Alessandro D'Andria for pointing out the region part - I've figured out the rest:
public Bitmap Rasterize()
{
Bitmap ringBmp = new Bitmap(width: _size.Width, height: _size.Height, format: PixelFormat.Format32bppArgb);
//Create an appropriate region from the inscribed ellipse
Drawing2D.GraphicsPath graphicsEllipsePath = new Drawing2D.GraphicsPath();
graphicsEllipsePath.AddEllipse(0, 0, _size.Width, _size.Height);
Region ellipseRegion = new Region(graphicsEllipsePath);
//Create a graphics object from our new bitmap
Graphics gfx = Graphics.FromImage(ringBmp);
//Draw a resized version of our image to our new bitmap while using the highest quality interpolation and within the defined ellipse region
gfx.InterpolationMode = Drawing2D.InterpolationMode.NearestNeighbor;
gfx.SmoothingMode = Drawing2D.SmoothingMode.HighQuality;
gfx.PixelOffsetMode = Drawing2D.PixelOffsetMode.HighQuality;
gfx.PageUnit = GraphicsUnit.Pixel;
gfx.Clear(Color.Transparent);
gfx.Clip = ellipseRegion;
gfx.DrawImage(image: _image, rect: new Rectangle(0, 0, _size.Width, _size.Height));
//Dispose our graphics
gfx.Dispose();
//return the resultant bitmap
return ringBmp;
}
Apparently it is extremely important to set PixelOffsetMode to HighQuality, because otherwise the DrawImage method would crop parts of the resulting image.
I need to crop sub-part from image.
For example,I have this image:
I need to crop the part of the image that in the red frame,
I have four coordinates of the frame corners,
Any idea how to implement it?
Thank you in advance.
You can use Graphics.DrawImage();
Rectangle cropRect = new Rectangle(...);
Bitmap src = Image.FromFile(fileName) as Bitmap;
Bitmap target = new Bitmap(cropRect.Width, cropRect.Height);
using(Graphics g = Graphics.FromImage(target))
{
g.DrawImage(src, new Rectangle(0, 0, target.Width, target.Height), cropRect, GraphicsUnit.Pixel);
}
And if need, you can save target to a new file.
Also See : C# Tutorial - Image Editing: Saving, Cropping, and Resizing