我想压缩PNG图像,以减小其尺寸,但质量应保持不变。我试图压缩JPEG图片。图片压缩了大约90%,质量保持不变,但是当我用它压缩PNG图像时。没有结果,没有压缩。大小相同。
这是我的代码。
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)
{
}
}
对于PNG压缩,我更改了以下行。
Bitmap bmp1 = new Bitmap(imageFile);//pathOfImage);
ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Png);
请有人帮助我。如果有新方法,我欢迎它。如果这可以改变,那就更好了。
答案 0 :(得分:8)
PNG图像默认为32位。您可以将它们转换为8位:结果文件将比原始文件小5倍。对于大多数图像,质量损失几乎是不可见的。
这就是在线png压缩机的功能。
您可以使用nQuant自己完成此操作:http://nquant.codeplex.com/(在Nuget上可用)
var quantizer = new WuQuantizer();
using(var quantized = quantizer.QuantizeImage(bmp1))
{
quantized.Save(targetPath, ImageFormat.Png);
}
此博客文章http://www.hurryupandwait.io/blog/convert-32-bit-pngs-to-high-quality-8-bit-pngs-with-c
上提供了该方法的完整说明答案 1 :(得分:0)
PNG压缩中的一个主要变量是压缩速度和输出大小之间的权衡。 PNG压缩实际上可能非常慢,因为它涉及搜索数据缓冲区以匹配模式。您可以通过限制编码器搜索的缓冲区数来加速压缩。
您的编码器应该有一个设置,允许您指定搜索匹配项的方式。
IF 您的输入PNG图像未通过编码器搜索整个缓冲区进行压缩,您可以通过搜索应用程序中的完整缓冲区来获得一些改进的压缩。但是,您不太可能获得重大改进。
答案 2 :(得分:0)
我还建议您查看也可以与.NET Core一起使用的ImageSharp
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
}
}