Reputation: 179
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.
Upvotes: 6
Views: 30287
Reputation: 1823
PNG should be losless given pixel size and color depth are consistent. If looking for something to baseline output size against.
Upvotes: 0
Reputation: 59
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
}
}
Upvotes: 4
Reputation: 518
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
Upvotes: 13
Reputation: 21710
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.
Upvotes: 1