I have to compress the PNG file image, without losing the quality
Solution 1
PNG Images are 32 bits by default. You can convert them to 8 bits : resulting file will be about 5 times smaller than the original one. With most images, the loss of quality is almost invisible.
This is what online png compressors do.
You can do this yourself by using nQuant : http://nquant.codeplex.com/ (available on Nuget)
var quantizer = new WuQuantizer();
using(var quantized = quantizer.QuantizeImage(bmp1))
{
quantized.Save(targetPath, ImageFormat.Png);
}
Full explanation of the method is available on this blog post http://www.hurryupandwait.io/blog/convert-32-bit-pngs-to-high-quality-8-bit-pngs-with-c
Solution 2
I also suggest looking at ImageSharp which also works with .NET Core
using (var image = Image.Load(fileData)) // fileData could be file path or byte array etc.
{
var h = image.Size().Height / 2;
var w = image.Size().Width / 2;
var options = new ResizeOptions
{
Mode = ResizeMode.Stretch,
Size = new Size(w, h)
};
image.Mutate(_ => _.Resize(options));
using (var destStream = new MemoryStream())
{
var encoder = new JpegEncoder();
image.Save(destStream, encoder);
// Do something with output stream
}
}
Solution 3
The one major variable in PNG compression is the tradeoff between compression speed and output size. PNG compression can actually be quite slow because it involves searching a data buffer for matching patterns. You can speed up the compression by limiting how much of the buffer the encoder searches.
Your encoder should have a setting that allows you to specify how searching for matches it will do.
IF your input PNG image was not compressed with the encoder searching the entire buffer, you may get some improved compression by searching the full buffer in your application. However, you are unlikely to get a major improvement.
Muhammad Bashir
Updated on December 31, 2021Comments
-
Muhammad Bashir over 2 years
I want to compress a PNG image, to reduce its size but the quality should remain the same. I have tried to compress JPEG picture. Picture compressed about 90% and quality remain the same but when i compress a PNG image with it. No result, no compression. Same size.
Here is my code.
public const string _StatusLog = "StatusLog.csv"; static void Main(string[] args) { Console.WriteLine(" ### WELCOME ###"); Console.Write("\n\nPlease enter image folder path :"); string imagePath = Console.ReadLine(); Program p = new Program(); p.VaryQualityLevel(imagePath); Console.ReadLine(); } private void VaryQualityLevel(string pathOfImage) { try { //Console.Write("Target Directory Path :"); string targetDirectory = pathOfImage;//Console.ReadLine(); if (targetDirectory != null) { string[] allDirectoryInTargetDirectory = Directory.GetDirectories(targetDirectory); //PRODUCT DIRECOTY OPEN Console.Write("Total Folders found = " + allDirectoryInTargetDirectory.Count()); Console.Read(); if (allDirectoryInTargetDirectory.Any()) { foreach (var directory in allDirectoryInTargetDirectory) { string[] subDirectory = Directory.GetDirectories(directory); // ATTRIBUTE DIRECTORY OPEN if (subDirectory.Any()) { foreach (var filesInSubDir in subDirectory) { string[] allFilesInSubDir = Directory.GetFiles(filesInSubDir); //FILES IN SUB DIR OPEN if (allFilesInSubDir.Any()) { foreach (var imageFile in allFilesInSubDir) { try { Bitmap bmp1 = new Bitmap(imageFile);//pathOfImage); ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Jpeg); // Create an Encoder object based on the GUID // for the Quality parameter category. System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality; // Create an EncoderParameters object. // An EncoderParameters object has an array of EncoderParameter // objects. In this case, there is only one // EncoderParameter object in the array. #region SAVING THE COMPRESS IMAGE FILE EncoderParameters myEncoderParameters = new EncoderParameters(1); EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 50L); myEncoderParameters.Param[0] = myEncoderParameter; bmp1.Save(filesInSubDir + "\\" + "Zip" + GettingImageNameForOptimizedImage(imageFile), jpgEncoder, myEncoderParameters);//pathOfImage Console.WriteLine(filesInSubDir + GettingImageNameForOptimizedImage(imageFile) + " CREATED");//pathOfImage #endregion #region DELETING THE ORIGNAL FILE bmp1.Dispose(); System.IO.File.Delete(filesInSubDir + "\\" + GettingImageNameForOptimizedImage(imageFile));//pathOfImage Console.WriteLine(imageFile.Replace("jpg", "png") + " DELETED");//pathOfImage #endregion //myEncoderParameter = new EncoderParameter(myEncoder, 100L); //myEncoderParameters.Param[0] = myEncoderParameter; //bmp1.Save("D:\\" + RemovingImageFormat[0] + "100L" + ".jpg", jpgEncoder, myEncoderParameters); #region BACK RENAMING FILE TO ORIGNAL NAME System.IO.File.Move(filesInSubDir + "\\" + "Zip" + GettingImageNameForOptimizedImage(imageFile), filesInSubDir + "\\" + GettingImageNameForOptimizedImage(imageFile)); #endregion } catch (Exception ex) { Console.Write("\n" + ex.Message + " Press enter to continue :"); Console.ReadLine(); Console.Write("\nWould you like to retry ? [Y/N] :"); string resp = Console.ReadLine(); if (resp == "Y" || resp == "y") { Console.WriteLine(" -------------------\n\n"); Main(null); } } } } } } } } } } catch (Exception ex) { Console.Write(ex); Console.Read(); } Console.Write("Press any key to exit..."); Console.Read(); // Get a bitmap. ################################################################### } private ImageCodecInfo GetEncoder(ImageFormat format) { ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders(); foreach (ImageCodecInfo codec in codecs) { if (codec.FormatID == format.Guid) { return codec; } } return null; } public string GettingImageNameForOptimizedImage(string pathOfImage) { try { string[] splitingPathOfImage = pathOfImage.Split('\\'); string[] RemovingImageFormat = splitingPathOfImage[splitingPathOfImage.Count() - 1].ToString().Split('.'); return RemovingImageFormat[0] + ".jpg"; } catch (Exception) { return null; } return null; } public static void LoggingOperations(string ImageName, string Status, bool UpdateRequired) { try { if (!File.Exists(_StatusLog)) { using (File.Create(_StatusLog)) { } DirectorySecurity sec = Directory.GetAccessControl(_StatusLog); SecurityIdentifier everyone = new SecurityIdentifier(WellKnownSidType.WorldSid, null); sec.AddAccessRule(new FileSystemAccessRule(everyone, FileSystemRights.Modify | FileSystemRights.Synchronize, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Allow)); Directory.SetAccessControl(_StatusLog, sec); } if (UpdateRequired == true) { string UpdateStatusText = File.ReadAllText(_StatusLog); UpdateStatusText = UpdateStatusText.Replace(ImageName, ImageName + "," + Status); File.WriteAllText(_StatusLog, UpdateStatusText); UpdateStatusText = ""; } else { File.AppendAllText(_StatusLog, Environment.NewLine); File.AppendAllText(_StatusLog, Status); } } catch (Exception) { } }
For PNG compression i changed the following line.
Bitmap bmp1 = new Bitmap(imageFile);//pathOfImage); ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Png);
Kindly some one help me out. If there is a new method, I welcome it. If this could be altered, it would a lot better.
-
Muhammad Bashir over 8 yearsAs Photoshop decrease the size of image with some trade of with quality. Same i want to do it with the help of .net.
-
user3344003 over 8 yearsThere is no size/quality tradeoff in PNG. There is a compression time/size tradeoff that is possible with PNG.
-
Doug S almost 8 yearsThanks for suggesting nQuant. I just tried it. Where .NET was creating a 800kb PNG with alpha transparency, nQuant was able to create the same PNG image at only 240kb, with no discernible quality loss. Keep in mind it does this by reducing the color count to 256, but it does it very smartly.
-
Pierre about 6 yearsBy simply indexing the PNG you will also see a major improvement
-
Donny V. over 4 yearsCareful with this library. It has crash issues with somewhat large images with a lot of colors. archive.codeplex.com/?p=nquant