Image resizing at different levels creating different size images - c#

I have the following code placed at a button click. Button got clicked after user selects an image to upload.
using (SD.Image OriginalImage = SD.Image.FromStream(AsyncUpload.FileContent))
{
decimal dRatio = (Decimal)1024 / OriginalImage.Width;
int iScaledW = 1024;
int iScaledH = (int)(OriginalImage.Height * dRatio);
using (SD.Bitmap bmp = new SD.Bitmap(iScaledW, iScaledH))
{
bmp.SetResolution(OriginalImage.HorizontalResolution, OriginalImage.VerticalResolution);
using (SD.Graphics Graphic = SD.Graphics.FromImage(bmp))
{
Graphic.SmoothingMode =SD2.SmoothingMode.AntiAlias;
Graphic.InterpolationMode = SD2.InterpolationMode.HighQualityBicubic;
Graphic.PixelOffsetMode = SD2.PixelOffsetMode.HighQuality;
Graphic.FillRectangle(SD.Brushes.White, 0, 0, iScaledW, iScaledH);
Graphic.DrawImage(OriginalImage, 0, 0, iScaledW, iScaledH);
bmp.Save(Path.Combine(Server.MapPath(upPath), AsyncUpload.FileName));
}
}
}
Here AsyncUpload is the name of FileUpload control. Original image is 3.96MB and by re-sizing the image with the above function, creates a re-sized image of 1.92MB.
However, If I select that same 3.96MB file as click a button that executes the following code that simply uploads whatever provided.
objfile.SaveAs(Path.Combine(Server.MapPath(upPath), AsyncUpload.FileName));
And then click a button that do the same processing of re-sizing the image as above mentioned, it creates an image of 200KB only. Below is the code of that button click.
static byte[] Crop(string Img, int Width, int Height, int X, int Y)
{
int w = Width;
int h = Height;
int xx = X;
int yy = Y;
try
{
using (SD.Image OriginalImage = SD.Image.FromFile(Img))
{
if (w == 0 || h == 0)
{
w = OriginalImage.Width;
h = OriginalImage.Height;
}
int iScaleX = 0, iScaleY = 0;
GetImageResolution(w, h, out iScaleX, out iScaleY);
using (SD.Bitmap bmp = new SD.Bitmap(iScaleX, iScaleY))
{
bmp.SetResolution(OriginalImage.HorizontalResolution, OriginalImage.VerticalResolution);
using (SD.Graphics Graphic = SD.Graphics.FromImage(bmp))
{
Graphic.SmoothingMode = SmoothingMode.AntiAlias;
Graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
Graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
Graphic.FillRectangle(SD.Brushes.White, 0, 0, iScaleX, iScaleY);
Graphic.DrawImage(OriginalImage, 0, 0, iScaleX, iScaleY);
bmp.Save(<Path>);
}
}
}
}
catch (Exception Ex)
{
return null;
// throw (Ex);
}
}
Both the code are same but the output images are of different sizes and that too, a big difference in size. Please help me understand why is this behavior. I want to avoid uploading big size image by reading them as stream and re-sizing them before even uploading them to disk. But the size after re-sizing is too big to accept.
Also, if anybody can share their thoughts of how to compress and image.
Thanks in advance

When both the image dimensions and contents are the same, the most likely cause for a file size difference of this magnitude (1.92MB to 200KB) is the compression type.
Most likely one of the 2 functions is saving lossless PNG, probably at the default 32 bits per pixel, and this produces large file.
The other likely saves 24-bit lossy JPEG, which gives much smaller size with almost all images.
To test this, force the format to be JPEG using this code:
bmp.Save(Path.Combine(Server.MapPath(upPath), AsyncUpload.FileName), SD.Imaging.ImageFormat.Jpeg);
Does this produce smaller files?

Related

C# Icon created looks fine, but Windows directory thumbnails don't look right

