Drawing Text on monochrome Bitmap in C# - c#

My problem is that I need to draw text on a monochrome bitmap. The resulting bitmap has to be printed on a thermal POS printer, so the bitmap has to be 1bpp.
I'm not good in graphics, so I've tried to find some samples.
Here's what I've tried:
Bitmap bmp = new Bitmap(300, 300, PixelFormat.Format1bppIndexed);
using (Graphics g = Graphics.FromImage(bmp))
{
Font font = new Font("Arial", 20, FontStyle.Bold, GraphicsUnit.Point);
g.Clear(Color.White);
g.DrawString(text, font, Brushes.Black, 0, 0);
}
bmp.Save(#"c:\x\x.bmp", ImageFormat.Bmp);
the Save at the end was just to check the result.
With this code, I get the following exception: A Graphics object cannot be created from an image that has an indexed pixel format.
Is there ANY way to draw text to a monochrome memory bitmap?
Just for info: I need this because my stupid POS Printer draws a 0 exactly the same way as a O, so they're impossible to distinguish...

Try this:
Bitmap bmp = new Bitmap(300, 300);
using (Graphics g = Graphics.FromImage(bmp))
{
Font font = new Font("Arial", 20, FontStyle.Bold, GraphicsUnit.Point);
g.Clear(Color.White);
g.DrawString("Hello", font, Brushes.Black, 0, 0);
}
System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format1bppIndexed);
Bitmap newBitmap = new Bitmap(300, 300, bmpData.Stride, System.Drawing.Imaging.PixelFormat.Format1bppIndexed, bmpData.Scan0);
newBitmap.Save(#"c:\x\x.bmp");
Here is a link that could help:
http://msdn.microsoft.com/en-us/library/zy1a2d14.aspx

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 do I resize an image to fill the new dimensions?

I am trying to stretch an image to fit new dimensions, but I am not being able to figure out how to make the image to fill the new dimensions, it only creates a larger image size but it keeps the image untouched, I want the image to fill width and height specified.
private Bitmap resizeImage(Image image, int width, int height, float HorizontalResolution, float VerticalResolution)
{
Rectangle destRect = new Rectangle(0, 0, width, height);
Bitmap destImage = new Bitmap(width, height);
destImage.SetResolution(HorizontalResolution, VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
Since you want to stretch the entire source image to a specified size, just use the simple five-argument overload that doesn't accept source coordinates:
DrawImage(Image, Int32, Int32, Int32, Int32)
Like so:
graphics.DrawImage(image, 0, 0, width, height);
Although none of the answers worked for me, I appreciate all the help and suggestions on which I could get to a solution pretty fast, here is the piece of code that worked for me:
private Bitmap resizeImage(Image image, int width, int height, float HorizontalResolution, float VerticalResolution)
{
Rectangle destRect = new Rectangle(0, 0, width, height);
Bitmap destImage = new Bitmap(width, height);
destImage.SetResolution(HorizontalResolution, VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
//drawImage must be set this way to get the desired outcome
graphics.DrawImage(imageBox.Image, new Rectangle(0, 0, image.Width, image.Height), destRect, GraphicsUnit.Pixel);
}
return destImage;
}
Basically I removed the wrapMode code and changed my drawImage method.
You need to draw your image with the newer width and height. It will look like this:
graphics.DrawImage(image, destRect, 0, 0, destRect.Width, destRect.Height, GraphicsUnit.Pixel, wrapMode);

How to build a string that have a fixed length, and append data to it at specific starting positions?

How to build a string that have a fixed length of pixels, and append three variables to it at specific starting positions in pixels, variables data constantly changes but their starting positions are constant within the string.
// Below is what am trying to accomplish if I were to use Graphics DrawString
Bitmap bmp = new Bitmap(656, 5);
using (Graphics g = Graphics.FromImage(bmp))
{
Font font = new Font("Arial", 14, FontStyle.Regular, GraphicsUnit.Point);
g.Clear(Color.White);
g.DrawString(first_number, font, Brushes.Black, 10, 1;
g.DrawString(full_name, font, Brushes.Black, 150, 1);
g.DrawString(second_number, font, Brushes.Black, 550, 1);
}

How to draw with replacement instead of blending

I'm trying to "draw" areas of transparency onto a bitmap -- like cutting holes in the image.
The following code does not draw a line of transparency because drawing a transparent line onto a bitmap of course blends instead of replaces. (Why the default is to do the more complicated of the two drawing operations, makes no sense.)
Bitmap myBitmap = new Bitmap(50, 50);
Graphics g = Graphics.FromImage(myBitmap);
g.FillRectangle(Brushes.Black, 0, 0, 50, 50);
g.FillEllipse(Brushes.Transparent, 25, 0, 25, 25); //Does nothing
g.DrawLine(Pens.Transparent, 0, 0, 50, 50); //Does nothing
How would I modify this so that a transparent circle and line replace what's in the bitmap instead of blending?
(Note that this is the trivial case of "drawing" complete transparency. The end I'm going toward is the ability to "draw" modifying the alpha channel only without creating my own pixel by pixel operation. Being able to do complete transparency will suffice though.)
Following answer in article suggested as a duplicate, I've also tried the following (which does not work)
base.OnPaint(e);
Bitmap myBitmap = new Bitmap(50, 50);
e.Graphics.FillRectangle(Brushes.Black, 0, 0, 50, 50);
Graphics g = Graphics.FromImage(myBitmap);
g.FillEllipse(new SolidBrush(Color.FromArgb(150, 125, 125, 125)), 25, 0, 25, 25);
g.DrawLine(new Pen(Color.FromArgb(150,25,25,25)), 0, 0, 50, 50);
g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
e.Graphics.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
e.Graphics.DrawImage(myBitmap, 0, 0);
also tested this with SourceCopy
This works totally fine for me
Bitmap bmp = new Bitmap(50, 50, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
using (Graphics g = Graphics.FromImage(bmp))
{
g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
g.FillRectangle(Brushes.Black, 0, 0, 50, 50);
g.FillEllipse(Brushes.Transparent, 25, 0, 25, 25);
g.DrawLine(Pens.Transparent, 0, 0, 50, 50);
g.Flush();
}
bmp.Save("Test.bmp");

(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