How to set images height and width in inches? - c#

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

Related

WPF Quality of BMP Image

I'm making an app that can save to PDF image of my controls (datagrids etc).
The controls are big - width and height, with scrolls.
And my app can paginate view of this controls for saving to PDF or can save without paginating.
If i add my control to Fixed Page, it works fine, the quality is superior, but it takes a long time to save such file and it "eats" lot of space. But if i firstly make a bitmap image of this control, then save it to PDF, the quality is getting poor for some page sizes, though it makes PDF file much more lightweight.
The process goes that way:
Paginating (or not - depends on settings) with visualbrush - > Make a bitmap (bmp) -> Save to PDF.
If my page size is about A4, A3 or A2 - the quality is OK. But if i set bigger size - A1 or A0, the quality is getting so poor, that text can't be read.
If i make some other way: Paginating (or not - depends on settings) with visualbrush - > Save to PDF - without part of making bitmap image of my control, everything is good, A1 and A0 ...and even bigger page sizes looks good, but PDF file becomes much more bigger and it takes more time to save.
Is this because of some bitmap features for big sizes or something goes wrong? I mean, why the quality for A4, A3 and A2 sizes is OK, and for bigger sizes is poor?
I've also tried to change dpi or render sizes and some other attributes, but i couldn't get some good result.
Here is my code for making image of control:
private Image GetPageImage(FrameworkElement element, Size pageSize, double dpiX = 0, double dpiY = 0)
{
//Get current dpi
if (dpiX == 0 || dpiY == 0) { dpiX = PrintProperties.GetDpi()[0];dpiY = PrintProperties.GetDpi()[1]; }
//Check element measure
if (!element.IsMeasureValid)
{
Size size = new Size(element.Width, element.Height);
element.Measure(size);
element.Arrange(new Rect(size));
}
element.ApplyTemplate();
element.UpdateLayout();
Image pageImage = new Image();
double renderHeight = element.Height;
double renderWidth = element.Width;
if (element.DesiredSize.Width > (pageSize.Width-2*_margin) || element.DesiredSize.Height> (pageSize.Height-2*_margin))
{
if(element.Height>element.Width)
{
renderHeight = pageSize.Height - _margin * 2;
renderWidth = element.Width*(renderHeight / element.Height);
}
else
{
renderWidth = pageSize.Width - _margin * 2;
renderHeight = element.Height * (renderWidth / element.Width);
}
}
element.RenderSize = new Size(renderWidth, renderHeight);
var rect = new Rect(element.RenderSize);
var visual = new DrawingVisual();
using (var dc = visual.RenderOpen())
{
dc.DrawRectangle(new VisualBrush(element), null, rect);
}
var bitmap = new RenderTargetBitmap((int)element.Width, (int)element.Height, dpiX, dpiY, PixelFormats.Default);
bitmap.Render(visual);
pageImage.Source = bitmap;
return pageImage;
}

Reduce image size in C#

