I have to compress the PNG file image, without losing the quality
Asked Answered
V

4

6

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.

Vervet answered 10/9, 2015 at 11:18 Comment(10)
PNG is already well compressed, unlikely to be improved.. You can't compress in JPG without losing some quality.Mclean
Images are themselves not PNG or JPEG. PNG and JPEG are file formats, representing ways to store some image. Both are compressed already. JPEG is "lossy", but is designed in such a way to preferentially lose data that most if not all humans would never notice simply by looking at the image. PNG is lossless; this necessarily prevents the PNG format from compressing a given image as much as JPEG can. PNG does have a large number of compression options, and it's possible other PNG encoders would compress better than the .NET one, but you'll never see the degree of compression as from JPEG.Hughes
@Taw, i cannot comment there, due to low rating. Up to some extent i can accept the loss. If i have a method, and it could ask me, for that much loss of image quality this would be size, so i would make a trade of.Vervet
@Peter Duniho JPEG can be compress. Image quality are loss obviously, but upto come extent it is acceptable. Is there any way i could compress PNG up to some extent, losing quality up to some extent.Vervet
"Is there any way i could compress PNG up to some extent, losing quality up to some extent" -- no, not really. PNG is by definition "lossless". As I mentioned, the format itself supports a variety of parameters that can be used to optimize the results, which can affect the final compressed size a bit (but nothing like what you're asking for), but the .NET encoder does not provide access to these parameters. You'd need a third-party encoder. Of course, you can always reduce the image dimensions; that necessarily discards information and would reduce the file size too.Hughes
...but, no. If you use PNG to compress, you have no option of trading quality of compression for file size in the same way that JPEG does.Hughes
@Peter Duniho I am curious, photoshop can compress PNG image, with some trade of with quality. How come it can not be done with .net.Vervet
You are incorrect about Photoshop. No matter what program encodes a PNG file, it will always have exactly the same pixel data as the original image. The only trade-off during encoding relates to time and variations in which compression techniques are used (different techniques are more appropriate for different kinds of data). Using the correct parameters can result in a more optimal compression, but no matter what parameters are used, you always get the same pixels out that you put in (which is completely different from lossy algorithms like JPEG).Hughes
at tinypng.com, they are quite good at PNG minification. what they do is "selectively decreasing the number of colors in the image", ie. quantization, probably similar to what the JPEG algorithm does.Spectroscope
i'd like to do as tinypng.com does too, but even WuQuantizer (although a great library) doesn't get close to tinypng.comGlue
F
13

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

Faraway answered 15/1, 2016 at 10:31 Comment(2)
Thanks 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.Diplomatist
Careful with this library. It has crash issues with somewhat large images with a lot of colors. archive.codeplex.com/?p=nquantBuckboard
R
4

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
                }     
            }
Regional answered 22/5, 2019 at 17:13 Comment(0)
A
1

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.

Aestheticism answered 11/9, 2015 at 18:24 Comment(3)
As Photoshop decrease the size of image with some trade of with quality. Same i want to do it with the help of .net.Vervet
There is no size/quality tradeoff in PNG. There is a compression time/size tradeoff that is possible with PNG.Aestheticism
By simply indexing the PNG you will also see a major improvementPardew
F
0

PNG should be losless given pixel size and color depth are consistent. If looking for something to baseline output size against.

https://pnggauntlet.com/

Farm answered 31/12, 2021 at 7:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.