I m trying to compress tiff file with CCITT4. Original size 101 KB, after run size reduce a little 98 KB. My limit size 50 KB, how can I make the size under my limit? code is below
My limits;
Size <50KB
Image Width: 1766 – 1890 pixels
Image Length: 915 – 1040 pixels
Thanks everyone.
Image Sample
public static Byte[] CompressBitmap(Bitmap img)
{
Bitmap bm = img;
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
ImageCodecInfo ici = null;
foreach (ImageCodecInfo codec in codecs)
{
if (codec.MimeType == "image/tiff")
ici = codec;
}
EncoderParameters ep = new EncoderParameters(1);
ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.SaveFlag,
(long)EncoderValue.Flush);
ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression,
(long)EncoderValue.CompressionCCITT4);
using (var stream = new MemoryStream())
{
bm.Save(stream, ici, ep);
return stream.ToArray();
}
}
Since the source Image seems to be a Color Image (that just happens to look like Black&White) and its dimensions need to be adjusted to a maximum value, you need to:
Redefine proportionally the Size of the source Image, setting the maximum Width and Height limits that the converted image needs to respect
Convert the Image to a 1bpp Indexed format: the Bitmap.Clone() method provides means to both define the source Image new Size and set a specific PixelFormat (PixelFormat.Format1bppIndexed, in this case). The internal conversion method is quite good, the resulting Image quality is usually a good compromise.
Define the quality of the Image: since the Image will be converted to B&W, its quality can be set initially to the maximum (100). The process can be repeated if the final Image bytes count doesn't fit the requirements (50KB)
Compress the Image using the CCTII Group 4 Compression scheme
Encode the Image, using the TIFF format Encoder, saving it to a MemoryStream for further processing
The size in bytes of the sample Image provided in the question, when saved to a file, is reduced from the initial 94,600 bytes to 6,786 bytes with maximum quality.
File.WriteAllBytes("[Image Path].tiff", imageStream.ToArray());
The ConvertToBWTiffImageStream() method can be called as:
var maximumWidthAndHeight = new Size(1024, 768);
int quality = 100;
var compression = EncoderValue.CompressionCCITT4;
var imageStream = ConvertToBWTiffImageStream(sourceImage, maximumWidthAndHeight, quality, compression);
Note that maximumWidthAndHeight specify the maximum Width and the maximum Height, not a new Size of the Image (which would be otherwise distorted). The Image Size is scaled proportionally according to these values.
► Remember to add this: using ImageCodec = System.Drawing.Imaging.Encoder;
(the GetImageMaxSize() method is half-dumb, I'll fix it later)
using System.Drawing;
using System.Drawing.Imaging;
using ImageCodec = System.Drawing.Imaging.Encoder;
private MemoryStream ConvertToBWTiffImageStream(Bitmap image, Size maxWidthHeight, long compressionLevel, EncoderValue compressionScheme)
{
var imageSize = GetImageMaxSize(image, maxWidthHeight);
var bwImage = image.Clone(new Rectangle(Point.Empty, image.Size), PixelFormat.Format1bppIndexed);
compressionLevel = Math.Max(0, Math.Min(100, compressionLevel));
var codecParms = new EncoderParameters(2);
try {
var imageCodec = ImageCodecInfo.GetImageEncoders().FirstOrDefault(enc => enc.FormatID == ImageFormat.Tiff.Guid);
var qualityParam = new EncoderParameter(ImageCodec.Quality, compressionLevel);
var compressionParam = new EncoderParameter(ImageCodec.Compression, (long)compressionScheme);
var ms = new MemoryStream();
codecParms.Param[0] = qualityParam;
codecParms.Param[1] = compressionParam;
image.Save(ms, imageCodec, codecParms);
return ms;
}
finally {
codecParms.Dispose();
bwImage.Dispose();
}
}
private Size GetImageMaxSize(Image image, Size maxSize)
{
float scale = 1.0f;
if (image.Width > maxSize.Width && image.Width >= image.Height) {
scale = (float)maxSize.Width / image.Width;
}
else if (image.Height > maxSize.Height) {
scale = (float)maxSize.Height / image.Height;
}
return new Size((int)(image.Width * scale), (int)(image.Height * scale));
}
Related
I've seen a ton of stackoverflow articles for reducing image size, but none of them maintain the original image type (or so I've found). They usually have steps to reduce pixel dimensions, reduce image quality, and convert to a specific type of image (usually jpeg).
I have a group of images that I need to resize. They have various image types, and the filenames are all stored in a database, which makes converting from one image type to another somewhat problematic. I can't just change the filename from png to jpg because then the database won't point at a real file.
Doe anyone have an example of how to resize / reduce images to '256 kilobytes' and maintain the original image type?
For examples, here is the code I'm currently fiddling with.
public static byte[] ResizeImageFile(Image oldImage, int targetSize) // Set targetSize to 1024
{
Size newSize = CalculateDimensions(oldImage.Size, targetSize);
using (Bitmap newImage = new Bitmap(newSize.Width, newSize.Height, PixelFormat.Format24bppRgb))
{
using (Graphics canvas = Graphics.FromImage(newImage))
{
canvas.SmoothingMode = SmoothingMode.AntiAlias;
canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
canvas.PixelOffsetMode = PixelOffsetMode.HighQuality;
canvas.DrawImage(oldImage, new Rectangle(new Point(0, 0), newSize));
MemoryStream m = new MemoryStream();
newImage.Save(m, ImageFormat.Jpeg);
return m.GetBuffer();
}
}
}
Maybe there is a way I can get file fileinfo or mime type first and then switch on the .Save for the type of image?
Here is what I came up with (based on some examples that I found online that weren't 100% complete.
private void EnsureImageRequirements(string filePath)
{
try
{
if (File.Exists(filePath))
{
// If images are larger than 300 kilobytes
FileInfo fInfo = new FileInfo(filePath);
if (fInfo.Length > 300000)
{
Image oldImage = Image.FromFile(filePath);
ImageFormat originalFormat = oldImage.RawFormat;
// manipulate the image / Resize
Image tempImage = RefactorImage(oldImage, 1200); ;
// Dispose before deleting the file
oldImage.Dispose();
// Delete the existing file and copy the image to it
File.Delete(filePath);
// Ensure encoding quality is set to an acceptable level
ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();
// Set encoder to fifty percent compression
EncoderParameters eps = new EncoderParameters
{
Param = { [0] = new EncoderParameter(Encoder.Quality, 50L) }
};
ImageCodecInfo ici = (from codec in encoders where codec.FormatID == originalFormat.Guid select codec).FirstOrDefault();
// Save the reformatted image and use original file format (jpeg / png / etc) and encoding
tempImage.Save(filePath, ici, eps);
// Clean up RAM
tempImage.Dispose();
}
}
}
catch (Exception ex)
{
this._logger.Error("Could not resize oversized image " + filePath, ex);
}
}
private static Image RefactorImage(Image imgToResize, int maxPixels)
{
int sourceWidth = imgToResize.Width;
int sourceHeight = imgToResize.Height;
int destWidth = sourceWidth;
int destHeight = sourceHeight;
// Resize if needed
if (sourceWidth > maxPixels || sourceHeight > maxPixels)
{
float thePercent = 0;
float thePercentW = 0;
float thePercentH = 0;
thePercentW = maxPixels / (float) sourceWidth;
thePercentH = maxPixels / (float) sourceHeight;
if (thePercentH < thePercentW)
{
thePercent = thePercentH;
}
else
{
thePercent = thePercentW;
}
destWidth = (int)(sourceWidth * thePercent);
destHeight = (int)(sourceHeight * thePercent);
}
Bitmap tmpImage = new Bitmap(destWidth, destHeight, PixelFormat.Format24bppRgb);
Graphics g = Graphics.FromImage(tmpImage);
g.InterpolationMode = InterpolationMode.HighQualityBilinear;
g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
g.Dispose();
return tmpImage;
}
I am uploading an image and reducing the dimensions. One of the reasons to do it is that I want also to reduce the size so it is better optimised and does not load long time.
But instead of downsizing the image has been enlarged despite the dimensions have halved.
This is my function:
public Image ScaleProportionally(Image imgPhoto, int shortestEdge = 0)
{
float sourceWidth = imgPhoto.Width;
float sourceHeight = imgPhoto.Height;
float destHeight = 0;
float destWidth = 0;
int sourceX = 0;
int sourceY = 0;
int destX = 0;
int destY = 0;
if (shortestEdge > 0)
{
if(sourceWidth < sourceHeight)
{
destWidth = shortestEdge;
destHeight = (float)(sourceHeight * shortestEdge / sourceWidth);
}
else
{
destWidth = (float)(shortestEdge * sourceWidth) / sourceHeight;
destHeight = shortestEdge;
}
Bitmap bmPhoto = new Bitmap((int)destWidth, (int)destHeight,
PixelFormat.Format32bppPArgb);
bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);
Graphics grPhoto = Graphics.FromImage(bmPhoto);
grPhoto.InterpolationMode = InterpolationMode.Low;
grPhoto.CompositingQuality = CompositingQuality.AssumeLinear;
grPhoto.DrawImage(imgPhoto,
new Rectangle(destX, destY, (int)destWidth, (int)destHeight),
new Rectangle(sourceX, sourceY, (int)sourceWidth, (int)sourceHeight),
GraphicsUnit.Pixel);
grPhoto.Dispose();
return bmPhoto;
}
else
{
return imgPhoto;
}
}
I originally had this below for InterpolationMode and CompositingQuality but changing them as above didn't really reduced the size of scaled photo:
grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;
grPhoto.CompositingQuality = CompositingQuality.HighSpeed;
Original image has 546KB while scaled has 1MB almost twice the size.
How to reduce the size on rescaling?
I am using .NET 4.5
EDIT
Save file function:
public int CreateAndSaveMedia(HttpPostedFileBase file, string fileName, string mediaType, string caption, int folderId, Dictionary<string,string> additionalProperties = null)
{
// Create temp mediaitem folder
string mediaDirectory = System.Web.HttpContext.Current.Server.MapPath($"~/media/");
var path = Path.Combine(mediaDirectory, fileName);
file.SaveAs(path);
Image imgOriginal = Image.FromFile(path);
//pass in whatever value you want
Image imgActual = _imageService.ScaleProportionally(imgOriginal, 450);
imgOriginal.Dispose();
imgActual.Save(path);
imgActual.Dispose();
// Open file and assign media url to media content
FileStream s = new FileStream(path, FileMode.Open);
// Save media content
IMedia media = _mediaService.CreateMedia(caption, folderId, mediaType);
_mediaService.Save(media);
media.SetValue("umbracoFile", Path.GetFileName(path), s);
if (additionalProperties != null)
{
foreach (var itm in additionalProperties)
{
media.SetValue(itm.Key, itm.Value);
}
}
_mediaService.Save(media);
// Get media Id
int mediaId = media.Id;
s.Close();
System.IO.File.Delete(path);
return mediaId;
}
EDIT
Following #Nyerguds's comment I specifically set the new image type to jpg and it made a total difference:
imgActual.Save(path, System.Drawing.Imaging.ImageFormat.Jpeg);
Thanks!
You're not setting a type when saving, which makes the Image.Save default to either the detected type of the original image, or to PNG if it can't save in the exact format detected from the input.
The compression you get out of png depends a lot on what is in the image; png isn't very good at compressing complex images like photos, and resizing it to smaller size might in fact increase said complexity. Also, the .Net framework's png compression algorithms aren't as good as those in actual graphics manipulation programs.
For reducing size, you may want to specifically re-save as jpeg.
This can be done in two ways. The simple way is to just specify Jpeg as save type:
imgActual.Save(path, ImageFormat.Jpeg);
A more advanced method is to use the JPEG encoder. If you do this, you can set the save quality (inverse of compression rate, really) of the image, as percentage (values from 1 to 100). Unfortunately, though, there's no simple method to get it; you need to retrieve it by GUID by going over the full list of available encoders:
Int32 quality = 80;
ImageCodecInfo jpegEncoder = ImageCodecInfo.GetImageDecoders().First(c => c.FormatID == ImageFormat.Jpeg.Guid);
EncoderParameters encparams = new EncoderParameters(1);
encparams.Param[0] = new EncoderParameter(Encoder.Quality, quality);
imgActual.Save(path, jpegEncoder, encparams);
I'm using ImageProcessor to reduce the resolution or quality of an image, but I'm don't know how to make sure that the image resultant size it's below 5 megabytes. I tried setting the image dimensions to 3840-2160 but I want to use a better option.
Here it's my code:
private static byte[] redimensionImage(ref byte[] photoBytes)
{
var byteCuantity = ConvertBytesToMegabytes(photoBytes.Count());
ISupportedImageFormat format = new JpegFormat();
using (MemoryStream inStream = new MemoryStream(photoBytes))
{
using (MemoryStream outStream = new MemoryStream())
{
// Initialize the ImageFactory using the overload to preserve EXIF metadata.
using (ImageFactory imageFactory = new ImageFactory(preserveExifData: true))
{
// Load, resize, set the format and quality and save an image.
using (var imageProcessor = imageFactory.Load(inStream))
{
var originalHeight = imageProcessor.Image.Size.Height;
var originalWidth = imageProcessor.Image.Size.Width;
//calculate aspect ratio
var aspect = originalWidth / (float)originalHeight;
int newWidth, newHeight;
var dimenssionTooSmall = false;
if (originalWidth <= originalHeight && originalWidth < 100)
{
//calculate new dimensions based on aspect ratio
newHeight = (int)(100 / aspect);
var resizeLayer = new ResizeLayer(new Size(100, newHeight), ResizeMode.Min);
imageProcessor.Resize(resizeLayer);
dimenssionTooSmall = true;
}
else if (originalHeight < originalWidth && originalHeight < 100)
{
//calculate new dimensions based on aspect ratio
newWidth = (int)(100 / aspect);
var resizeLayer = new ResizeLayer(new Size(newWidth, 100), ResizeMode.Min);
imageProcessor.Resize(resizeLayer);
dimenssionTooSmall = true;
}
if (byteCuantity > 1 || dimenssionTooSmall)
{
//format.Quality = 6;
imageProcessor.Resize(new ResizeLayer(new Size(3840, 2160), ResizeMode.Min));
imageProcessor.Format(format);
imageProcessor.Save(outStream);
return outStream.ToArray();
}
else
{
return inStream.ToArray();
}
}
}
}
}
}
Thanks and regards.
Unfortunately there's no way you can really do this without reprocessing unless you're saving as bitmap.
When you save an image there are many compression processes that take place to store the image in each individual format (except bitmap which doesn't compress the image). Without actually going through the process itself you can't predict the file size.
You could potentially create your own lookup tables to act as a guideline by resizing a large sample of images in different formats and collecting the output sizes to give you a rough estimate for future processing.
I want to make image size smaller then its original size.I am using following code for compress the size images but it increased the image size from 1MB to 1.5MB
Any Other solution for compress large size images without change image original height,width.
public static byte[] CompressImage(Image img) {
int originalwidth = img.Width, originalheight = img.Height;
Bitmap bmpimage = new Bitmap(originalwidth, originalheight);
Graphics gf = Graphics.FromImage(bmpimage);
gf.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
gf.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.AssumeLinear;
gf.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
Rectangle rect = new Rectangle(0, 0, originalwidth, originalheight);
gf.DrawImage(img, rect, 0, 0, originalwidth, originalheight, GraphicsUnit.Pixel);
byte[] imagearray;
using (MemoryStream ms = new MemoryStream())
{
bmpimage.Save(ms, ImageFormat.Jpeg);
imagearray= ms.ToArray();
}
return imagearray;
}
You can set the quality level when you save the file as JPEG, which mostly also directly will correlate with file size - the less quality the smaller your output file will be.
Also see How to: Set JPEG Compression Level , for an example see this SO answer.
As said by #BrokenGlass you can specify the compression level within the EncoderParameter. Here's a snippet if you want to give a try changing quality:
public static void SaveJpeg(string path, Image image, int quality)
{
//ensure the quality is within the correct range
if ((quality < 0) || (quality > 100))
{
//create the error message
string error = string.Format("Jpeg image quality must be between 0 and 100, with 100 being the highest quality. A value of {0} was specified.", quality);
//throw a helpful exception
throw new ArgumentOutOfRangeException(error);
}
//create an encoder parameter for the image quality
EncoderParameter qualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
//get the jpeg codec
ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
//create a collection of all parameters that we will pass to the encoder
EncoderParameters encoderParams = new EncoderParameters(1);
//set the quality parameter for the codec
encoderParams.Param[0] = qualityParam;
//save the image using the codec and the parameters
image.Save(path, jpegCodec, encoderParams);
}
I've got to following function which is called to change the resolution of an image. I want to do this so uploaded image with for example 300dpi will be modified to 72dpi (for web). This question is related to another question here on SO where i'm working on.
I'm creation an extension method for this to be able to use this function on more places in my application, instead of only when uploading new files. (See above mentioned question)
public static byte[] SetDpiTo72(this byte[] imageToFit, string mimeType, Size newSize)
{
using (MemoryStream memoryStream = new MemoryStream(), newMemoryStream = new MemoryStream())
{
memoryStream.Write(imageToFit, 0, imageToFit.Length);
var originalImage = new Bitmap(memoryStream);
using (var canvas = Graphics.FromImage(originalImage))
{
canvas.SmoothingMode = SmoothingMode.AntiAlias;
canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
canvas.PixelOffsetMode = PixelOffsetMode.HighQuality;
canvas.DrawImage((Image)originalImage,0,0, newSize.Width, newSize.Height);
newBitmap.SetResolution(72, 72);
newBitmap.Save(newMemoryStream, ImageFunctions.GetEncoderInfo(mimeType), null);
}
return newMemoryStream.ToArray();
}
}
The mentioned extension methode is being called in a function similar to the situation below;
if (newSize.Width > originalImage.Width && newSize.Height > originalImage.Height)
{
newSize.Width = originalImage.Width;
newSize.Height = originalImage.Height;
uploadedFileBuffer = uploadedFileBuffer.SetDpiTo72(uploadedFile.ContentType, newSize);
return CreateFile(newSize, uploadedFile, uploadedFileBuffer);
}
The bytearray coming in is the file as an bytearray. It already has the correct size, but I want to change the resolution to 72dpi. However after exectution and saving the image the resolution is still the originale entered resolution, which is 300dpi. How can I do this?
UPDATE AFTER SEVERAL ANSWERS:
public static byte[] SetDpiTo72(this byte[] imageToFit, string mimeType, Size newSize)
{
using (MemoryStream memoryStream = new MemoryStream(), newMemoryStream = new MemoryStream())
{
memoryStream.Write(imageToFit, 0, imageToFit.Length);
var originalImage = new Bitmap(memoryStream);
using (var canvas = Graphics.FromImage(originalImage))
{
canvas.SmoothingMode = SmoothingMode.AntiAlias;
canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
canvas.PixelOffsetMode = PixelOffsetMode.HighQuality;
canvas.DrawImage((Image)originalImage,0,0, newSize.Width, newSize.Height);
originalImage.SetResolution(72, 72);
var epQuality = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 75);
var epParameters = new EncoderParameters(1);
epParameters.Param[0] = epQuality;
Image newimg = Image.FromStream(memoryStream);
//Getting an GDI+ exception after the execution of this line.
newimg.Save("C:\\test1234.jpg", ImageFunctions.GetEncoderInfo(mimeType), epParameters);
originalImage.Save("test.jpg", ImageFormat.Jpeg);
//This line give me an Argumentexception - Parameter is not valid.
//originalImage.Save(newMemoryStream, ImageFunctions.GetEncoderInfo(mimeType), epParameters);
//newMemoryStream.Close();
}
return newMemoryStream.ToArray();
}
}
The stackstrace which comes with the exception is telling me the following;
at System.Drawing.Image.Save(String filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
at Extensions.ByteArrayExtensions.SetDpiTo72(Byte[] imageToFit, String mimeType, Size newSize) in C:\Website\Project\Extensions\ByteArrayExtensions.cs:line 356
at CMS.Presentation.FileFunctions.CreateFullsizeImage(HttpPostedFileBase uploadedFile, Size newSize, Byte[] uploadedFileBuffer) in C:\Website\Project\CMS.Presentation\FileFunctions.cs:line 197
at CMS.Presentation.FileFunctions.CreateFile(HttpPostedFileBase uploadedFile, INodeService nodeservice, Guid userId, Node parentNode) in C:\Website\Project\CMS.Presentation\FileFunctions.cs:line 53
In the mean time I've also developed another function (see below) resizing just a bitmap. And this seem to work correctly. I can't use this function with my current implementation though because it returns just an Bitmap. Or should i change everything to work with bitmaps?
private static Bitmap ResizeImage(Image image, int width, int height)
{
var frameCount = image.GetFrameCount(new FrameDimension(image.FrameDimensionsList[0]));
var newDimensions = ImageFunctions.GenerateImageDimensions(image.Width, image.Height, width, height);
Bitmap resizedImage;
if (frameCount > 1)
{
//we have a animated GIF
resizedImage = ResizeAnimatedGifImage(image, width, height);
}
else
{
resizedImage = (Bitmap)image.GetThumbnailImage(newDimensions.Width, newDimensions.Height, null, IntPtr.Zero);
}
resizedImage.SetResolution(72,72);
return resizedImage;
}
Ok, I tried it only on files on harddrive, but it should work with streams too.
Bitmap bitmap = new Bitmap(loadFrom);
Bitmap newBitmap = new Bitmap(bitmap);
newBitmap.SetResolution(72, 72);
newBitmap.Save(saveTo);
Took me a while, but I finally found the problem!
The problem lied in the ResizeImage function I used. In the 'GetThumbnailImage' to be specific. I ran into another problem with blurry images, which was explainable because GetThumbnailImage would stretch up the created ThumbNail to the desired size. And the resolution off the thumbnail never changes.
private static Bitmap ResizeImage(Image image, int width, int height)
{
var frameCount = image.GetFrameCount(new FrameDimension(image.FrameDimensionsList[0]));
var newDimensions = ImageFunctions.GenerateImageDimensions(image.Width, image.Height, width, height);
Bitmap resizedImage;
if (frameCount > 1)
{
//we have a animated GIF
resizedImage = ResizeAnimatedGifImage(image, width, height);
}
else
{
resizedImage = (Bitmap)image.GetThumbnailImage(newDimensions.Width, newDimensions.Height, null, IntPtr.Zero);
}
resizedImage.SetResolution(72,72);
return resizedImage;
}
By modifying the function above to the function below I was able to solve the problem using Graphics.DrawImage to redraw the new image before rendering it. Also the GenerateImageDimensions was slightly modified. This taken together the problem was solved.
private static Bitmap ResizeImage(Image image, int width, int height)
{
var frameCount = image.GetFrameCount(new FrameDimension(image.FrameDimensionsList[0]));
var newDimensions = ImageFunctions.GenerateImageDimensions(image.Width, image.Height, width, height);
var resizedImage = new Bitmap(newDimensions.Width, newDimensions.Height);
if (frameCount > 1)
{
//we have a animated GIF
resizedImage = ResizeAnimatedGifImage(image, width, height);
}
else
{
//we have a normal image
using (var gfx = Graphics.FromImage(resizedImage))
{
gfx.SmoothingMode = SmoothingMode.HighQuality;
gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
gfx.PixelOffsetMode = PixelOffsetMode.HighQuality;
var targRectangle = new Rectangle(0, 0, newDimensions.Width, newDimensions.Height);
var srcRectangle = new Rectangle(0, 0, image.Width, image.Height);
gfx.DrawImage(image, targRectangle, srcRectangle, GraphicsUnit.Pixel);
}
}
return resizedImage;
}
By "changing the resolution", do you actually mean you want to reduce the number of pixels in the image by 72/300? I.e. change a 4000x3000 image to 960x720?
If so, I can't see where your code actually does that. The overload of DrawImage() you're using does this:
Draws the specified image, using its original physical size, at the location specified by a coordinate pair.
Which is exactly what is happening.
Try one of the other overloads such as this one:
Draws the specified Image at the specified location and with the specified size.
for example:
// Create image.
Image newImage = Image.FromFile("SampImag.jpg");
// Create coordinates for upper-left corner of image and for size of image.
int x = 0;
int y = 0;
int width = 450;
int height = 150;
// Draw image to screen.
e.Graphics.DrawImage(newImage, x, y, width, height);
EDIT: per the comments, I understand the OP wants to reduce file size without reducing pixel count. Therefore the files must be recompressed.
I've borrowed some sample code from here:
ImageCodecInfo iciJpegCodec = null;
// This will specify the image quality to the encoder. Change the value of 75 from 0 to 100, where 100 is best quality, but highest file size.
EncoderParameter epQuality = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 75);
// Get all image codecs that are available
ImageCodecInfo[] iciCodecs = ImageCodecInfo.GetImageEncoders();
// Store the quality parameter in the list of encoder parameters
EncoderParameters epParameters = new EncoderParameters(1);
epParameters.Param[0] = epQuality;
// Loop through all the image codecs
for (int i = 0; i < iciCodecs.Length; i++)
{
// Until the one that we are interested in is found, which is image/jpeg
if (iciCodecs[i].MimeType == "image/jpeg")
{
iciJpegCodec = iciCodecs[i];
break;
}
}
// Create a new Image object from the current file
Image newImage = Image.FromFile(strFile);
// Get the file information again, this time we want to find out the extension
FileInfo fiPicture = new FileInfo(strFile);
// Save the new file at the selected path with the specified encoder parameters, and reuse the same file name
newImage.Save(outputPath + "\\" + fiPicture.Name, iciJpegCodec, epParameters);
Rob, I believe that issue with your code is at saving the image - the actual digital image data would be certain number of dots/pixels i.e. (m x n) and setting resolution at bitmap wouldn't/shouldn't change the number dots (and hence physical byte size of image). The resolution information will be stored in the image header (to be used by programs while printing/editing images) - what happens if you store the new bitmap to file instead of mem stream
newBitmap.Save("c:\test.png", ImageFormat.Png);
Check dpi for above file from file -> properties -> summary (advanced). It should be 72 dpi.