I want function which will reduce image size.
The function should take the image URL, check is image 4MB size or bigger and if it is then resize it to lover then 4MB and return bytes.
I have next method:
public byte[] ResizeImage(string url)
{
var uri = new Uri(url);
var c = new WebClient();
var oldImgStream = new MemoryStream(c.DownloadData(uri));
if (oldImgStream.Length <= 4194304)
{
return oldImgStream.ToArray();
}
using (var oldImage = new Bitmap(oldImgStream))
using (var newImageStream = new MemoryStream())
{
var format = oldImage.RawFormat;
float resizePercent = (float)4194304 / oldImgStream.Length;
var newImage = ResizeImageByPercent(oldImage, resizePercent);
newImage.Save(newImageStream, format);
return newImageStream.ToArray();
}
}
public static Bitmap ResizeImageByPercent(Bitmap image, float resizePercent)
{
//Set minimum resizePercentage to 80%
resizePercent = resizePercent > 0.8 ? (float)0.8 : resizePercent;
int newWidth = (int)(image.Width * resizePercent);
int newHeight = (int)(image.Height * resizePercent);
var newImage = new Bitmap(newWidth, newHeight);
using (var graphics = Graphics.FromImage(newImage))
{
graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
graphics.FillRectangle(Brushes.Transparent, 0, 0, newWidth, newHeight);
graphics.DrawImage(image, 0, 0, newWidth, newHeight);
return newImage;
}
}
But this doesn't work fine.
I have an jpg image as example.
The image size is a little more then 4MB (4194587 bytes).
Resolution of the image is 2272 x 1704.
So when I try to resize this image with my method above.
It first calculate "resizePercentage" as:
float resizePercent = (float)4194304 / oldImgStream.Length;
resizePercent = (float)4194304 / 4194587;
resizePercent = 0.9999325 //(99.99325%)
But because I have set minimum of resizePercent it will be set to 0.8 (80%).
resizePercent = 0.8;
Then it will calculate new width and height with this resizePercent.
And new resolution will be: 1817 x 1363 and image is resized to new resolution.
But after it is saved to stream and it read bytes it returns even larger image.
Site of the returned image is "5146056 bytes" 5MB
So does anyone has idea how to implement this, or what is wrong this my method so it's returning larger image even resolution is reduced.
I should be able to reduce size of images png, jpg and gif
There's not a one to one correlation between image file size and resolution, when dealing with compressed bitmaps. That correlation does exist for a true bitmap (BMP, for example), since 1 pixel is always equal to a defined number of bytes (based on the colorspace).
However, when talking about compressed bitmaps, like JPEG, the file size is based on efficiency of the compression (how many colors needs to be encoded overall, how many pixels can combine based on being the same color, or how much dithering can be done to create more pixels of the same color that can be combined). That may end up being less with a lower resolution image, but it also could just as easily remain unchanged or even increase, depending on how efficient the original compression was and how what effect a lesser quantity of pixels overall has on the efficiency of the compression.
Long and short, you can't just apply a simple percentage-based reduction in resolution to ensure a certain file size. The best you could really to is gradually decrease the resolution, testing the file size with each iteration, until it's below your threshold, assuming it does actually go below the threshold. With 4MB to play with, there's conceivably a certain resolution that would definitely be below that, but where that point lies is virtually impossible to calculate.
Additionally, this will vary based on a the type of image format. JPEG functions mostly by trying to spread color out as much as possible (dithering). This is why lower quality JPEGs display artifacts. PNG and GIF are mostly indexed, though, where the overall amount of colors is attempted to be reduced (though both can also employ dithering as well). PNG further complicates matters in that it you can also have lossless PNGs, where all colors and pixels are preserved but a simple compression is applied (much like a ZIP archive) to reduce file size. All of these will have different behavior from each other and at various resolutions.
try to change the quality of InterpolationMode, SmoothingMode, CompositingQuality, PixelOffsetMode. You can see that all of these are set to high quality

How to Draw a given Character in exact height?

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..

Picturebox Bitmap Scaling

I have a Picturebox and a ton of Bitmaps that can be displayed in it. The relative size of the Bitmap when compared to the others is of importance to the user. They need to be able to see that one image is smaller or bigger than another. The Bitmap must also fit in the picturebox entirely and the picturebox cannot be resized.
When simply displaying the Bitmaps unscaled in a huge picturebox the relative sizes of the bitmaps is easy to see, but when trying to fit them in a small box and having to scale them down my problem starts.
When using the Stretch PictureBoxSizeMode as you would imagine the images sometimes appear distorted due to the nonspecific sizes of the Bitmaps and the fact they then get stretched to fill the whole box regardless, but the Stretch sizemod is the closest to the kind I need.
None of the other sizemodes suit my needs so I know now I need to create a function to resize the Bitmap and here was the start of my attempt until I realized I was going in completely the wrong direction, the image returned here retains no 'scale'.
private Bitmap ResizeBitmap(Bitmap img)
{
int newWidth = 0;
int newHeight = 0;
double imgRatio;
if (img.Width > img.Height)
{
imgRatio = ((double)img.Height / (double)img.Width) * 100;
newWidth = pictureBox.Width;
newHeight = (int)(((double)newWidth / 100) * imgRatio);
}
else
{
imgRatio = ((double)img.Width / (double)img.Height) * 100;
newHeight = pictureBox.Height;
newWidth = (int)(((double)newHeight / 100) * imgRatio);
}
Bitmap newImg = new Bitmap(newWidth, newHeight);
using (Graphics g = Graphics.FromImage(newImg))
g.DrawImage(img, 0, 0, newWidth, newHeight);
return newImg;
}
I've been staring at the screen for a while now and the math to do the scaling currently eludes me, I'm hoping someone can point me in the right direction. It's almost 4am so maybe my brain just isn't grasping some simple concepts.
Set the PictureBoxSizeMode to Zoom. This maintains the aspect ratio.

How draw rectangle in millimeter

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.

Categories