Link to home
Start Free TrialLog in
Avatar of canuckconsulting
canuckconsultingFlag for United Kingdom of Great Britain and Northern Ireland

asked on

Determine size of image in memory

I have a .Net 4 Windows Forms project created with Visual Studio 2010 using c#.

I need to open an image file (jpg or gif) and resize the dimensions to a fixed size and then adjust the quality of the image until the image size is 30kb or less. Is there a way to calculate the memory used by this image while in memory?  I don't want the overhead of saving it to disk to check System.IO.FileInfo.  I would be happy to use a free library or utility which would help.

Scott
Avatar of Carlos Villegas
Carlos Villegas
Flag of United States of America image

Hello, I know how to do that for jpg files, but for gif files... I think that is more complex because to control the quality (therefore the file size) you need to play with the color palette... the next code can help you to control the size of your jpg files:
private void TestExample()
{
    ResizeImage(@"C:\Temp\MyOriginalImage.jpg", @"C:\Temp\MyResizedImage.jpg", 640, 30000);
}

private void ResizeImage(string imageFilePath, string imageFilePathOutput, int newWidth, int maxImageFileSize)
{
    using (Image myImage = Image.FromFile(imageFilePath))
    {
        Size newSize = myImage.Size;
        if (newSize.Width > newWidth)
            newSize = Resize(newSize, newWidth);

        using (Image myResizedImage = new Bitmap(myImage, newSize))
        {
            EncoderParameters eps = null;
            ImageCodecInfo ici = null;
            string fileExt = System.IO.Path.GetExtension(imageFilePath).ToLower();
            switch (fileExt)
            {
                case ".jpg":
                    eps = new System.Drawing.Imaging.EncoderParameters(1);
                    ici = GetEncoderInfo(ImageFormat.Jpeg);
                    break;
                default:
                    throw new NotImplementedException("Image format not supported");
            }

            // Starting quality
            long qualityValue = 90;
            long lastSize = 0;
            while (true)
            {
                eps.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qualityValue);

                using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
                {
                    myResizedImage.Save(ms, ici, eps);

                    if (ms.Length <= maxImageFileSize || (lastSize > 0 && lastSize <= ms.Length))
                    {
                        // Write new image file.
                        System.IO.File.WriteAllBytes(imageFilePathOutput, ms.ToArray());
                        return;
                    }
                    lastSize = ms.Length;
                }

                // Decrease quality
                qualityValue -= 5;
            }
        }
    }
}

private static Size Resize(Size size, int newWidth)
{
    float factor = (float)size.Height / size.Width;
    return new Size(newWidth, Convert.ToInt32(newWidth * factor));
}

private static ImageCodecInfo GetEncoderInfo(ImageFormat format)
{
    return ImageCodecInfo.GetImageEncoders().FirstOrDefault(x => x.FormatID == format.Guid);
}

Open in new window

I forgot to mention that you will require these namespaces:
 System.Drawing
 System.Drawing.Imaging
Avatar of canuckconsulting

ASKER

This is perfect; thanks!  Can you advis if it is possible to convert the contents of ms back into an Image?  I would like the method to return the reduced image which will be saved later on?
ASKER CERTIFIED SOLUTION
Avatar of Carlos Villegas
Carlos Villegas
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Perfect...thank you!
Glad to help!