I need to scale down an image that has a height or width greater than a predefined pixel value.
I wrote some code that takes a look at the original image, checks to see if either the width, the height, or the height and width are greater than the Max Width/Max Height settings.
I now need to figure out what dimensions to resize to based on the max of the latter value.
For example: If the image is 900h x 300w
and the MAX Height is 700h
I will need to resize the height to 700
and the width to ????
<-- this is what I need to calculate..
Creating and saving the image file is simple, and outside the scope of this post:
// First I get the max height and width allowed:
int resizeMaxHeight = int.Parse(Utility.GetConfigValue("ResizeMaxHeight")); // in config: 700px
int resizeMaxWidth = int.Parse(Utility.GetConfigValue("ResizeMaxWidth")); // in config: 500px
// Save original:
try
{
filebase.SaveAs(savedFileName);
}
catch (System.IO.DirectoryNotFoundException ex)
{
Logger.Instance.LogException(ex, 0, "FileTransfer");
}
// Determin original dimensions:
Image image = System.Drawing.Image.FromFile(Server.MapPath(savedFileName));
int resizeHeight, resizeWidth;
bool doResize = true;
// both height and width are greater than the allowed height and width:
if (image.Width > resizeMaxWidth && image.Height > resizeMaxHeight)
{
if (image.Height > image.Width)
resizeHeight = resizeMaxHeight;
else
resizeWidth = resizeMaxWidth;
}
else if (image.Width > resizeMaxWidth)
{
// width is too great, but height is ok
resizeWidth = resizeMaxWidth;
}
else if (image.Height > resizeMaxHeight)
{
// height is too great, but width is ok
resizeHeight = resizeMaxHeight;
}
else
{
// image is ok size, don't resize:
doResize = false;
}
Create thumbnail: This is what I'm working now... not complete:
if (doResize)
{
ImageUtilities.ResizeImage(image, resizeWidth, resizeHeight);
}
One of the simplest ways to resize an image in the HTML is using the height and width attributes on the img tag. These values specify the height and width of the image element. The values are set in px i.e. CSS pixels.
The background-size CSS property lets you resize the background image of an element, overriding the default behavior of tiling the image at its full size by specifying the width and/or height of the image. By doing so, you can scale the image upward or downward as desired.
The solution posted by Nathaniel actually fails if the image height is larger than the image width. The following example yields the correct result :
private Size ResizeFit(Size originalSize, Size maxSize)
{
var widthRatio = (double)maxSize.Width / (double)originalSize.Width;
var heightRatio = (double) maxSize.Height/(double) originalSize.Height;
var minAspectRatio = Math.Min(widthRatio, heightRatio);
if (minAspectRatio > 1)
return originalSize;
return new Size((int)(originalSize.Width*minAspectRatio), (int)(originalSize.Height*minAspectRatio));
}
Here are two ways to make this calculation. Depending upon how you think about the problem, one may seem more intuitive than the other. They are mathematically equivalent to several decimal places.
Both are safe for Math.Round, but only ConstrainVerbose produces results that are always less than maxWidth/maxHeight.
SizeF ConstrainConcise(int imageWidth, int imageHeight, int maxWidth, int maxHeight){
// Downscale by the smallest ratio (never upscale)
var scale = Math.Min(1, Math.Min(maxWidth / (float)imageWidth, maxHeight / (float) imageHeight));
return new SizeF(scale * imageWidth, scale * imageHeight);
}
SizeF ConstrainVerbose(int imageWidth, int imageHeight, int maxWidth, int maxHeight){
// Coalculate the aspect ratios of the image and bounding box
var maxAspect = (float) maxWidth / (float) maxHeight;
var aspect = (float) imageWidth / (float) imageHeight;
// Bounding box aspect is narrower
if (maxAspect <= aspect && imageWidth > maxWidth)
{
// Use the width bound and calculate the height
return new SizeF(maxWidth, Math.Min(maxHeight, maxWidth / aspect));
}
else if (maxAspect > aspect && imageHeight > maxHeight)
{
// Use the height bound and calculate the width
return new SizeF(Math.Min(maxWidth, maxHeight * aspect), maxHeight);
}else{
return new SizeF(imageWidth, imageHeight);
}
}
Brute force unit-test here
You can avoid calculating the aspect ratio (and using doubles) using a few integer tricks..
// You have the new height, you need the new width
int orgHeight = 1200;
int orgWidth = 1920;
int newHeight = 400;
int newWidth = (newHeight * orgWidth) / orgHeight; // 640
or...
// You have the new width, you need the new height.
int orgWidth = 1920;
int orgHeight = 1200;
int newWidth = 800;
int newHeight = (newWidth * orgHeight) / orgWidth; // 500
The following example will resize an image to any desired rectangle (desWidth and desHeight) and center the image within that rectangle.
static Image ResizeImage(Image image, int desWidth, int desHeight)
{
int x, y, w, h;
if (image.Height > image.Width)
{
w = (image.Width * desHeight) / image.Height;
h = desHeight;
x = (desWidth - w) / 2;
y = 0;
}
else
{
w = desWidth;
h = (image.Height * desWidth) / image.Width;
x = 0;
y = (desHeight - h) / 2;
}
var bmp = new Bitmap(desWidth, desHeight);
using (Graphics g = Graphics.FromImage(bmp))
{
g.CompositingQuality = CompositingQuality.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(image, x, y, w, h);
}
return bmp;
}
I did something similar for Bitmaps, but idea is same:
1. get image height and width
2. get current screen resolution
3. calculate aspect ratio (ASR) from image size
Handle following cases:
4. if ASR >=1 and image width > image height
if image width > screen width {}
if image height > screen height {}
else if image width > screen width {}
else {}
else
if image height > screen height {}
else if image width > screen width {}
else {}
//SCREEN_SIZE is configurable; Defs.SCREEN_SIZE = 100; // and boolPixelAR is true;
Try following code:
// PERCENTAGE OF IMAGE -> TODO: Configurable? IMAZE ZOOM / SCREEN PERCENTAGE
Double HScale = __bmp.Width;// *Defs.SCREEN_SIZE / 100;
Double VScale = __bmp.Height;// *Defs.SCREEN_SIZE / 100;
Double __aspectRatio;
Double __screenRatio = _currentScreenSize.Width / _currentScreenSize.Height;
// PERCENTAGE OF SCREEN
if (!_boolPixelAR) {
HScale = _currentScreenSize.Width * Defs.SCREEN_SIZE / 100;
VScale = _currentScreenSize.Height * Defs.SCREEN_SIZE / 100;
}
else {
__aspectRatio = HScale / VScale;
if( __aspectRatio >= 1)
if (HScale >= _currentScreenSize.Width) { // Long Edge is WIDTH. For 100%, HScale = WIDTH
VScale = ((VScale * _currentScreenSize.Width) / HScale) * Defs.SCREEN_SIZE / 100;
HScale = _currentScreenSize.Width * Defs.SCREEN_SIZE / 100;
if (VScale > _currentScreenSize.Height) { // Long Edge is HEIGHT. For 100%, VScale = HEIGHT
//__aspectRatio = VScale / HScale;
HScale = ((HScale * _currentScreenSize.Height) / VScale) * Defs.SCREEN_SIZE / 100;
VScale = _currentScreenSize.Height * Defs.SCREEN_SIZE / 100;
}
}
else if (VScale > _currentScreenSize.Height) { // Long Edge is HEIGHT. For 100%, VScale = HEIGHT
//__aspectRatio = VScale / HScale;
HScale = ((HScale * _currentScreenSize.Height) / VScale) * Defs.SCREEN_SIZE / 100;
VScale = _currentScreenSize.Height * Defs.SCREEN_SIZE / 100;
}
else {
//Do nothing... Just set Zoom.
HScale = HScale * Defs.SCREEN_SIZE / 100;
VScale = VScale * Defs.SCREEN_SIZE / 100;
}
else
if (VScale > _currentScreenSize.Height) { // Long Edge is HEIGHT. For 100%, VScale = HEIGHT
//__aspectRatio = VScale / HScale;
HScale = ((HScale * _currentScreenSize.Height) / VScale) * Defs.SCREEN_SIZE / 100;
VScale = _currentScreenSize.Height * Defs.SCREEN_SIZE / 100;
}
else if (HScale >= _currentScreenSize.Width) { // Long Edge is WIDTH. For 100%, HScale = WIDTH
VScale = ((VScale * _currentScreenSize.Width) / HScale) * Defs.SCREEN_SIZE / 100;
HScale = _currentScreenSize.Width * Defs.SCREEN_SIZE / 100;
}
else {
//Do nothing... Just set Zoom.
HScale = HScale * Defs.SCREEN_SIZE / 100;
VScale = VScale * Defs.SCREEN_SIZE / 100;
}
////__aspectRatio = VScale / HScale;
//HScale = ((HScale * _currentScreenSize.Height) / VScale) * Defs.SCREEN_SIZE / 100;
//VScale = _currentScreenSize.Height * Defs.SCREEN_SIZE / 100;
}
Bitmap scaledBmp = GraphicsFactory.ResizeImage(
__bmp,
Convert.ToInt32(HScale),
Convert.ToInt32(VScale));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With