How to reduce image size in C#? - c#

I was using Graphics.DrawImage(DrawText()) to DrawText into Image.
The problem is: I only draw three text but origin images size is: 226kb and output image when Save() ~3.45mb. It too larger.
Image dimensions: 2732 * 3200.
I only loop my list textFileSplit, and this list only has three items.
This is all my code to save image:
foreach (string text in lstTextFromFile)
{
count++;
if (text == "") continue;
Graphics gra = Graphics.FromImage(img);
string st = lstImgAdded.Items[k].Text;
Bitmap bmp = new Bitmap(#"" + st);
bmp = (Bitmap)ResizePanel(bmp, panel2);
panel2.BackgroundImage = bmp;
Graphics gbmp = Graphics.FromImage(bmp);
string[] textFileSplit = text.Split('-');
for (int u = 0; u < textFileSplit.Count(); u++)
{
myColorLabel = activeLabels[u+1].ForeColor;
gbmp.DrawImage(
DrawText(textFileSplit[u], fontType, myColorLabel,
Color.Transparent),
Point.Round(StretchImageSize(new Point(activeLabels[u+1].Location.X, activeLabels[u+1].Location.Y), panel2)));
}
gra.Dispose();
Guid id = Guid.NewGuid();
ScaleImage(bmp, witdhImg, heightImg)
.Save(linkLocation + "\\" + id + "." + imgType,
ImageFormat.Png);
}
In class ScaleImage() I tried to keep dimensions like origin images:
public Image ScaleImage(Image image, int maxWidth, int maxHeight)
{
var ratioX = (double)maxWidth / image.Width;
var ratioY = (double)maxHeight / image.Height;
var ratio = Math.Min(ratioX, ratioY);
var ratio2 = Math.Max(ratioX, ratioY);
var newWidth = (int)(image.Width * ratio);
var newHeight = (int)(image.Height * ratio2);
var newImage = new Bitmap(newWidth, newHeight);
Graphics.FromImage(newImage).DrawImage(image, 0, 0, newWidth, newHeight);
return newImage;
}

Make sure to set the resolution and quality in your scaling function:
public Image ScaleImage(Image image, int maxWidth, int maxHeight)
{
var ratioX = (double)maxWidth / image.Width;
var ratioY = (double)maxHeight / image.Height;
var ratio = Math.Min(ratioX, ratioY);
var ratio2 = Math.Max(ratioX, ratioY);
var newWidth = (int)(image.Width * ratio);
var newHeight = (int)(image.Height * ratio2);
var newImage = var newImage = new Bitmap(newWidth, newHeight, image.PixelFormat);
newImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
Graphics grPhoto = Graphics.FromImage(newImage);
grPhoto.InterpolationMode = InterpolationMode.High;
grPhoto.DrawImage(image, 0, 0, newWidth, newHeight);
grPhoto.Dispose();
return newImage;
}
Apply EncoderParameters with low Quality:
ImageCodecInfo pngEncoder = ImageCodecInfo.GetImageDecoders().Where(k=> k.FormatID == ImageFormat.Png.Guid).First();
EncoderParameters encoderParameters;
encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 60L);
ScaleImage(bmp, witdhImg, heightImg)
.Save(linkLocation + "\\" + id + "." + imgType, pngEncoder ,encoderParameters);

Related

change the scale of the image and save it, it is saved horizontally unconditionally

In my code, if the image capacity is greater than 10 megabytes, resize the image.
And when I check the saved image, the image is always lying horizontally.
I've tried to solve this, but I don't know where the problem comes from.
How can I save the direction of the image as it is?
if (fileLength >= 1024 * 1024 && useImageResize == "Y")
{
System.Drawing.Bitmap bmpPostedImage = new System.Drawing.Bitmap(file.InputStream);
System.Drawing.Image objImage = WebMethods.ScaleImage(bmpPostedImage, 1080);
using (var ms = new MemoryStream(1024 * 1024))
{
objImage.Save(ms, ImageFormat.Jpeg);
fileLength = Methods.ConvInt32(ms.Length);
}
file.Save(newFilePath, ImageFormat.Jpeg);
}
public static System.Drawing.Image ScaleImage(System.Drawing.Image image, int maxHeight)
{
var ratio = (double)maxHeight / image.Height;
var newWidth = (int)(image.Width * ratio);
var newHeight = (int)(image.Height * ratio);
var newImage = new Bitmap(newWidth, newHeight);
using (var g = Graphics.FromImage(newImage))
{
g.DrawImage(image, 0, 0, newWidth, newHeight);
}
return newImage;
}

