Calculating image sizes - c#

Basically, I have an image which could be large (couple of thousand pixels in both height and width), and can vary quite a bit in width's and height's.
What I need to do is display these images at approximately 500 pixels in height and width - but I want to keep the aspect ratio of these intact, so the values would just be fairly close. But I'm a bit confused on what calculations I could use on the original width's and heights to get them to the right figures.
Any ideas?

Try this:
Size original = new Size(5000,4000);
double ratio = (double)original.Height/original.Width;
int resizePercent = 50;
int newWidth = Convert.ToInt32(original.Width*resizePercent/100);
int newHeight = Convert.ToInt32(newWidth * ratio);
Size resized = new Size(newWidth,newHeight);
Of course simply set original variable to your images size and determine your resize percentage. You could calculate the resize percentage if you had a target width like this:
int targetWidth = 500;
int resizePercent = Convert.ToInt32((double)original.Width/targetWidth);

I ran into this problem a couple weeks ago. Check out this article https://web.archive.org/web/20200508200042/http://www.4guysfromrolla.com:80/articles/012203-1.2.aspx
You create a Generic Handler (.ashx) that finds the image, resizes it, and returns it
Here is what I ended up using (you can resize on the fly):
public void ProcessRequest (HttpContext context) {
TimeSpan refresh = new TimeSpan(168, 0, 0);
HttpContext.Current.Response.Cache.SetExpires(DateTime.Now.Add(refresh));
HttpContext.Current.Response.Cache.SetMaxAge(refresh);
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.Public);
HttpContext.Current.Response.Cache.SetValidUntilExpires(true);
string dir = HttpContext.Current.Request.QueryString["dir"];
string img = HttpContext.Current.Request.QueryString["img"];
bool force = HttpContext.Current.Request.QueryString["force"] == "yes";
double w = 0;
double h = 0;
string path = null;
Image orig = null;
Image thumb = null;
//make sure we have a directory and image filename
if (string.IsNullOrEmpty(dir))
return;
//make sure that we allow access to that directory, could do some extra sneaky security stuff here if we had to... (only accept a DirectoryID so the user doesn't know the actual path)
switch (dir)
{
case "user":
dir = "assets/images/users";
if (string.IsNullOrEmpty(img) || img == "undefined") img = "0.jpg";
break;
break;
case "icon":
dir = "assets/images/icons";
break;
default:
dir = "assets/images";
break;
}
//make sure that the image filename is just a filename
if (img.IndexOf("/") > -1 | img.IndexOf("\\") > -1)
return;
//make sure the image exists
path = HttpContext.Current.Server.MapPath("~/" + dir + "/" + img);
if (System.IO.File.Exists(path))
{
orig = Image.FromFile(path);
}
else
{
return;
}
//if there is a max width or height
if (double.TryParse(HttpContext.Current.Request.QueryString["w"], out w) | double.TryParse(HttpContext.Current.Request.QueryString["h"], out h))
{
//thumb is the resized image
double s = 1;
if (w > 0 & h > 0)
{
double ratio = h / w;
if (orig.Height / (double)orig.Width > ratio)
{
if (orig.Height > h)
{
if (force)
s = w / (double)orig.Width;
else
s = h / (double)orig.Height;
}
}
else
{
if (orig.Width > w)
{
if (force)
s = h / (double)orig.Height;
else
s = w / (double)orig.Width;
}
}
}
else if (w > 0)
{
if (orig.Width > w)
{
s = w / (double)orig.Width;
}
}
else if (h > 0)
{
if (orig.Height > h)
{
s = h / (double)orig.Height;
}
}
//double flip gets it to lose the embedded thumbnail
//https://web.archive.org/web/20200508200042/http://www.4guysfromrolla.com:80/articles/012203-1.2.aspx
orig.RotateFlip(RotateFlipType.Rotate180FlipNone);
orig.RotateFlip(RotateFlipType.Rotate180FlipNone);
thumb = orig.GetThumbnailImage(Convert.ToInt32(orig.Width * s), Convert.ToInt32(orig.Height * s), null, IntPtr.Zero);
if (force && w > 0 & h > 0)
thumb = cropImage(thumb, (int)w, (int)h);
}
else
{
//thumb is the image at it's original size
thumb = orig;
}
HttpContext.Current.Response.ContentType = "image/jpeg";
thumb.Save(HttpContext.Current.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
}
private Image cropImage(Image img, int w, int h)
{
if (w > img.Width && h > img.Height)
return img;
Rectangle cropArea = new Rectangle((img.Width - w) / 2, (img.Height - h) / 2, w, h);
Bitmap bmpImage = new Bitmap(img);
Bitmap bmpCrop = bmpImage.Clone(cropArea, bmpImage.PixelFormat);
return (Image)(bmpCrop);
}
public bool IsReusable {
get {
return false;
}
}

