I am drawing the text using Graphics.DrawString() method, But the text height drawn is not same as which i gave.
For Eg:
Font F=new Font("Arial", 1f,GraphicUnit.Inch);
g.DrawString("M", F,Brushes.red,new Point(0,0));
By using the above code, i'm drawing the text with height 1 inch, but the text drawn is not exactly in 1 inch.
I need to Draw the text in Exact height which i'm giving. Thanks in advance..
The simplest solution will be to use a GraphicsPath. Here are the steps necessary:
Calculate the height you want in pixels: To get 1.0f inches at, say 150 dpi you need 150 pixels.
Then create a GraphicsPath and add the character or string in the font and font style you want to use, using the calculated height
Now measure the resulting height, using GetBounds.
Then scale the height up to the necessary number of pixels
Finally clear the path and add the string again with the new height
Now you can use FillPath to output the pixels..
Here is a code example. It writes the test string to a file. If you want to write it to a printer or a control using their Graphics objects, you can do it the same way; just get/set the dpi before you calculate the first estimate of the height..
The code below creates this file; the Consolas 'x' is 150 pixels tall as is the 2nd character (ox95) from the Wingdings font. (Note that I did not center the output):
// we are using these test data:
int Dpi = 150;
float targetHeight = 1.00f;
FontFamily ff = new FontFamily("Consolas");
int fs = (int) FontStyle.Regular;
string targetString = "X";
// this would be the height without the white space
int targetPixels = (int) targetHeight * Dpi;
// we write to a Btimpap. I make it large enough..
// Instead you can write to a printer or a Control surface..
using (Bitmap bmp = new Bitmap(targetPixels * 2, targetPixels * 2))
{
// either set the resolution here
// or get and use it above from the Graphics!
bmp.SetResolution(Dpi, Dpi);
using (Graphics G = Graphics.FromImage(bmp))
{
// good quality, please!
G.SmoothingMode = SmoothingMode.AntiAlias;
G.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
// target position (in pixels)
PointF p0 = new PointF(0, 0);
GraphicsPath gp = new GraphicsPath();
// first try:
gp.AddString(targetString, ff, fs, targetPixels, p0,
StringFormat.GenericDefault);
// this is the 1st result
RectangleF gbBounds = gp.GetBounds();
// now we correct the height:
float tSize = targetPixels * targetPixels / gbBounds.Height;
// and if needed the location:
p0 = new PointF(p0.X - gbBounds.X, p0.X - gbBounds.Y);
// and retry
gp.Reset();
gp.AddString(targetString, ff, fs, tSize, p0, StringFormat.GenericDefault);
// this should be good
G.Clear(Color.White);
G.FillPath(Brushes.Black, gp);
}
//now we save the image
bmp.Save("D:\\testString.png", ImageFormat.Png);
}
You may want to try using the correction factor to scale up a Font size and use DrawString after all.
There is also a way to calculate the numbers ahead using FontMetrics, but I understand the link to mean that such an approach could be font-dependent..
Related
I have a project in which I create an image with rotated text around an invisible circle.
The drawing in itself is working just fine. However, it seems that no matter the font I use, I always get the same result, which is I assume some low quality default font.
Here is the code :
Bitmap objBmpImage = new Bitmap(1000, 1000);
System.Drawing.Text.InstalledFontCollection installedFontCollection = new System.Drawing.Text.InstalledFontCollection();
FontFamily[] fontFamilies = installedFontCollection.Families;
System.Drawing.Font objFont = new System.Drawing.Font(fontFamilies.Where(x => x.Name == "Arial").FirstOrDefault(),10);
Graphics objGraphics = Graphics.FromImage(objBmpImage);
objGraphics.Clear(Color.Transparent);
float angle = (float)360.0 / (float)competences.Count();
objGraphics.TranslateTransform(500, 450);
objGraphics.RotateTransform(-90 - (angle / 3));
int nbComptetence = competences.Count();
int indexCompetence = 0;
foreach (T_Ref_Competence competence in competences)
{
byte r, g, b;
HexToInt(competence.T_Ref_CompetenceNiveau2.T_Ref_CompetenceNiveau1.Couleur, out r, out g, out b);
Brush brush = new System.Drawing.SolidBrush(Color.FromArgb(255,r,g,b));
if (indexCompetence * 2 < nbComptetence)
{
objGraphics.DrawString(competence.Nom, objFont, brush, 255, 0);
objGraphics.RotateTransform(angle);
}
else
{
objGraphics.RotateTransform(180);
objGraphics.RotateTransform(angle/2);
float textSize = objGraphics.MeasureString(competence.Nom, objFont).Width;
objGraphics.DrawString(competence.Nom, objFont, brush, -253 - textSize, 0);
objGraphics.RotateTransform(angle);
objGraphics.RotateTransform(-180);
objGraphics.RotateTransform(-angle / 2);
}
indexCompetence++;
}
I get the font using the installed families like this
System.Drawing.Text.InstalledFontCollection installedFontCollection = new System.Drawing.Text.InstalledFontCollection();
FontFamily[] fontFamilies = installedFontCollection.Families;
System.Drawing.Font objFont = new System.Drawing.Font(fontFamilies.Where(x => x.Name == "Arial").FirstOrDefault(),10);
I tried using other font but the result is always the same. Is there anything I am missing ? If not, what could be the reason ?
Thanks,
EDIT : To answer the question, what is it that I want exactly, consider this :
This image is a screenshot of a web site I am making. The chart in the middle was generated using charts.js, but its limitation force me to draw the text as a background image. It actually takes most of my screen so it can't really get much bigger than this. As you can see, the text font is pretty blurry and I would simply want it to be easier to read. I though the font was the problem, but I don't really know.
I am not really familiar with the whole image drawing part of C#, so if there are is better way to draw my text (which can change depending of many variables), I will gladly try other things.
Option 1: change text rendering
objGraphics.TextRenderingHint = TextRenderingHint.SingleBitPerPixel
Option 2: change the mode of anti aliasing
objGraphics.InterpolationMode=InterpolationMode.NearestNeighbor;
Option 3: change the DPI of the image
You'll get the best result if you scale the input image and then draw the text in higher DPI.
The default DPI for a Bitmap are 96. Probably the JS library exported with that setting.
If you want a smoother rendering of the font, you need to increase the DPI, e.g.
objBmpImage.SetResolution(1200,1200);
If you do so, you probably need to increase the number of pixels your Bitmap has.
If the "ugly" text just fitted the 1000x1000 picture, you now need 1000*1200/96=12500 pixels.
Before the change (using Arial 10 pt):
After the change (still using Arial 10 pt):
Note that the size in centimeters doesn't change. So it will still print well.
On the left is the polygon I drew using my paint-like program. On the right is the polygon drawn by System.Drawing.Bitmap/Graphics:
The code to draw it is as follows:
protected static Bitmap CropImage(Bitmap src, Vector2[] rect)
{
var result = new Bitmap(src.Width, src.Height);
using (Graphics g = Graphics.FromImage(result))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
var pen = new Pen(Color.White);
g.DrawImage(src, new Point(0,0));
var poly = rect.Select(p => p.ToPointF()).ToArray();
g.DrawPolygon(pen, poly);
}
return result;
}
poly is:
{System.Drawing.PointF[4]}
[0]: {X = 57.4230042 Y = 57.4229736}
[1]: {X = 147.058868 Y = 56.0224}
[2]: {X = 148.43277 Y = 143.951767}
[3]: {X = 58.7969131 Y = 145.352341}
Each of the black squares in the image is 50x50. If you look at poly, all the coordinates are exactly as you'd expect: poly[0] is a little above 50,50 which corresponds to inside the black square labelled "6" (as shown in left image).
So how is Graphics getting confused and putting it in the wrong spot? It looks like it's scaling the whole rect down.
You are confused. The rectangle is correct, but the background image is scaled up. Note that the 6 and the black square are a lot bigger, but the rectangle is the exact same size.
Note that the Graphics.DrawImage method scales the source image to match the destination resolution.
This method draws an image using its physical size, so the image will have its correct size in inches regardless of the resolution (dots per inch) of the display device. For example, suppose an image has a pixel width of 216 and a horizontal resolution of 72 dots per inch. If you call this method to draw that image on a device that has a resolution of 96 dots per inch, the pixel width of the rendered image will be (216/72)*96 = 288.
You should use the overload that accepts a Rectangle instead:
g.DrawImage(src, new Rectangle(0, 0, src.Width, src.Height));
using (var mem = new MemoryStream())
using (var bmp = new Bitmap(85, 54))
using (var gfx = Graphics.FromImage((Image)bmp))
{
// gfx.SmoothingMode = SmoothingMode.AntiAlias;
gfx.PageUnit = GraphicsUnit.Millimeter;
gfx.FillRectangle(Brushes.Red, new Rectangle(0, 0, bmp.Width, bmp.Height));
//add question
gfx.DrawString(captcha, new Font("Arial", 5), Brushes.Blue, bmp.Width / 2, bmp.Height/2);
//render as Jpeg
bmp.Save(mem, System.Drawing.Imaging.ImageFormat.Jpeg);
img = this.File(mem.GetBuffer(), "image/Jpeg");
}
return img;
this not work.
I need 85x54 millimeter
how do this?
I need draw for print
The size of this Bitmap is in pixels.
When you display a bitmap on a regular display a single pixel will be 1/96th of an inch. Other displays might have other DPI's (Dots Per Inch) - such as Retina displays
Most printers support at least 300 DPI.
So what you need to do is get the DPI of the screen or printer and size the bitmap accordingly or use a image format (vector?) that allows you to specify the DPI. Some bitmap formats also allow you to specify the intended DPI
Digital images are always in pixels. Never in millimeters or inches. Depending on the DPI (dots per inch) you'll use when printing, the pixels are translated to millimeters or inches.
For screen, use 72 pixels per inch, for print use 300.
For your picture (85x54mm = 3.34x2.12in) use (3.34 * 300) x (2.12 * 300) = 1002 x 637 pixels for print.
I am trying to save an image from string.
so I want to know how I can set image height and width in inches at the time of saving the image.
my code follows for image saving :
private void Base64ToImage(string base64String)
{
Image fullSizeImg = null;
byte[] imageBytes = Convert.FromBase64String(base64String);
MemoryStream ms = new MemoryStream(imageBytes);
fullSizeImg = Image.FromStream(ms, true);
System.Drawing.Image.GetThumbnailImageAbort dummyCallBack = new System.Drawing.Image.GetThumbnailImageAbort(ThumbnailCallback);
System.Drawing.Image thumbNailImg = fullSizeImg.GetThumbnailImage(700, 800, dummyCallBack, IntPtr.Zero);
thumbNailImg.Save(ImagePath, System.Drawing.Imaging.ImageFormat.Png);
fullSizeImg.Dispose();
thumbNailImg.Dispose();
}
That doesn't work. We save in pixels because an inch/cm/mile does not convert to on-screen real estate. The reason for this is that we all use different DPI settings, albeit 92 DPI seems to be one of the more common settings nowadays.
There are also varying DPI settings for printers...
To calculate the pixels from inches, you could try:
pixels = inches * someDpiSetting
but bear in mind this will not result in inches on every screen, every printout, etc.
EDIT: If you take a look at WPF you'll find that it has fantastic support for DPI, and will translate a form to the same (give or take) size regardless of DPI. Maybe that helps?
Bitmaps don't have a size in inches, their size is measured in pixels. That said most modern bitmat formats have a piece of metadata called DPI (dots per inch) that is used to translate a size in pixels to a size in inches via the simple formula:
inches = pixels / dpi
For the Image class you set metadata using the SetPropertyItem Method where the pieces of metadata we are interested in are:
PropertyTagResolutionUnit - set this to "2" for inches
PropertyTagXResolution - Essentially the X DPI as long as PropertyTagResolutionUnit is in inches.
PropertyTagYResolution - The Y DPI as long as PropertyTagResolutionUnit is in inches
See Property Item Descriptions for details.
(Actually, I realised half way through writing this that the setting of property metadata using SetPropertyItem looks really complicated - you might just be better off using Bitmat instead, which has resolution properties making the whole thing a lot easier)
As a contrast to those imperial measures and formula-only's:
// inches = pixels / dpi
// pixel = inches * dpi
// 1 centimeter = 0.393700787 inch
// pixel = cm * 0.393700787 * dpi
single sngWidth = 2.25; //cm
single sngHeight = 1.0; //cm
sngWidth *= 0.393700787 * bmpImage.HorizontalResolution; // x-Axis pixel
sngHeight *= 0.393700787 * bmpImage.VerticalResolution; // y-Axis pixel
Like so:
public static int Cm2Pixel(double WidthInCm)
{
double HeightInCm = WidthInCm;
return Cm2Pixel(WidthInCm, HeightInCm).Width;
} // End Function Cm2Pixel
public static System.Drawing.Size Cm2Pixel(double WidthInCm, double HeightInCm)
{
float sngWidth = (float)WidthInCm; //cm
float sngHeight = (float)HeightInCm; //cm
using (System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(1, 1))
{
sngWidth *= 0.393700787f * bmp.HorizontalResolution; // x-Axis pixel
sngHeight *= 0.393700787f * bmp.VerticalResolution; // y-Axis pixel
}
return new System.Drawing.Size((int)sngWidth, (int)sngHeight);
} // End Function Cm2Pixel
If you are using a Bitmap then it has the method SetResolution (http://msdn.microsoft.com/en-us/library/system.drawing.bitmap.setresolution.aspx) that allows you to set the x and y dpi which can be easily derived from your knowledge of the height and width of the image in pixels and inches that you already have.
I'm hoping here that using a Bitmap instead of an Image shouldn't be a problem. Its a subclass so I would imagine it is likely you can.
MemoryStream ms = new MemoryStream();
new FileStream(Afiladdress, FileMode.Open).CopyTo(ms);
Bitmap myimage = new Bitmap(ms);
float Width = myimage.Width / myimage.HorizontalResolution;//in INCHES
float Height= myimage.Height/ myimage.VerticalResolution;//in INCHES
I'm using the following codeproject to build an asp.net website and so far everything is good. My only problem is after the barcode is generated, a huge whitespace exist to the right of the barcode. I've been playing with this and am unable to resolve it.
Details below:
Link to Code Project Article: http://www.codeproject.com/KB/aspnet/AspBarCodes.aspx?msg=3543809
Copy of the Font is here: http://trussvillemethodist.web01.appliedi-labs.net/IDAutomationHC39M.ttf
//Working Path
string sWorkPath = "";
sWorkPath = this.Context.Server.MapPath("");
//Fonts
PrivateFontCollection fnts = new PrivateFontCollection();
fnts.AddFontFile(sWorkPath + #"\IDAutomationHC39M.ttf");
FontFamily fntfam = new FontFamily("IDAutomationHC39M", fnts);
Font oFont = new Font(fntfam, 18);
// Get the Requested code sent from the previous page.
string strCode = Request["code"].ToString();
//Graphics
//I don't know what to set the width to as I can't call the MeasureString without creating the Graphics object.
Bitmap oBitmaptemp = new Bitmap(40, 100);
Graphics oGraphicstemp = Graphics.FromImage(oBitmaptemp);
int w = (int)oGraphicstemp.MeasureString(strCode, oFont).Width + 4;
// Create a bitmap object of the width that we calculated and height of 100
Bitmap oBitmap = new Bitmap(w, 100);
// then create a Graphic object for the bitmap we just created.
Graphics oGraphics = Graphics.FromImage(oBitmap);
// Let's create the Point and Brushes for the barcode
PointF oPoint = new PointF(2f, 2f);
SolidBrush oBrushWrite = new SolidBrush(Color.Black);
SolidBrush oBrush = new SolidBrush(Color.White);
// Now lets create the actual barcode image
// with a rectangle filled with white color
oGraphics.FillRectangle(oBrush, 0, 0, w, 100);
// We have to put prefix and sufix of an asterisk (*),
// in order to be a valid barcode
oGraphics.DrawString("*" + strCode + "*", oFont, oBrushWrite, oPoint);
// Then we send the Graphics with the actual barcode
Response.ContentType = "image/gif";
oBitmap.Save(Response.OutputStream, ImageFormat.Gif);
oBitmap.Dispose();
oGraphics.Dispose();
oBrush.Dispose();
oFont.Dispose();
The code just assumes 40 pixels per character, which is why you get a lot of image left on the right of the text. You can use the MeasureString method to measure the size of the text, and use that to create an image of the correct size:
int w = (int)oGraphics.MeasureString("*123$10.00*", oFont).Width + 4;
I noticed that you don't dispose any of the objects that you are using. The Graphics, Bitmap, SolidBrush and Font objects need to be disposed.
You might also want to consider using a GIF image instead of JPEG, it's more suited for this kind of graphics.