Binary image resizing goes wrong

I try to resize a binary image to a smaller file if needed, however all images are getting more byte after resize, while size is getting smaller, so result is very ugly images...have no idea why its get bigger.
here is the code I use any help would be appreciated.
using (var srcImage = System.Drawing.Image.FromStream(myMemStream))
{
double height = srcImage.Height;
double width = srcImage.Width;
newWidth = (int)(srcImage.Width);
double aspect = scale / width;
newHeight = Convert.ToInt32(aspect * height);
newWidth = Convert.ToInt32(aspect * width);
using (var newImage = new Bitmap(newWidth, newHeight))
using (var graphics = Graphics.FromImage(newImage))
{
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.DrawImage(srcImage, new Rectangle(0, 0, newWidth, newHeight));
System.IO.MemoryStream ms = new System.IO.MemoryStream();
newImage.Save(ms, format);
ms.Position = 0;
_bytes = ms.ToArray(); //Returns a new byte array.
newImage.Dispose();
}
}
**** update *****
double height = srcImage.Height;
double width = srcImage.Width;
newWidth = (int)(srcImage.Width);
double aspect = scale / width;
newHeight = Convert.ToInt32(aspect * height);
newWidth = Convert.ToInt32(aspect * width);
Image scaledImage = ScaleDownTo(srcImage, newHeight, newWidth);
newWidth = scaledImage.Width;
newHeight = scaledImage.Height;
System.IO.MemoryStream ms = new System.IO.MemoryStream();
scaledImage.Save(ms, format);
ms.Position = 0;
_bytes = ms.ToArray();
scaledImage.Dispose();
What I actually do is resize the image for example to a static max width, from any to 300px, so I calculate the current image width, take the aspect in double and resize this image to this size.
Any help on this is really appriciated
Well, here is a short function for scaling down images.
public static Image ScaleDownTo(Image image, int height, int width) {
if (image != null) {
if (image.Width > width || image.Height > height) {
float factor = Math.Max(((float)width) / image.Width, ((float)height) / image.Height);
if (factor > 0) {
RectangleF imgRect = new RectangleF(0, 0, image.Width * factor, image.Height * factor);
imgRect.X = ((float)width - imgRect.Width) / 2f;
imgRect.Y = ((float)height - imgRect.Height) / 2f;
Bitmap cellImage = new Bitmap(width, height);
using (Graphics cellImageGraphics = Graphics.FromImage(cellImage)) {
cellImageGraphics.Clear(Color.Transparent);
cellImageGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
cellImageGraphics.DrawImage(image, imgRect);
}
return cellImage;
}
}
return image;
}
return null;
}
Just use it to get the new downscaled image.

Why does this C# image handler change the color of my image?

I have the below image handler method to resize and save an image, however it changes the image's color enough to notice. I am passing in 100 as the Quality value. I also might be losing my mind but i swear on occasion it doesnt affect the colors. However the last 10 test i ran it did.
public string Save(Bitmap image, int maxWidth, int maxHeight, int quality, string pathWithName, out int iWidth, out int iHeight)
{
// Get the image's original width and height
int originalWidth = image.Width;
int originalHeight = image.Height;
int newWidth = 0;
int newHeight = 0;
if (originalWidth < maxWidth && originalHeight < maxHeight)
{
newWidth = originalWidth;
newHeight = originalHeight;
}
else
{
// To preserve the aspect ratio
float ratioX = (float)maxWidth / (float)originalWidth;
float ratioY = (float)maxHeight / (float)originalHeight;
float ratio = Math.Min(ratioX, ratioY);
// New width and height based on aspect ratio
newWidth = (int)(originalWidth * ratio);
newHeight = (int)(originalHeight * ratio);
}
// Convert other formats (including CMYK) to RGB.
Bitmap newImage = new Bitmap(newWidth, newHeight, PixelFormat.Format24bppRgb);
// Draws the image in the specified size with quality mode set to HighQuality
using (Graphics graphics = Graphics.FromImage(newImage))
{
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.DrawImage(image, 0, 0, newWidth, newHeight);
}
// Get an ImageCodecInfo object that represents the JPEG codec.
ImageCodecInfo imageCodecInfo = this.GetEncoderInfo(ImageFormat.Jpeg);
// Create an Encoder object for the Quality parameter.
Encoder encoder = Encoder.Quality;
// Create an EncoderParameters object.
EncoderParameters encoderParameters = new EncoderParameters(1);
// Save the image as a JPEG file with quality level.
EncoderParameter encoderParameter = new EncoderParameter(encoder, quality);
encoderParameters.Param[0] = encoderParameter;
newImage.Save(pathWithName, imageCodecInfo, encoderParameters);
iWidth = newWidth;
iHeight = newHeight;
return pathWithName;
}