Related

Remove individual pictures by size

I have a folder with images and i would like to delete some of the images by size. Unfortunately, i can’t use the File.Delete(string) method. What should I do to fix this error?
string pathName = #"C:\Users\Desktop\Images\";
DirectoryInfo dir_info = new DirectoryInfo(pathName);
foreach (FileInfo filo in dir_info.GetFiles())
{
Bitmap img = new Bitmap(filo.FullName);
int width = img.Width;
int height = img.Height;
int H = 90;
int W = 136;
if ((height >= H) && (width >= W))
{
File.Delete(filo.FullName);
}
}

C# Forms Print Image As Big As Possible [duplicate]

This question already has answers here:
c# Image resizing to different size while preserving aspect ratio
(14 answers)
Closed 4 years ago.
I want to print an image on Windows Forms, but I want to print the image as big as possible on the page without breaking its aspect ratio. Like when I want to print a simple square to A4 paper it becomes rectangle with this script:
private void Page(object sender, PrintPageEventArgs e)
{
Bitmap i = image;
if(e.PageBounds.Height > e.PageBounds.Width)
{
if (i.Width > i.Height)
i.RotateFlip(RotateFlipType.Rotate90FlipNone);
}
else if(e.PageBounds.Width > e.PageBounds.Height)
{
if (i.Height > i.Width)
i.RotateFlip(RotateFlipType.Rotate90FlipNone);
}
e.Graphics.DrawImage(i, new Rectangle(0, 0, e.PageBounds.Width, e.PageBounds.Height));
i.Dispose();
}
Original:
500x500 square
What I got (as pdf):
A rectangle on the A4 paper
Another example:
Original:Original image(313x234)
Print:Print image
I don't want to break the aspect ratio of the image
Try this:
private void Page(object sender, PrintPageEventArgs e)
{
using (Bitmap i = image) //are you *really sure* you want to dispose this after printing?
{
var pageRatio = e.PageBounds.Width / (double)e.PageBounds.Height;
var imageRatio = i.Width / (double)i.Height;
//do we need to rotate?
if ( (pageRatio < 1 && imageRatio > 1) || (pageRatio < 1 && imageRatio > 1))
{
i.RotateFlip(RotateFlipType.Rotate90FlipNone);
imageRatio = i.Width / (double)i.Height; //ratio will have changed after rotation
}
var scale = 1.0D;
//do we need to scale?
if (pageRatio > imageRatio)
{ //the page is wider than the image, so scale to the height
scale = e.PageBounds.Height / (double)i.Height;
}
else if (pageRatio < imageRatio)
{ //the page is narrower than the image, so scale to width
scale = e.PageBounds.Width / (double)i.Width;
}
var W = (int)(scale * i.Width);
var H = (int)(scale * i.Height);
e.Graphics.DrawImage(i, new Rectangle(0, 0, W, H));
}
}
This will always draw from the top left corner. If you want it centered, you need to make additional adjustments:
private void Page(object sender, PrintPageEventArgs e)
{
using (Bitmap i = image) //are you *really sure* you want to dispose this after printing?
{
var pageRatio = e.PageBounds.Width / (double)e.PageBounds.Height;
var imageRatio = i.Width / (double)i.Height;
//do we need to rotate?
if ( (pageRatio < 1 && imageRatio > 1) || (pageRatio < 1 && imageRatio > 1))
{
i.RotateFlip(RotateFlipType.Rotate90FlipNone);
imageRatio = i.Width / (double)i.Height; //ratio will have changed after rotation
}
int T = 0, L = 0; //top, left
var scale = 1.0D;
int W = i.Width, H = i.Height;
//do we need to scale?
if (pageRatio > imageRatio)
{ //the page is wider than the image, so scale to the height
scale = e.PageBounds.Height / (double)i.Height;
W = (int)(scale * i.Width);
H = (int)(scale * i.Height);
L = (e.PageBounds.Width - W)/2;
}
else if (pageRatio < imageRatio)
{ //the page is narrower than the image, so scale to width
scale = e.PageBounds.Width / (double)i.Width;
W = (int)(scale * i.Width);
H = (int)(scale * i.Height);
T = (e.PageBounds.Height - H)/2;
}
e.Graphics.DrawImage(i, new Rectangle(L, T, W+L, H+T));
}
}
The important thing is both the width and height are adjusted to the same scale... that is, multiplied by the same number.