I wrote some code to create ico files from any png, jpg, etc. images. The icons seem to be getting created correctly, and looks almost like the original image, when opened in Paint3d. Here is how it looks:
But when setting the image as a thumbnail to a folder, it looks weird and shiny.
Here is how it looks in windows file explorer:
Firstly, I would like to know if this is an issue in Windows itself, or is it code related? If this is Windows related, the code doesn't matter. If not, here it is:
I picked up a couple of code snippets from across the internet, so probably some non-optimized code, but here is the meat of my code:
//imagePaths => all images which I am converting to ico files
imagePaths.ForEach(imgPath => {
//create a temp png at this path after changing the original img to a squared img
var tempPNGpath = Path.Combine(icoDirPath, imgName.Replace(ext, ".png"));
var icoPath = tempPNGpath.Replace(".png", ".ico");
using (FileStream fs1 = File.OpenWrite(tempPNGpath)) {
Bitmap b = ((Bitmap)Image.FromFile(imgPath));
b = b.CopyToSquareCanvas(Color.Transparent);
b.Save(fs1, ImageFormat.Png);
fs1.Flush();
fs1.Close();
ConvertToIco(b, icoPath, 256);
}
File.Delete(tempPNGpath);
});
public static void ConvertToIco(Image img, string file, int size) {
Icon icon;
using (var msImg = new MemoryStream())
using (var msIco = new MemoryStream()) {
img.Save(msImg, ImageFormat.Png);
using (var bw = new BinaryWriter(msIco)) {
bw.Write((short)0); //0-1 reserved
bw.Write((short)1); //2-3 image type, 1 = icon, 2 = cursor
bw.Write((short)1); //4-5 number of images
bw.Write((byte)size); //6 image width
bw.Write((byte)size); //7 image height
bw.Write((byte)0); //8 number of colors
bw.Write((byte)0); //9 reserved
bw.Write((short)0); //10-11 color planes
bw.Write((short)32); //12-13 bits per pixel
bw.Write((int)msImg.Length); //14-17 size of image data
bw.Write(22); //18-21 offset of image data
bw.Write(msImg.ToArray()); // write image data
bw.Flush();
bw.Seek(0, SeekOrigin.Begin);
icon = new Icon(msIco);
}
}
using (var fs = new FileStream(file, FileMode.Create, FileAccess.Write))
icon.Save(fs);
}
In the Extension class, the method goes:
public static Bitmap CopyToSquareCanvas(this Bitmap sourceBitmap, Color canvasBackground) {
int maxSide = sourceBitmap.Width > sourceBitmap.Height ? sourceBitmap.Width : sourceBitmap.Height;
Bitmap bitmapResult = new Bitmap(maxSide, maxSide, PixelFormat.Format32bppArgb);
using (Graphics graphicsResult = Graphics.FromImage(bitmapResult)) {
graphicsResult.Clear(canvasBackground);
int xOffset = (maxSide - sourceBitmap.Width) / 2;
int yOffset = (maxSide - sourceBitmap.Height) / 2;
graphicsResult.DrawImage(sourceBitmap, new Rectangle(xOffset, yOffset, sourceBitmap.Width, sourceBitmap.Height));
}
return bitmapResult;
}
The differences in scaling are the result of the fact you're not doing the scaling yourself.
The icon format technically only supports images up to 256x256. You have code to make a square image out of the given input, but you never resize it to 256x256, meaning you end up with an icon file in which the header says the image is 256x256, but which is really a lot larger. This is against the format specs, so you are creating a technically corrupted ico file. The strange differences you're seeing are a result of different downscaling methods the OS is using in different situations to remedy this situation.
So the solution is simple: resize the image to 256x256 before putting it into the icon.
If you want more control over any smaller display sizes for the icon, you can add code to resize it to a number of classic used formats, like 16x16, 32x32, 64x64 and 128x128, and put them all in an icon file together. I have written an answer to another question that details the process of putting multiple images into a single icon:
A: Combine System.Drawing.Bitmap[] -> Icon
There are quite a few other oddities in your code, though:
I see no reason to save your in-between image as png file. That whole fs1 stream serves no purpose at all. You never use or load the temp file; you just keep using the b variable, which does not need anything written to disk.
There is no point in first making the icon in a MemoryStream, then loading that as Icon class through its file loading function, and then saving that to a file. You can just write the contents of that stream straight to a file, or, heck, use a FileStream right away.
As I noted in the comments, Bitmap is a disposable class, so any bitmap objects you create should be put in using statements as well.
The adapted loading code, with the temp png writing removed, and the using statements and resizes added:
public static void WriteImagesToIcons(List<String> imagePaths, String icoDirPath)
{
// Change this to whatever you prefer.
InterpolationMode scalingMode = InterpolationMode.HighQualityBicubic;
//imagePaths => all images which I am converting to ico files
imagePaths.ForEach(imgPath =>
{
// The correct way of replacing an extension
String icoPath = Path.Combine(icoDirPath, Path.GetFileNameWithoutExtension(imgPath) + ".ico");
using (Bitmap orig = new Bitmap(imgPath))
using (Bitmap squared = orig.CopyToSquareCanvas(Color.Transparent))
using (Bitmap resize16 = squared.Resize(16, 16, scalingMode))
using (Bitmap resize32 = squared.Resize(32, 32, scalingMode))
using (Bitmap resize48 = squared.Resize(48, 48, scalingMode))
using (Bitmap resize64 = squared.Resize(64, 64, scalingMode))
using (Bitmap resize96 = squared.Resize(96, 96, scalingMode))
using (Bitmap resize128 = squared.Resize(128, 128, scalingMode))
using (Bitmap resize192 = squared.Resize(192, 192, scalingMode))
using (Bitmap resize256 = squared.Resize(256, 256, scalingMode))
{
Image[] includedSizes = new Image[]
{ resize16, resize32, resize48, resize64, resize96, resize128, resize192, resize256 };
ConvertImagesToIco(includedSizes, icoPath);
}
});
}
The CopyToSquareCanvas remains the same, so I didn't copy it here. The Resize function is fairly simple: just use Graphics.DrawImage to paint the picture on a different-sized canvas, after setting the desired interpolation mode.
public static Bitmap Resize(this Bitmap source, Int32 width, Int32 height, InterpolationMode scalingMode)
{
Bitmap result = new Bitmap(width, height, PixelFormat.Format32bppArgb);
using (Graphics g = Graphics.FromImage(result))
{
// Set desired interpolation mode here
g.InterpolationMode = scalingMode;
g.PixelOffsetMode = PixelOffsetMode.Half;
g.DrawImage(source, new Rectangle(0, 0, width, height), new Rectangle(0, 0, source.Width, source.Height), GraphicsUnit.Pixel);
}
return result;
}
And, finally, the above-linked Bitmap[] to Icon function, slightly tweaked to write to a FileStream directly instead of loading the result into an Icon object:
public static void ConvertImagesToIco(Image[] images, String outputPath)
{
if (images == null)
throw new ArgumentNullException("images");
Int32 imgCount = images.Length;
if (imgCount == 0)
throw new ArgumentException("No images given!", "images");
if (imgCount > 0xFFFF)
throw new ArgumentException("Too many images!", "images");
using (FileStream fs = new FileStream(outputPath, FileMode.Create, FileAccess.Write))
using (BinaryWriter iconWriter = new BinaryWriter(fs))
{
Byte[][] frameBytes = new Byte[imgCount][];
// 0-1 reserved, 0
iconWriter.Write((Int16)0);
// 2-3 image type, 1 = icon, 2 = cursor
iconWriter.Write((Int16)1);
// 4-5 number of images
iconWriter.Write((Int16)imgCount);
// Calculate header size for first image data offset.
Int32 offset = 6 + (16 * imgCount);
for (Int32 i = 0; i < imgCount; ++i)
{
// Get image data
Image curFrame = images[i];
if (curFrame.Width > 256 || curFrame.Height > 256)
throw new ArgumentException("Image too large!", "images");
// for these three, 0 is interpreted as 256,
// so the cast reducing 256 to 0 is no problem.
Byte width = (Byte)curFrame.Width;
Byte height = (Byte)curFrame.Height;
Byte colors = (Byte)curFrame.Palette.Entries.Length;
Int32 bpp;
Byte[] frameData;
using (MemoryStream pngMs = new MemoryStream())
{
curFrame.Save(pngMs, ImageFormat.Png);
frameData = pngMs.ToArray();
}
// Get the colour depth to save in the icon info. This needs to be
// fetched explicitly, since png does not support certain types
// like 16bpp, so it will convert to the nearest valid on save.
Byte colDepth = frameData[24];
Byte colType = frameData[25];
// I think .Net saving only supports colour types 2, 3 and 6 anyway.
switch (colType)
{
case 2: bpp = 3 * colDepth; break; // RGB
case 6: bpp = 4 * colDepth; break; // ARGB
default: bpp = colDepth; break; // Indexed & greyscale
}
frameBytes[i] = frameData;
Int32 imageLen = frameData.Length;
// Write image entry
// 0 image width.
iconWriter.Write(width);
// 1 image height.
iconWriter.Write(height);
// 2 number of colors.
iconWriter.Write(colors);
// 3 reserved
iconWriter.Write((Byte)0);
// 4-5 color planes
iconWriter.Write((Int16)0);
// 6-7 bits per pixel
iconWriter.Write((Int16)bpp);
// 8-11 size of image data
iconWriter.Write(imageLen);
// 12-15 offset of image data
iconWriter.Write(offset);
offset += imageLen;
}
for (Int32 i = 0; i < imgCount; i++)
{
// Write image data
// png data must contain the whole png data file
iconWriter.Write(frameBytes[i]);
}
iconWriter.Flush();
}
}

