I have following markup codes that has a container div element and an img tag nested inside the div. The container div has width, height, top and left CSS style properties.
An originally uploaded image has arbitrary width and height that may be bigger or smaller than the container div. So definitely, the originally uploaded image must be resized and well scaled, and saved as an thumbnail image to sit within the borders of the container div. That resized thumbnail image will be shown as the source (src) in the following markups:
<div id="divContainer" style="width: 600px; height: 450px; top: 50px; left: 20px;">
<img src="[my resized and well scaled thumbnail source]..." id="imgResizedThumnail" />
</div>
In a another .NET form page, there is a file tag letting users upload an original image from local hard disk. That uploaded image needs to be resized and saved as another thumbnail image with best scaling. "Best scalling" means the thumbnail image has a proportional ratio of width and height, and the thumbnail must be sit within the container div.
My C# .NET method looks like follows and I have questions about the code logic in that method.
...
using System.Drawing;
public void SaveThumbnailImageWithbestScaling(Image originalImage, int containerDivWidth, int containerDivHeight)
{
// input containerDivWidth and containerDivHeight are dynamic!
// 1. How can I calculate the scale variable?
double scale = ??? // how can I do the codes here?
// 2. Use that scale to determine the dimension of resized thumbnail image from
// the input originalImage for following variables "thumnailWidth" and "thumnailHeight"
string thumbnailFilename = "myThumnailFileName";
int thumnailWidth = ??? // how can I do the codes here?
int thumnailHeight = ??? // how can I do the codes here?
Bitmap thumnailImage = CreateThumbnail(thumbnailFilename,int thumnailWidth, int thumnailHeight);
// 3. save thumbnail
SaveThumnail(thumnailImage);
}
public void Bitmap CreateThumbnail(string lcFilename,int lnWidth, int lnHeight)
{
...
}
public void thumnailImage (Bitmap thumnail)
{
...
}
This is what I use:
public static Image Resize(
Image srcImage,
int newWidth,
int maxHeight,
int dpi = 72)
{
if(srcImage.Width<=newWidth)
{
newWidth = srcImage.Width;
}
var newHeight = srcImage.Height * newWidth / srcImage.Width;
if (newHeight > maxHeight)
{
newWidth = srcImage.Width * maxHeight / srcImage.Height;
newHeight = maxHeight;
}
var newImage = new Bitmap(newWidth, newHeight);
newImage.SetResolution(dpi, dpi);
using (var gr = Graphics.FromImage(newImage))
{
gr.SmoothingMode = SmoothingMode.AntiAlias;
gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
gr.DrawImage(srcImage, new Rectangle(0, 0, newWidth, newHeight));
}
return newImage;
}
I would have done something like this:
public void SaveThumbnailImageWithbestScaling(Image originalImage, int containerDivWidth, int containerDivHeight)
{
string thumbnailFilename = "myThumnailFileName";
int thumbnailWidth = 0;
int thumbnailHeight = 0;
float imgWidth = (float)originalImage.Width;
float imgHeight = (float)originalImage.Height;
float scale_w = imgWidth / (float)containerDivWidth;
float scale_h = imgHeight / (float)containerDivHeight;
// Compute how much each scale diverge from 1 (1 means no scaling, which is desirable)
float variance_w = Math.Abs(1.0 - scale_w);
float variance_h = Math.Abs(1.0 - scale_h);
if (variance_w > variance_h)
{
// Height ratio is closer to 1
float aspect_ratio = imgWidth / imgHeight;
thumbnailHeight = containerDivHeight;
thumbnailWidth = (int)Math.Floor(aspect_ratio * imgWidth);
}
else
{
// Width ratio is closer to 1
float aspect_ratio = imgHeight / imgWidth;
thumbnailHeight = (int)Math.Floor(aspect_ratio * imgHeight);
thumbnailWidth = containerDivWidth;
}
Bitmap thumnailImage = CreateThumbnail(thumbnailFilename,int thumnailWidth, int thumnailHeight);
// 3. save thumbnail
SaveThumnail(thumnailImage);
}
The algorithm computes the ratio of each dimension, then figures out which one varies the most from the div tag's dimension. It then proceeds to snap the dimension with the least variance to the size of the div tag, and scale the other one to respect the image's aspect ratio.
Of course there are other ways of doing it, you could for example not care about aspect ratio and just snap both dimensions to that of the div tag.
Related
We have a problem in our system. We extract images from doc file and perform scaling up and down if the size of the extracted image is not as we want. Image looks good after scaling but the text that lies inside the image looks a little bit blurry or not in the same quality (sharpness) as in the image before scaling. Any ideas that can help to improve the text sharpness will be most appreciated.Thank you wonderful people!
Our scaling function looks like this:
const float highScalingFactor = 0.58F; // default scaling of large images - based on experience
const float lowScalingFactor = 0.44F; // default scaling of small images - based on experience
const int maxWidth = 1100;
const int maxHeight = 2500;
float formulaScale = 0.9F;
//calling scaling function here
var lImgStream = ScaleImage(shape, lowScalingFactor * formulaScale, maxWidth, maxHeight, "png");
private static MemoryStream ScaleImage(Shape shape, float scale, int maxWidth, int maxHeight, string extension)
{
var resolution = 300F;
ShapeRenderer r = new ShapeRenderer(shape);
var rect = r.GetBoundsInPixels(scale, resolution);
if (rect.Width > maxWidth)
{
scale = 1 - (rect.Width * scale - maxWidth) / rect.Width;
}
if (rect.Height > maxHeight)
{
scale = 1 - (rect.Height * scale - maxHeight) / rect.Height;
}
ImageSaveOptions imageOptions = new ImageSaveOptions(FileFormatUtil.ExtensionToSaveFormat(extension))
{
SaveFormat = SaveFormat.Png,
Scale = scale,
Resolution = resolution,
UseHighQualityRendering = true
};
// sharpen formulas
if (shape.ImageData.ImageType == ImageType.Wmf)
imageOptions.ImageContrast = 0.55f;
var output = new MemoryStream();
r.Save(output, imageOptions);
output.Seek(0, SeekOrigin.Begin);
return output;
}
We tried the above scaling algorithm with successful output in terms of image sharpness except text on the image. The text looks blurry.
Try using SaveOptions.UseAntiAliasing to improve the quality of a rendered image.
I'm using C# to scale and rotate an image with a transparent background, then using JavaScript to add it to a Google Maps API map, but once it's scaled and rotated, the edges of the image get blurred, and it becomes hard to see, especially over water.
Here is my original 300x300 image:
And here is an example of one of the output images at 100x100 (SizeInt = 100):
Before you get confused as to the background colour, the image is projected onto a map where the water is a similar colour to the image.
You can see some slight ghosting around the edges of the image.
Once it's scaled down further (to it's required scale):
It's almost unnoticeable...
I'm still relatively new to C#, but I've tried loading SVGs directly onto the map with JavaScript (icon: "some/SVG/file.svg"), but that causes serious performance problems, as there are up to 1,000 icons on the map at any given time, making the map unusable when using SVG files, so I have to use image files.
The images need to be sharp and not blurred around the edges. Here is the code used to generate the images, forgive any sloppy code, I'm still somewhat new to C#:
Here is the code used to scale the image:
The image needs to be rotated in a full circle (rounded to 5 degrees), hence the loop from 0 to 361.
private void BuildIcons(string dir)
{
int SizeInt = 30;
// Get the content path
var ContentPath = dir;
// Get the original image
Bitmap OriginalImage = new Bitmap(ContentPath + "base.png");
#region Resize image
// New size
Size size = new Size(SizeInt, SizeInt);
// New height/width temp vars
int newWidth;
int newHeight;
// Aspect ratio preservation
int originalWidth = OriginalImage.Width;
int originalHeight = OriginalImage.Height;
float percentWidth = (float)size.Width / (float)originalWidth;
float percentHeight = (float)size.Height / (float)originalHeight;
float percent = percentHeight < percentWidth ? percentHeight : percentWidth;
newWidth = (int)(originalWidth * percent);
newHeight = (int)(originalHeight * percent);
// Generate the new image
Image ResizedImage = new Bitmap(newWidth, newHeight);
using (Graphics graphicsHandle = Graphics.FromImage(ResizedImage))
{
graphicsHandle.SmoothingMode = SmoothingMode.HighQuality;
graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphicsHandle.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphicsHandle.DrawImage(OriginalImage, 0, 0, newWidth, newHeight);
}
#endregion
int maxside = SizeInt;
#region Image rotation
// Generate images
for (int i = 0; i < 361; i += 5)
{
// New empty bitmap to hold rotated images
Bitmap ReturnBitmap = new Bitmap(maxside, maxside);
// Graphics object from the empty bitmap
// Normal
Graphics Gfx = Graphics.FromImage(ReturnBitmap);
Gfx.SmoothingMode = SmoothingMode.HighQuality;
Gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
Gfx.PixelOffsetMode = PixelOffsetMode.HighQuality;
// Move rotation point to center of image
Gfx.TranslateTransform(
(float)ResizedImage.Width / 2,
(float)ResizedImage.Height / 2
);
// Rotate
Gfx.RotateTransform(i);
// Move image back
Gfx.TranslateTransform(
-(float)ResizedImage.Width / 2,
-(float)ResizedImage.Height / 2
);
// draw original in image onto graphics object
Gfx.DrawImage(ResizedImage, new Point(0, 0));
// Save the image
ReturnBitmap.Save(ContentPath + i.ToString() + ".png");
// Clean up
ReturnBitmap.Dispose();
Gfx.Dispose();
}
#endregion
// Clean up
ResizedImage.Dispose();
OriginalImage.Dispose();
}
Any suggestions?
I want to center a background image. However the background image is larger than my control(which is a flat style checkbox).
A picture to make my problem clear
Usually if the background image is smaller than the control, it will be shown like the black box(which is properly centered); but in my case it will show partial image in the green box(left top corner), but the end result I want is the orange box(the center of the image), or zoomed proportionally to fill the control with extra part cut off(ImageLayout.Zoom will show whole image with blank space).
Update: Code used:
Image img = Image.FromFile("xxxx.png");
mycheckbox.BackgroundImage = img;
mycheckbox.BackgroundImageLayout = ImageLayout.Center;
Image can be used instead of BackgroundImage to get the part of the image as the orange rectangle of the example.
If the image doesn't fill the entire checkbox and if it's acceptable to alter the image being set (should work without problems, but would not be dynamic in case the checkbox size changes during runtime), the image could be resized first according to the largest ratio:
var img = Image.FromFile("xxxx.png");
float ratio = Math.Max(mycheckbox.Height / (float)img.Height,mycheckbox.Width / (float)img.Width);
if (ratio > 1)
{
Func<float, int> calc = f => (int)Math.Ceiling(f * ratio);
var bmp = new Bitmap(img, calc(img.Width ), calc(img.Height ));
img.Dispose();
img = bmp;
}
mycheckbox.ImageAlign = ContentAlignment.MiddleCenter;
mycheckbox.Image = img;
The line float ratio = Math.Max(mycheckbox.Height / (float)img.Height,mycheckbox.Width / (float)img.Width); simply calculates both the height ratio and the width ratio. If either is larger than 1, it means the checkbox height or width is larger. It doesn't matter which one, only which is larger, hence the Math.Max. The check of larger than 1 is performed on the largest ratio and if needed the image is enlarged with said ratio.
Edit A more generic approach, that scales and cuts the image so that if fills the control size and the BackGroundImage property can be used:
public static void SetImage(this Control ctrl, Image img)
{
var cs = ctrl.Size;
if (img.Size != cs)
{
float ratio = Math.Max(cs.Height / (float)img.Height, cs.Width / (float)img.Width);
if (ratio > 1)
{
Func<float, int> calc = f => (int)Math.Ceiling(f * ratio);
img = new Bitmap(img, calc(img.Width), calc(img.Height));
}
var part = new Bitmap(cs.Width, cs.Height);
using (var g = Graphics.FromImage(part))
{
g.DrawImageUnscaled(img, (cs.Width - img.Width) /2, (cs.Height - img.Height) / 2);
}
img = part;
}
ctrl.BackgroundImageLayout = ImageLayout.Center;
ctrl.BackgroundImage = img;
}
I'm incredibly new to C# (just started today)
I need to be able to make a C# Image resizer with a canvas handler. For example a 500 x 500 image needs to retain its aspect ration. it will be getting resized to 1024x500. To do this it will remain 500x500 but then fill the rest of the space with white space (the canvas).
I will also be resizing the same original image to 300 x 500, where the image will again retain its 1:1 ration and be resized to 300x300 and the remaining space again used as canvas white space.
Can anybody help me to produce a C# console application for this, that I can understand?
Here is what I have managed to find that I could reasonably understand (due to nice commenting).
What I find with code is that I can read it, but when it comes to me actually writing some I just fall apart. I mainly do HTML and CSS. Starting to branch out into JQuery and C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Drawing.Imaging;
namespace ImageResizer
{
class ImageResize
{
static void Main(string[] args)
{
}
public void ResizeImage(string OriginalFile, string NewFile, int NewWidth, int MaxHeight, bool OnlyResizeIfWider)
{
System.Drawing.Image FullsizeImage = System.Drawing.Image.FromFile(OriginalFile);
// Prevent using images internal thumbnail
FullsizeImage.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
FullsizeImage.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
if (OnlyResizeIfWider)
{
if (FullsizeImage.Width <= NewWidth)
{
NewWidth = FullsizeImage.Width;
}
}
int NewHeight = FullsizeImage.Height * NewWidth / FullsizeImage.Width;
if (NewHeight > MaxHeight)
{
// Resize with height instead
NewWidth = FullsizeImage.Width * MaxHeight / FullsizeImage.Height;
NewHeight = MaxHeight;
}
System.Drawing.Image NewImage = FullsizeImage.GetThumbnailImage(NewWidth, NewHeight, null, IntPtr.Zero);
// Clear handle to original file so that we can overwrite it if necessary
FullsizeImage.Dispose();
// Save resized picture
NewImage.Save(NewFile);
}
}
}
Try To Go For This>>
private void resizeImage(string path, string originalFilename,
/* note changed names */
int canvasWidth, int canvasHeight,
/* new */
int originalWidth, int originalHeight)
{
Image image = Image.FromFile(path + originalFilename);
System.Drawing.Image thumbnail =
new Bitmap(canvasWidth, canvasHeight); // changed parm names
System.Drawing.Graphics graphic =
System.Drawing.Graphics.FromImage(thumbnail);
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphic.SmoothingMode = SmoothingMode.HighQuality;
graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphic.CompositingQuality = CompositingQuality.HighQuality;
/* ------------------ new code --------------- */
// Figure out the ratio
double ratioX = (double) canvasWidth / (double) originalWidth;
double ratioY = (double) canvasHeight / (double) originalHeight;
// use whichever multiplier is smaller
double ratio = ratioX < ratioY ? ratioX : ratioY;
// now we can get the new height and width
int newHeight = Convert.ToInt32(originalHeight * ratio);
int newWidth = Convert.ToInt32(originalWidth * ratio);
// Now calculate the X,Y position of the upper-left corner
// (one of these will always be zero)
int posX = Convert.ToInt32((canvasWidth - (originalWidth * ratio)) / 2);
int posY = Convert.ToInt32((canvasHeight - (originalHeight * ratio)) / 2);
graphic.Clear(Color.White); // white padding
graphic.DrawImage(image, posX, posY, newWidth, newHeight);
/* ------------- end new code ---------------- */
System.Drawing.Imaging.ImageCodecInfo[] info =
ImageCodecInfo.GetImageEncoders();
EncoderParameters encoderParameters;
encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality,
100L);
thumbnail.Save(path + width + "." + originalFilename, info[1],
encoderParameters);
}
i generate picture according to the size of picture box and set the picture to picture box whose size mode is normal but full image is not showing rather few area of picture is cutting off. i want to generate picture in such a way as a result when i will set the picture on picture box then full image should be display. here is my code by which i generate picture
new Bitmap _lastSnapshot = new Bitmap(261, 204);
this.DrawToBitmap((Bitmap)_lastSnapshot, new Rectangle(Point.Empty, ((Bitmap)_lastSnapshot).Size));
261, 204 is size of picture box and picture size mode is normal.i assign the lastSnapshot to picture box after generation but full picture is not displaying.
i got a routine to resize image according to picture box size. it works well but image looks become obscure or unclear.i have to set the picturebox size mode stretch to fill up the image into pic box.
here is the routine i use to resize picture according to picture box size.
public static Image ResizeImage(Image image, Size size,
bool preserveAspectRatio = true)
{
int newWidth;
int newHeight;
if (preserveAspectRatio)
{
int originalWidth = image.Width;
int originalHeight = image.Height;
float percentWidth = (float)size.Width / (float)originalWidth;
float percentHeight = (float)size.Height / (float)originalHeight;
float percent = percentHeight < percentWidth ? percentHeight : percentWidth;
newWidth = (int)(originalWidth * percent);
newHeight = (int)(originalHeight * percent);
}
else
{
newWidth = size.Width;
newHeight = size.Height;
}
Image newImage = new Bitmap(newWidth, newHeight);
using (Graphics graphicsHandle = Graphics.FromImage(newImage))
{
graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphicsHandle.DrawImage(image, 0, 0, newWidth, newHeight);
}
return newImage;
}
call the routine
ResizeImage(value,pictureBox1.Size,true);
can anyone give some advise to generate and resize the picture for fit into picture box with good crystal clear image. thanks
If you want to preview of image in picturebox according to picturebox size then:
Change PictureBox property SizeMode to Zoom.
pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;