Send Arabic text as Bitmap

I want to Send Arabic text as Bitmap to a POS printer since I could not print Arabic words directly to the printer. I used below code to convert a text to Bitmap :
Convert_ValueToImage("كيكه", "Simplified Arabic Fixed", 12)
public static Bitmap Convert_ValueToImage(string ValueText, string Fontname, int Fontsize)
{
//creating bitmap image
Bitmap ValueBitmap = new Bitmap(1, 1);
//FromImage method creates a new Graphics from the specified Image.
Graphics Graphics = Graphics.FromImage(ValueBitmap);
// Create the Font object for the image text drawing.
Font Font = new Font(Fontname, Fontsize);
// Instantiating object of Bitmap image again with the correct size for the text and font.
SizeF stringSize = Graphics.MeasureString(ValueText, Font);
ValueBitmap = new Bitmap(ValueBitmap, (int)stringSize.Width, (int)stringSize.Height);
Graphics = Graphics.FromImage(ValueBitmap);
//Draw Specified text with specified format
Graphics.DrawString(ValueText, Font, Brushes.Black, 0, 0);
Font.Dispose();
Graphics.Flush();
Graphics.Dispose();
return ValueBitmap; //return Bitmap Image
}
and when I assign it to pictureBox it works.
Now I want to send it to the printer. I used below method to convert the bitmap image to string with adding the image mode to the string:
public string GetArabic(Bitmap ArabicText)
{
string logo = "";
BitmapData data = GetArabicBitmapData(ArabicText);
BitArray dots = data.Dots;
byte[] width = BitConverter.GetBytes(data.Width);
int offset = 0;
MemoryStream stream = new MemoryStream();
BinaryWriter bw = new BinaryWriter(stream);
bw.Write((char)0x1B);
bw.Write('#');
bw.Write((char)0x1B);
bw.Write('3');
bw.Write((byte)24);
while (offset < data.Height)
{
bw.Write((char)0x1B);
bw.Write('*'); // bit-image mode
bw.Write((byte)33); // 24-dot double-density
bw.Write(width[0]); // width low byte
bw.Write(width[1]); // width high byte
for (int x = 0; x < data.Width; ++x)
{
for (int k = 0; k < 3; ++k)
{
byte slice = 0;
for (int b = 0; b < 8; ++b)
{
int y = (((offset / 8) + k) * 8) + b;
// Calculate the location of the pixel we want in the bit array.
// It'll be at (y * width) + x.
int i = (y * data.Width) + x;
// If the image is shorter than 24 dots, pad with zero.
bool v = false;
if (i < dots.Length)
{
v = dots[i];
}
slice |= (byte)((v ? 1 : 0) << (7 - b));
}
bw.Write(slice);
}
}
offset += 24;
bw.Write((char)0x0A);
}
// Restore the line spacing to the default of 30 dots.
bw.Write((char)0x1B);
bw.Write('3');
bw.Write((byte)30);
bw.Flush();
byte[] bytes = stream.ToArray();
return logo + Encoding.Default.GetString(bytes);
}
public BitmapData GetArabicBitmapData(Bitmap bmpFileName)
{
using (var bitmap = bmpFileName )
{
var threshold = 127;
var index = 0;
double multiplier = 570; // this depends on your printer model. for Beiyang you should use 1000
double scale = (double)(multiplier / (double)bitmap.Width);
int xheight = (int)(bitmap.Height * scale);
int xwidth = (int)(bitmap.Width * scale);
var dimensions = xwidth * xheight;
var dots = new BitArray(dimensions);
for (var y = 0; y < xheight; y++)
{
for (var x = 0; x < xwidth; x++)
{
var _x = (int)(x / scale);
var _y = (int)(y / scale);
var color = bitmap.GetPixel(_x, _y);
var luminance = (int)(color.R * 0.3 + color.G * 0.59 + color.B * 0.11);
dots[index] = (luminance < threshold);
index++;
}
}
return new BitmapData()
{
Dots = dots,
Height = (int)(bitmap.Height * scale),
Width = (int)(bitmap.Width * scale)
};
}
}
this code print a black Rectangle. what would help me is if I could print the text with white background and the size is small as the text size.