How to resize image with different resolution

I have to display image in photo gallery # width=200 height=180, but while uploading images I have to resize it , but the problem is every image have different resolution. How can I resize the images with different resolution so that images remain intact.
Here is my code :
private void ResizeImage()
{
System.Drawing.Image ImageToUpload = System.Drawing.Image.FromStream(FileUpload1.PostedFile.InputStream);
byte[] image = null;
int h = ImageToUpload.Height;
int w = ImageToUpload.Width;
int r = int.Parse(ImageToUpload.VerticalResolution.ToString());
int NewWidth = 200;//constant
int NewHeight = 180;//constant
byte[] imagesize = FileUpload1.FileBytes;
System.Drawing.Bitmap BitMapImage = new System.Drawing.Bitmap(ImageToUpload, NewWidth, NewHeight);//this line gives horrible output
MemoryStream Memory = new MemoryStream();
BitMapImage.Save(Memory, System.Drawing.Imaging.ImageFormat.Jpeg);
Memory.Position = 0;
image = new byte[Memory.Length + 1];
Memory.Read(image, 0, image.Length);
}
if resolution is 96 and if I set maxwidth=200 then its height would be 150 then only the image looks small and accurate. Can't we resize image in desired way so that it looks exact?
The function will resize the image maintaining aspect ratio.
public static Image Resize(Image originalImage, int w, int h)
{
//Original Image attributes
int originalWidth = originalImage.Width;
int originalHeight = originalImage.Height;
// Figure out the ratio
double ratioX = (double)w / (double)originalWidth;
double ratioY = (double)h / (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);
Image thumbnail = new Bitmap(newWidth, newHeight);
Graphics graphic = Graphics.FromImage(thumbnail);
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphic.SmoothingMode = SmoothingMode.HighQuality;
graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphic.CompositingQuality = CompositingQuality.HighQuality;
graphic.Clear(Color.Transparent);
graphic.DrawImage(originalImage, 0, 0, newWidth, newHeight);
return thumbnail;
}
Usage
Image BitMapImage = Resize(ImageToUpload, NewWidth, NewHeight);
Here i keep height fixed to 180 to maintain aspect ratio. It will resize the image and save to disk. The return value is the percentage value which i use in 'background-size' css.
public float ResizePhoto(string filepath, string filename)
{
var path = Path.Combine(filepath, filename);
var newPath = Path.Combine(filepath, "sml_" + filename);
Image orgImage = Image.FromFile(path);
float fixedHt = 180f;
int destHeight, destWidth;
float reqScale;
if(orgImage.Height > fixedHt)
{
destHeight = (int)fixedHt;
destWidth = (int)(fixedHt / orgImage.Height * orgImage.Width);
reqScale = destWidth / destHeight * 100;
}
else
{
destHeight = orgImage.Height;
destWidth = orgImage.Width;
reqScale = fixedHt / destHeight * 100;
}
Bitmap bmp = new Bitmap(destWidth, destHeight);
bmp.SetResolution(orgImage.HorizontalResolution,orgImage.VerticalResolution);
Graphics grPhoto = Graphics.FromImage(bmp);
grPhoto.DrawImage(orgImage,
new Rectangle(0, 0, destWidth, destHeight),
new Rectangle(0, 0, orgImage.Width, orgImage.Height),
GraphicsUnit.Pixel);
bmp.Save(newPath);
return reqScale;
}

C# : How to resize image proportionately with max height

