简体   繁体   中英

Optimize image for web (C# & ASP.NET MVC)

I am looking for a way to efficiently prepare large amount of images for website in .NET

Images are often largescale, unedited, 2-5MB 4000x8000px monster images from phone camera.

I would like to generate thumbnails quickly, and as efficient as possible. (not to slow down CPU) or performance for user.

I also have to consider caching.

Modern CMS systems are using Image pre-processor that you can invoke via front-end. So I want to make something like this also, but my own. Cause in my case, I can't use CMS here.

Here is my code: I have a static helper method from Helper class. I call it in razor every time I need to render an image.

public static string GetImgThumbnail(string web_path, int _width = 0, int _height = 0)
{
        //Default parameters
        Image image;
        Image thumbnail;
        string thumb_url = "/img/noimg.png";

        try
        {
            // web_path example input "/images/helloworld.jpg"
            //system_path returns system path of Ogirinal image in the system f.e.: "C:\projects\websites\mysite\images\helloworld.jpg"
            string system_path = HttpContext.Current.Server.MapPath(web_path);
            image = Image.FromFile(system_path);

            //Original image dimensions
            int width = image.Width;
            int height = image.Height;

            //Get New image dimensions
            if(_height == 0)
            {
                if(_width == 0)
                {
                    _width = 700;
                }
                _height = (_width * height) / width;
            }

            if (_width == 0)
            {
                if (_height == 0)
                {
                    _height = 700;
                }
                _width = (_height * width) / height;
            }

            //Generate Thumbnail, passing in new dimensions
            thumbnail = image.GetThumbnailImage(_width, _height, null, IntPtr.Zero);

            //Find out how to call newly created thumbnail.
            //Original image example name = "/images/helloworld.jpg" thumbnail would be "/images/helloworld_thumb_700x250.jpg" or analogical with .png or JPEG etc...
            //Suffix should be "_thumb_{width}x{height}"
            string suffix = string.Format("_thumb_{0}x{1}", _width.ToString(),_height.ToString());

            var bigImgFilename = String.Format("{0}{1}",
                     Path.GetFileNameWithoutExtension(system_path), Path.GetExtension(system_path));

            var newImgFilename = String.Format("{0}{1}{2}",
                     Path.GetFileNameWithoutExtension(system_path), suffix, Path.GetExtension(system_path));

            //New system path of new Thumbnail example: "C:\projects\websites\mysite\images\helloworld_thumb_700x250.jpg"
            var newpath = system_path.Replace(bigImgFilename, newImgFilename);

            //Set new web path, expect this to be: "/images/helloworld_thumb_700x250.jpg"
            thumb_url = web_path.Replace(bigImgFilename, newImgFilename);

            //Check if file exists, no need to overrite if file exists.
            if (!File.Exists(newpath)) 
            { 
                thumbnail.Save(newpath);
            }

        }
        catch (Exception exc)
        {
            // If something goes wrong, just return backup image.
            thumb_url = "/img/noimg.png";
        }

        // return thumbnail 
        return thumb_url;
}

Would love to hear some tips/suggestions or whether I am on the right path, or I should do it in different way?

So in your code, you calculate the thumbnail first. Then you calculate the filename and check if the thumbnail calculation was necessary.

I would do in a different order:

  1. Load the image (since you need that to calculate the new filename)
  2. Calculate the new filename
  3. Check if the file is already there
  4. If the file is already there, use it
  5. If not, generate the thumbnail.

In code this would roughtly look like the following:

public static string GetImgThumbnail(string web_path, int _width = 0, int _height = 0)
{

    [...]
    string system_path = HttpContext.Current.Server.MapPath(web_path);
    image = Image.FromFile(system_path);

    // calculate new width and height
    [...]

    // calculate new filename
    [...]
        //New system path of new Thumbnail example: "C:\projects\websites\mysite\images\helloworld_thumb_700x250.jpg"
        var newpath = system_path.Replace(bigImgFilename, newImgFilename);

        //Set new web path, expect this to be: "/images/helloworld_thumb_700x250.jpg"
        thumb_url = web_path.Replace(bigImgFilename, newImgFilename);

        //Check if file exists, no need to overrite if file exists.
        if (!File.Exists(newpath)) 
        { 
            //Generate Thumbnail, passing in new dimensions
            thumbnail = image.GetThumbnailImage(_width, _height, null, IntPtr.Zero);
            thumbnail.Save(newpath);
        }

My point is: Loading an image and calculating the size dosen't use much resources. The resizing part is a heavy on the CPU. So you will get faster responses, if you only transform the image if necessary.


Here are some points you can consider:

I call it in razor every time I need to render an image.

This will generate a thumbnail on every image view. This is very cpu heavy and most likely not what you want. Consider creating the thumbnail only once, save it to disk and start using the pre-rendered version.

Next issue:

 //Check if file exists, no need to overrite if file exists. if (!File.Exists(newpath)) { thumbnail.Save(newpath); } 

You first compute the thumbnail and then check if the computation has already be done. It should be the other way round.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM