-3

How can I compress images of different sizes (2-5-10-20 MB) of type .jpg to almost 1-1.5 MB in C#? I have been trying to compress using the 'quality' factor in the MagickImage library, but the quality factor is not proportional to the percentage. I have searched and tried different libraries but I couldn't find the solution I'm looking for.

There is an iterative way - compress the image, check its size and if its greater than the desired size, keep compressing it until the size is desired. Is this a good way?

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
  • A JPEG is already a compressed (lossy) format. You're not going to get more out of it without losing more quality. Why do you need to make them so small? Do they need to remain images that are readable by general image software, or can you use a zip file? – Logarr Oct 25 '22 at 06:45
  • @Logarr - I have jpg images of size 10-15mbs. Now I need to show a mix of 2-4 images at a time on the website. Therefore we have to compress them so that site does not hang/lag. I chose the compressed size to be 1-1.5mb because its not that bad, I've tested it its working for us. – Aakash Rana Oct 25 '22 at 06:57
  • Your "iterative way" is terrible - the results are guaranteed to be much worse than finding the right quality setting to compress the original image in a single go. – Orion Oct 25 '22 at 07:02
  • @Orion - That is why I did not use it and asked for suggestions and better solution here :) – Aakash Rana Oct 25 '22 at 07:08
  • @AakashRana the answer is `compression doesn't work this way`. The notion you have is simply wrong. Quality is quality, not size. *Nothing* says it has a linear relation to size. A solid color image compresses far better than other images, even in 100% quality. You'll have to try different quality values until you get the size you want. *OR* resize the picture before compressing. – Panagiotis Kanavos Oct 25 '22 at 07:15
  • @Logarr how is a ZIP file going to be smaller than an already compressed image ? ZIP compression is by definition lossless. – Panagiotis Kanavos Oct 25 '22 at 07:16
  • _Is this a good way?_ It is the only way. But make sure to start each iteration with the original. Instead of MagickImage the regular GDI quality parameter should work pretty much equally well. – TaW Oct 25 '22 at 07:28

2 Answers2

3

There is no real way to estimate the final size of a compressed image without compressing it. Some types of images are just easier to compress than others, take a fully black image, a good compressor should compress that to a very small size, and the quality value should have no effect. And the input is likely already compressed, so a quality-factor of the same value as the input would not lead to any size reduction.

It might be possible get a size estimation faster by skipping the output stage of the compressor, or compressing a smaller set of randomly selected blocks from the image. But unless you have such a function available in your compression library, or are comfortable to to write your own, running the compressor iteratively is probably the best solution. Just make sure to use a memory stream until you are satisfied with the size.

JonasH
  • 28,608
  • 2
  • 10
  • 23
0

You can use the system.Drawing.Imaging library to compress the image. This library compresses the image based on quality. You have to create a formula to select this number from 0 to 100 for different sizes. sample code:

    public static void CompressImage(string SoucePath, string DestPath, int quality)
    {

        using (Bitmap bmp1 = new Bitmap(SoucePath))
        {
            ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Jpeg);

            System.Drawing.Imaging.Encoder QualityEncoder = System.Drawing.Imaging.Encoder.Quality;

            EncoderParameters myEncoderParameters = new EncoderParameters(1);

            EncoderParameter myEncoderParameter = new EncoderParameter(QualityEncoder, quality);

            myEncoderParameters.Param[0] = myEncoderParameter;
            bmp1.Save(DestPath, jpgEncoder, myEncoderParameters);

        }
    }

    private static ImageCodecInfo GetEncoder(ImageFormat format)
    {
        ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
        foreach (ImageCodecInfo codec in codecs)
        {
            if (codec.FormatID == format.Guid)
            {
                return codec;
            }
        }
        return null;
    }

Now I pass a 2.5MB image to this function:

CompressImage("N.jpg", "N_compress.jpg", 85);

then the result:

enter image description here

Hossein Sabziani
  • 1
  • 2
  • 15
  • 20