I need to resize my image proportionately without changing aspect ratio.I have the code to resize with fixed hight and width but I need to resize image proportionately with max height(say 600 pixels). How can I modify the code to suit my requirement?
public static void Main()
{
var image = Image.FromFile(#"c:\logo.png");
var newImage = ScaleImage(image, 300, 400);
newImage.Save(#"c:\test.png", ImageFormat.Png);
}
public static Image ScaleImage(Image image, int maxWidth, int maxHeight)
{
var ratioX = (double)maxWidth / image.Width;
var ratioY = (double)maxHeight / image.Height;
var ratio = Math.Min(ratioX, ratioY);
var newWidth = (int)(image.Width * ratio);
var newHeight = (int)(image.Height * ratio);
var newImage = new Bitmap(newWidth, newHeight);
Graphics.FromImage(newImage).DrawImage(image, 0, 0, newWidth, newHeight);
return newImage;
}
Please provide your valuable thoughts.
This almost feels to easy and I feel I'm missing something. Anyway, won't that do the trick?
public static Image ScaleImage(Image image, int maxHeight)
{
var ratio = (double)maxHeight / image.Height;
var newWidth = (int)(image.Width * ratio);
var newHeight = (int)(image.Height * ratio);
var newImage = new Bitmap(newWidth, newHeight);
using (var g = Graphics.FromImage(newImage))
{
g.DrawImage(image, 0, 0, newWidth, newHeight);
}
return newImage;
}
Use the following function
public Bitmap ProportionallyResizeBitmapByHeight(Bitmap imgToResize, int height)
{
int sourceWidth = imgToResize.Width;
int sourceHeight = imgToResize.Height;
float scale = 0;
scale = (height / (float)sourceHeight);
int destWidth = (int)(sourceWidth * scale);
int destHeight = (int)(sourceHeight * scale);
Bitmap result = new Bitmap(destWidth, destHeight);
result.SetResolution(imgToResize.HorizontalResolution, imgToResize.VerticalResolution);
Graphics g = Graphics.FromImage(result);
g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
g.Dispose();
return result;
}
Well, thinking through the process:
if you have an image that 800 x 600 in size and want to resize it to newWidth x 400 height (plus whatever the respective newWidth will be), you get the ratio by dividing the newHeight (maxHeight in your case) with 600 and multiply 800 with this ratio, right?
So, in this case you need to change maxWidth and maxHeight to optional parameters (say 800 by 600) to give yourself some dynamism and get the following:
public static Image ScaleImage(Image image, int maxWidth = 800, int maxHeight = 600)
{
int newWidth;
int newHeight;
double ratio = image.Height / image.Width;
if(maxHeight != 600) {
newWidth = image.Width * ratio;
newHeight = maxHeight;
}
Bitmap newImage = new Bitmap(newWidth, newHeight);
Graphics.FromImage(newImage).DrawImage(image, 0, 0, newWidth, newHeight);
return newImage;
}
I hope this helps. I didn't test it, but I've rewritten my VB code, so allegedly it should be okay...
There's also a ResizeStream method here: http://forums.asp.net/t/1576697.aspx/1 that you might find useful.
If you want to keep image quality, you can use the CompositingQuality and SmoothingMode, etc. variables.
100% Worked
private static BitmapFrame CreateResizedImage(ImageSource source, int Max_width, int Max_height, int margin)
{
float scaleHeight = (float)Max_width / (float)source.Height;
float scaleWidth = (float)Max_height / (float)source.Width;
float scale = Math.Min(scaleHeight, scaleWidth);
int width = (int)(source.Width * scale);
int height = (int)(source.Height * scale);
var rect = new Rect(margin, margin, width - margin * 2, height - margin * 2);
var group = new DrawingGroup();
RenderOptions.SetBitmapScalingMode(group, BitmapScalingMode.HighQuality);
group.Children.Add(new ImageDrawing(source, rect));
var drawingVisual = new DrawingVisual();
using (var drawingContext = drawingVisual.RenderOpen())
drawingContext.DrawDrawing(group);
var resizedImage = new RenderTargetBitmap(
width, height, // Resized dimensions
96, 96, // Default DPI values
PixelFormats.Default); // Default pixel format
resizedImage.Render(drawingVisual);
return BitmapFrame.Create(resizedImage);
}
//--------Main------------//
BitmapImage imageSource = (BitmapImage)ImagePreview.Source;
var NewImage= CreateResizedImage(imageSource , 300, 300, 0);

Categories

Resources