C# Upload image and saving as Bitmap Increase size of the image

For uploading image I am using plupload on client side. Then in my controlled I have next logic:
public ActionResult UploadFile()
{
try
{
var file = Request.Files.Count > 0 ? Request.Files[0] : null;
using (var fileStream = new MemoryStream())
{
using (var oldImage = new Bitmap(file.InputStream))
{
var format = oldImage.RawFormat;
using (var newImage = ImageUtility.ResizeImage(oldImage, 800, 2000))
{
newImage.Save(fileStream, format);
}
byte[] bits = fileStream.ToArray();
}
}
{
catch (Exception ex)
{
}
}
ImageUtility.ResizeImage Method:
public static class ImageUtility
{
public static Bitmap ResizeImage(Bitmap image, int width, int height)
{
if (image.Width <= width && image.Height <= height)
{
return image;
}
int newWidth;
int newHeight;
if (image.Width > image.Height)
{
newWidth = width;
newHeight = (int)(image.Height * ((float)width / image.Width));
}
else
{
newHeight = height;
newWidth = (int)(image.Width * ((float)height / image.Height));
}
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;
}
}
}
The issue which i have here that Image size is increased.
I uploaded image of 1.62MB and after this controller is called and it creates instance if Bitmap and then save Bitmap to filestream and read bits with "fileStream.ToArray();" I am getting 2.35MB in "bits".
Can anyone tell me what's the reason of increasing the image size after I save it as bitmap. I need Bitmap because I need to check with and height of uploaded image and resize it if I need.
The answer is simple, the bitmap takes up more memory the whatever format the image was in previously because it's uncompressed it stays in that uncompressed format after saving it.
jpeg, png, gif, etc. are compressed and therefore use less bytes tha a bitmap which is uncompressed.
If you just want to save the original image, just save file.InputStream.
If you need to resize, you can use a library to apply jpg/png/etc compression and then save the result.
What is the goal here? Are you merely trying to upload an image? Does it need to be validated as an image? Or are you just trying to upload the file?
If upload is the goal, without any regard to validation, just move the bits and save them with the name of the file. As soon as you do this ...
using (var oldImage = new Bitmap(file.InputStream))
... you are converting to a bitmap. Here is where you are telling the bitmap what format to use (raw).
var format = oldImage.RawFormat;
If you merely want to move the file (upload), you can run the memory stream to a filestream object and you save the bits.
If you want a few checks on whether the image is empty, etc, you can try this page (http://www.codeproject.com/Articles/1956/NET-Image-Uploading), but realize it is still putting it in an image, which is not your desire if you simply want to save "as is".

Save as 8bit PNG

I am creating placeholder images in certain sizes that will be used as Data URIs
Bitmap bitmap = new Bitmap(16, 10);
I have done some research, but can't find a good way of saving this bitmap as the smallest possible filesize, which is why I want an 8bit PNG.
My question is: How can I save this bitmap into a file/bytearray/stream as an 8bit PNG? Any good libraries?
You can do this with nQuant (which you can install with nuget, or see references below). The following example converts an image on disk and would be readily adapted to meet your needs.
public static bool TryNQuantify(string inputFilename, string outputFilename)
{
var quantizer = new nQuant.WuQuantizer();
var bitmap = new Bitmap(inputFilename);
if (bitmap.PixelFormat != System.Drawing.Imaging.PixelFormat.Format32bppArgb)
{
ConvertTo32bppAndDisposeOriginal(ref bitmap);
}
try
{
using (var quantized = quantizer.QuantizeImage(bitmap))
{
quantized.Save(outputFilename, System.Drawing.Imaging.ImageFormat.Png);
}
}
catch
{
return false;
}
finally
{
bitmap.Dispose();
}
return true;
}
private static void ConvertTo32bppAndDisposeOriginal(ref Bitmap img)
{
var bmp = new Bitmap(img.Width, img.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using (var gr = Graphics.FromImage(bmp))
gr.DrawImage(img, new Rectangle(0, 0, img.Width, img.Height));
img.Dispose();
img = bmp;
}
For more information see:
https://github.com/mcychan/nQuant.cs
https://code.msdn.microsoft.com/windowsdesktop/Convert-32-bit-PNGs-to-81ef8c81
I like the FreeImage project, it is light weight and easy to use. Below is an example of creating a transparent png. You could easily wrap this in a method and set the width and height and transparency value.
//create a new bit map
FIBITMAP dib = new FIBITMAP();
//allocate a 16x10 bitmap with 8bit depth
dib = FreeImage.Allocate(16, 10, 8);
//set the transpareny
byte[] Transparency = new byte[1];
Transparency[0] = 0x00;
FreeImage.SetTransparencyTable(dib, Transparency);
//save the bitmap
FreeImage.Save(FREE_IMAGE_FORMAT.FIF_PNG, dib, "C:\\temp\\tp.png", FREE_IMAGE_SAVE_FLAGS.DEFAULT);
If all you need is a small transparent image, why stop at 8 bit? You can go straight down to 1 bit! You only need one colour anyway, and it'll be even smaller.
In fact, you don't even need to do anything special for that. Since the pixels on a new indexed bitmap will all default to 0, meaning they reference its first palette colour, all you need to do is make a new 1bpp image, and set that first palette colour to transparent:
public static Bitmap MakePlaceholderImage(Int32 width, Int32 height)
{
Bitmap bm = new Bitmap(width, height, PixelFormat.Format1bppIndexed);
// This colour can't be assigned directly since the .Palette getter actually makes a copy of the palette.
ColorPalette pal = bm.Palette;
pal.Entries[0] = Color.Transparent;
bm.Palette = pal;
return bm;
}
I experimented a bit with this, and, saved as png, the end result seemed to consistently be 8 times smaller than the result of the same code executed with 8bpp. For a 5000x5000 image, the file size as png was barely over 3 KiB.
Google search led me to a 6 year old thread and I can't find my solution. It should've been possible 6 years as well, as it uses the System.Drawing Libraray of the .Net Framework.
This example code should help anyone who want to write an 8 bit indexed png.
static class SaveImages
{
public static void SaveGrayImage(Bitmap srcImg, string name)
{
Bitmap grayImg = new Bitmap(srcImg.Width, srcImg.Height, PixelFormat.Format8bppIndexed);
var pal = grayImg.Palette;
foreach (int i in Enumerable.Range(0, 256))
pal.Entries[i] = Color.FromArgb(255, i, i, i);
grayImg.Palette = pal;
var data = grayImg.LockBits(new Rectangle(0, 0, srcImg.Width, srcImg.Height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
var bytes = new byte[data.Stride * data.Height];
foreach (int y in Enumerable.Range(0, srcImg.Height))
{
foreach (int x in Enumerable.Range(0, srcImg.Width))
{
var colour = srcImg.GetPixel(x, y);
var c = (int)colour.R + (int)colour.G + (int)colour.B;
c /= 3;
bytes[data.Stride * y + x] = (byte)c;
}
}
Marshal.Copy(bytes, 0, data.Scan0, bytes.Length);
grayImg.Save(name, ImageFormat.Png);
}
}
Edit: To add transparency dabble with the color palette.
1) Create your bitmap with 8 bit per pixel format:
Bitmap bmp = new Bitmap(20, 20, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
See PixelFormat for more formats.
2) Draw to the bitmap ...
3) Then save it as PNG:
bmp.Save(#"c:\temp\xyz.png", System.Drawing.Imaging.ImageFormat.Png);
The created file will have the same pixel format as bmp (8 bit)

Scaling .JPG images down from one directory and saving to another as .JPG/.PNG

SO what I'm trying to do here is to import a list of .JPG images that are of a large size and I would like to scale them down without too much of a quality loss and then output them as a .JPG/.PNG to not take up too much memory like .BMP's do.
I know that you can only manipulate images when they are .bmp's.
Here's some of the sample code I have(I only know how to import them)
private void LoadImages()
{
for (int i = 0; i < trees.Length; i++)
{
string d = imagePath + trees[i].latinName + ".JPG";
treesImage[i] = Image.FromFile(d);
}
//the image path is a constant
//trees[i].latinName is a string property
//treesImage is an array of Images created.
//so I'd like(preferably within my for loop to create the .bmp's and scale down
//using a const value such as const int width = 400, const int height = 300;
//and I'd lke to save the image to a different diretory than imagePath
}
if there is anything else you would like to know post below and I'll edit the question
Try this:
int newWidth = 75;
int newHeight = 50;
for (int i = 0; i < trees.Length; i++)
{
string d = imagePath + trees[i].latinName + ".JPG";
Image image = Image.FromFile(d);
//new image with size you need
Bitmap smallImage = new Bitmap(newWidth, newHeight);
Graphics g = Graphics.FromImage(smallImage);
//draw scaled old image to new with correct size
//g.drawImage(Image sourceImage, Rectangle destination, Rectangle source, GraphicsUnit gu)
g.DrawImage(image, new Rectangle(0, 0, smallImage.Width, smallImage.Height), new Rectangle(0, 0, image.Width, image.Height), GraphicsUnit.Pixel);
//format of new image is defined by it's name (.png/.jpg)
smallImage.Save(trees[i].latinName + "_new.png");
}

C# - Image size increases after creating a smaller resolution of the same image

I'm unable to see why this code creates a thumbnail of an image that was previously 1280x800 with a size of 241kb to 600x375 with a size of 556kb. Here is the code:
using (System.Drawing.Image img = System.Drawing.Image.FromFile(#"c:\images\myImg.jpg"))
{
int sourceWidth = img.Width;
int sourceHeight = img.Height;
int thumbHeight, thumbWidth = 0;
decimal ratio = decimal.Divide(sourceHeight, sourceWidth);
if (sourceHeight > 600 || sourceWidth > 800)
{
if (ratio >= 1) // Image is higher than it is wide.
{
thumbHeight = 800;
thumbWidth = Convert.ToInt32(decimal.Divide(sourceWidth, sourceHeight) * thumbHeight);
}
else // Image is wider than it is high.
{
thumbWidth = 600;
thumbHeight = Convert.ToInt32(decimal.Divide(sourceHeight, sourceWidth) * thumbWidth);
}
using (Bitmap bMap = new Bitmap(thumbWidth, thumbHeight))
{
Graphics gr = Graphics.FromImage(bMap);
gr.SmoothingMode = SmoothingMode.HighQuality;
gr.CompositingQuality = CompositingQuality.HighQuality;
gr.InterpolationMode = InterpolationMode.High;
Rectangle rectDestination = new Rectangle(0, 0, thumbWidth, thumbHeight);
gr.DrawImage(img, rectDestination, 0, 0, sourceWidth, sourceHeight, GraphicsUnit.Pixel);
bMap.Save(HttpContext.Current.Server.MapPath("~/i/" + filename + "_" + fileExtension));
}
}
}
Any help would be greatly appreciated.
Thank you kindly,
Ben
You're saving an image that used to be compressed using jpeg compression as a bitmap image that has no compression. The offending line is here:
bMap.Save(HttpContext.Current.Server
.MapPath("~/i/" + filename + "_" + fileExtension));
Just because you're saving it with a different file extension doesn't make the resulting image file a jpeg image. You need to use one of the Bitmap.Save overloads that specifies the format of the image you would like to save it as. For example
//Creating a second variable just for readability sake.
var resizedFilePath = HttpContext.Current.Server
.MapPath("~/i/" + filename + "_" + fileExtension);
bMap.Save(resizedFilePath, ImageFormat.Jpeg);
Granted, you're relying on Microsoft's implementation of the compression algorithm. It's not bad, but there may be better ones out there.
Now, what you could do is use the Image.RawFormat property of the original image to determine what kind of compression to use during the Save method. I've had varying success having that retrieve the proper method, so I generally use ImageFormat.Png as a backup (Png format supports image transparency, Jpeg does not).

Categories