C# Getting error when generating tiles from big image

the sample panorama image url https://upload.wikimedia.org/wikipedia/commons/3/3b/360%C2%B0_Hoher_Freschen_Panorama_2.jpg which i saved in my pc and generate tile from that image programmatically and got
error like out of memory
this line throw the error Bitmap bmLevelSource =
(Bitmap)Bitmap.FromFile(levelSourceImage);
here is my program code in c# which throw the error
double maxZoom = 5;
string FILEPATH = #"C:\test\img.jpg";
string TARGETFOLDER = #"C:\test\Src";
bool REMOVEXISTINGFILES = true;
if (!System.IO.File.Exists(FILEPATH))
{
Console.WriteLine("file not exist");
return;
}
if (maxZoom >= 10)
{
Console.WriteLine("Scale multiplier should be an integer <=10");
return;
}
//Read image
Bitmap bmSource;
try
{
bmSource = (Bitmap)Bitmap.FromFile(FILEPATH);
}
catch
{
Console.WriteLine("image file not valid");
return;
}
//check directory exist
if (!System.IO.Directory.Exists(TARGETFOLDER))
{
System.IO.Directory.CreateDirectory(TARGETFOLDER);
}
else if (REMOVEXISTINGFILES)
{
string[] files = System.IO.Directory.GetFiles(TARGETFOLDER);
foreach (string file in files)
System.IO.File.Delete(file);
string[] dirs = System.IO.Directory.GetDirectories(TARGETFOLDER);
foreach (string dir in dirs)
System.IO.Directory.Delete(dir, true);
}
int actualHeight = bmSource.Height;
int actualWidth = bmSource.Width;
if (((actualHeight % 256) != 0)
||
((actualWidth % 256) != 0))
{
Console.WriteLine("image width and height pixels should be multiples of 256");
return;
}
int actualResizeSizeWidth = 1;
int level = 0;
while (level <= maxZoom)
{
string leveldirectory = System.IO.Path.Combine(TARGETFOLDER, String.Format("{0}", level));
if (!System.IO.Directory.Exists(leveldirectory))
System.IO.Directory.CreateDirectory(leveldirectory);
int rowsInLevel = Convert.ToInt32(Math.Pow(2, level));
actualResizeSizeWidth = 256 * rowsInLevel;
//create image to parse
int actualResizeSizeHeight = (actualHeight * actualResizeSizeWidth) / actualWidth;
Bitmap resized = new Bitmap(bmSource, new Size(actualResizeSizeWidth, actualResizeSizeHeight));
string levelSourceImage = System.IO.Path.Combine(leveldirectory, "level.png");
resized.Save(levelSourceImage);
for (int x = 0; x < rowsInLevel; x++)
{
string levelrowdirectory = System.IO.Path.Combine(leveldirectory, String.Format("{0}", x));
if (!System.IO.Directory.Exists(levelrowdirectory))
System.IO.Directory.CreateDirectory(levelrowdirectory);
Bitmap bmLevelSource = (Bitmap)Bitmap.FromFile(levelSourceImage);
//generate tiles
int numberTilesHeight = Convert.ToInt32(Math.Ceiling(actualResizeSizeHeight / 256.0));
for (int y = 0; y < numberTilesHeight; y++)
{
Console.WriteLine("Generating Tiles " + level.ToString() + " " + x.ToString() + " " + y.ToString()); int heightToCrop = actualResizeSizeHeight >= 256 ? 256 : actualResizeSizeHeight;
Rectangle destRect = new Rectangle(x * 256, y * 256, 256, heightToCrop);
//croped
Bitmap bmTile = bmLevelSource.Clone(destRect, System.Drawing.Imaging.PixelFormat.DontCare);
//full tile
Bitmap bmFullTile = new Bitmap(256, 256);
Graphics gfx = Graphics.FromImage(bmFullTile);
gfx.DrawImageUnscaled(bmTile, 0, 0);
bmFullTile.Save(System.IO.Path.Combine(levelrowdirectory, String.Format("{0}.png", y)));
bmFullTile.Dispose();
bmTile.Dispose();
}
}
level++;
}
i comment the below code when i run the program
if (((actualHeight % 256) != 0)
||
((actualWidth % 256) != 0))
{
Console.WriteLine("image width and height pixels should be multiples of 256");
return;
}
what is the fault for which i got the error called "Out of Memory"
Thanks
Edit
actual image height and width was 1250 and 2500.
actualResizeSizeWidth 256
actualResizeSizeHeight 128
i include a panorama image url in this post at top. can u plzz download url and execute my code at your end to see memory issue is coming?
Code Update
i modify the code a bit and dispose some Bitmap.
dispose like this way
bmLevelSource.Dispose(); and resized.Dispose();
while (level <= maxZoom)
{
string leveldirectory = System.IO.Path.Combine(TARGETFOLDER, String.Format("{0}", level));
if (!System.IO.Directory.Exists(leveldirectory))
System.IO.Directory.CreateDirectory(leveldirectory);
int rowsInLevel = Convert.ToInt32(Math.Pow(2, level));
actualResizeSizeWidth = 256 * rowsInLevel;
//create image to parse
int actualResizeSizeHeight = (actualHeight * actualResizeSizeWidth) / actualWidth;
Bitmap resized = new Bitmap(bmSource, new Size(actualResizeSizeWidth, actualResizeSizeHeight));
string levelSourceImage = System.IO.Path.Combine(leveldirectory, "level.png");
resized.Save(levelSourceImage);
for (int x = 0; x < rowsInLevel; x++)
{
string levelrowdirectory = System.IO.Path.Combine(leveldirectory, String.Format("{0}", x));
if (!System.IO.Directory.Exists(levelrowdirectory))
System.IO.Directory.CreateDirectory(levelrowdirectory);
Bitmap bmLevelSource = (Bitmap)Bitmap.FromFile(levelSourceImage);
//generate tiles
int numberTilesHeight = Convert.ToInt32(Math.Ceiling(actualResizeSizeHeight / 256.0));
for (int y = 0; y < numberTilesHeight; y++)
{
Console.WriteLine("Generating Tiles " + level.ToString() + " " + x.ToString() + " " + y.ToString()); int heightToCrop = actualResizeSizeHeight >= 256 ? 256 : actualResizeSizeHeight;
Rectangle destRect = new Rectangle(x * 256, y * 256, 256, heightToCrop);
//croped
Bitmap bmTile = bmLevelSource.Clone(destRect, System.Drawing.Imaging.PixelFormat.DontCare);
//full tile
Bitmap bmFullTile = new Bitmap(256, 256);
Graphics gfx = Graphics.FromImage(bmFullTile);
gfx.DrawImageUnscaled(bmTile, 0, 0);
bmFullTile.Save(System.IO.Path.Combine(levelrowdirectory, String.Format("{0}.png", y)));
bmFullTile.Dispose();
bmTile.Dispose();
}
bmLevelSource.Dispose();
}
level++;
resized.Dispose();
}
please see my bit modified code and give suggestion now.

How to resize my image and maintain the aspect ratio?

I'm trying to resize my picture so it fits the 640x640 size and keep the aspect ratio.
For example, if this is the original picture: http://i.imgur.com/WEMCSyd.jpg
I want to resize in this way: http://i.imgur.com/K2BalOm.jpg to keep the aspect ratio (Basically, the image is always in the middle, and keeps the aspect ratio, the rest of space remains white)
I have tried making a program in C# which has this code:
Bitmap originalImage, resizedImage;
try
{
using (FileStream fs = new FileStream(textBox1.Text, System.IO.FileMode.Open))
{
originalImage = new Bitmap(fs);
}
int imgHeight = 640;
int imgWidth = 640;
if (originalImage.Height == originalImage.Width)
{
resizedImage = new Bitmap(originalImage, imgHeight, imgWidth);
}
else
{
float aspect = originalImage.Width / (float)originalImage.Height;
int newHeight;
int newWidth;
newWidth = (int)(imgWidth / aspect);
newHeight = (int)(newWidth / aspect);
if (newWidth > imgWidth || newHeight > imgHeight)
{
if (newWidth > newHeight)
{
newWidth = newHeight;
newHeight = (int)(newWidth / aspect);
}
else
{
newHeight = newWidth;
newWidth = (int)(newHeight / aspect);
}
}
resizedImage = new Bitmap(originalImage, newWidth, newHeight);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
But it doesn't work the way I need it to.
Let (W, H) be the size of your image. Let s = max(W, H). Then you want to resize the image to (w, h) = (640 * W / s, 640 * H / s) where / denotes integer division. Note that we have w <= 640 and h <= 640 and max(w, h) = 640.
The horizontal and vertical offsets for your image inside of the new (640, 640) image are x = (640 - W) / 2 and y = (640 - H) / 2, respectively.
You can accomplish all of this by creating a new (640, 640) blank white image and then drawing your current image to the rectangle (x, y, w, h).
var sourcePath = textBox1.Text;
var destinationSize = 640;
using (var destinationImage = new Bitmap(destinationSize, destinationSize))
{
using (var graphics = Graphics.FromImage(destinationImage))
{
graphics.Clear(Color.White);
using (var sourceImage = new Bitmap(sourcePath))
{
var s = Math.Max(sourceImage.Width, sourceImage.Height);
var w = destinationSize * sourceImage.Width / s;
var h = destinationSize * sourceImage.Height / s;
var x = (destinationSize - w) / 2;
var y = (destinationSize - h) / 2;
// Use alpha blending in case the source image has transparencies.
graphics.CompositingMode = CompositingMode.SourceOver;
// Use high quality compositing and interpolation.
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.DrawImage(sourceImage, x, y, w, h);
}
}
destinationImage.Save(...);
}
Can u add max-width:100% to image tag. And define your fixed width to parent tag using css. Hope this should work no need to write c# code for the same.
Eg. <figure > <img src="" > </figure>
Css
Figure{ width:600px }
Img { max-width: 100%}

Categories