DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Coding
  3. Frameworks
  4. UPDATE: Dynamically Resizing Your ASP.NET MVC Images

UPDATE: Dynamically Resizing Your ASP.NET MVC Images

A while back, I used a technique for dynamically resizing images. Today, I fix an issue my readers found when loading the main page.

Jonathan Danylko user avatar by
Jonathan Danylko
·
Mar. 12, 18 · Tutorial
Like (2)
Save
Tweet
Share
15.70K Views

Join the DZone community and get the full member experience.

Join For Free

Back in 2016, I wrote a post about dynamically resizing your ASP.NET MVC images.

I thought this was a great way to save storage with a hosting company. Resize the original image, send it back to the browser, and call it a day.

However, there was an issue with the code.

When rendering the home page, images wouldn't display on the screen. It simply displayed a blank spot. Not even a partial image would appear.

Hmm...not cool.

While looking through the Chrome Dev Tools, I examined the Network tab and found out the images would return an HTTP status of 200, but with only a content size of zero.

THAT would explain the empty images.

There were a couple of thoughts running through my head:

  1. I was using an old class for loading an image (WebImage). Could this have an effect on the blanks images? After reading through the description, I found out the class isn't thread-safe.
  2. Was I doing too much with the WebImage class where it couldn't keep up with the processing of each image as requested?

Maybe I analyzed it too much back in 2016 and needed a simple approach.

Time to Refactor!

A Simpler Approach

I needed to take a step back and look at this a different way.

  • ImageResult should be easier to use.
  • Instead of using the WebImage, I thought I'd use the Image class (from System.Drawing, not System.Windows.Controls).
  • The Controller should be smaller instead of what we had previously.

So let's focus on the ImageResult first.

ActionResults\ImageResult.cs
public class ImageResult : ActionResult
{
    private readonly Image _image;

    public ImageResult(Image image)
    {
        _image = image;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        HttpResponseBase response = context.HttpContext.Response;
        response.ContentType = "image/jpeg";
        try
        {
            _image.Save(response.OutputStream, ImageFormat.Jpeg);
        }
        finally
        {
            _image.Dispose();
        }
    }
}

For my needs, I need the picture on the main page to be a JPG so I save the image to the OutputStream as a JPG.

Compare this to our previous version and it's definitely easier on the eyes.

Image Manipulation Extension Methods

How's that for a mouthful?

Basically, we need something to constrain either the width or height when resizing the image.

If we want to constrain the image to a certain height or width, we need a way to shrink it to the appropriate size without the image looking squished.

public static class ImageExtensions
{
    public static Image BestFit(this Image image, int height, int width)
    {
        return image.Height > image.Width
            ? image.ConstrainProportions(height, Dimensions.Height)
            : image.ConstrainProportions(width, Dimensions.Width);
    }

    public static Image ConstrainProportions(this Image imgPhoto, int size, Dimensions dimension)
    {
        var sourceWidth = imgPhoto.Width;
        var sourceHeight = imgPhoto.Height;
        var sourceX = 0;
        var sourceY = 0;
        var destX = 0;
        var destY = 0;
        float nPercent;

        switch (dimension)
        {
            case Dimensions.Width:
                nPercent = (float) size / (float) sourceWidth;
                break;
            default:
                nPercent = (float) size / (float) sourceHeight;
                break;
        }

        int destWidth = (int) (sourceWidth * nPercent);
        int destHeight = (int) (sourceHeight * nPercent);

        Bitmap bmPhoto = new Bitmap(destWidth, destHeight, PixelFormat.Format24bppRgb);
        bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);

        Graphics grPhoto = Graphics.FromImage(bmPhoto);
        grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;

        try
        {
            grPhoto.DrawImage(imgPhoto,
                new Rectangle(destX, destY, destWidth, destHeight),
                new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
                GraphicsUnit.Pixel
            );
        }
        finally
        {
            grPhoto.Dispose();
        }

        return bmPhoto;
    }
}

It doesn't matter if we use width or height, we still need a percentage to shrink the image down to our specifications.

Once we have our dimensions, we can copy the image into a new image for the browser.

The Final Touch

The only thing remaining is the controller.

Since we don't want to change our HTML, we'll keep the Thumbnail signature the same and update the implementation details with our new ImageResult.

[ETag, OutputCache(Duration = 3600, VaryByParam = "filename")]
public ActionResult Thumbnail(string filename)
{
    var partialName = $"~{new Uri(filename).PathAndQuery}";

    using (Image image = Image.FromFile(Server.MapPath(partialName)))
    {
        return new ImageResult(image.BestFit(291, 285));
    }
}

With this change in place, the Image class seems to be a better alternative than the WebImage.

In addition to fixing this issue, I now have the start of an image manipulation extension library.

Conclusion

First, thanks go out to my readers for letting me know about this issue. Letting me know about issues like this makes it a win-win for everyone. I (try to) fix the issue and let my audience know about it so they can benefit from the solution as well.

Second, after about a week in "production," this technique seems to fix my issue with blank images.

Finally, this brings me to a couple of questions for my readers:

  • How could you make a unit test for this scenario?
  • Would you use the Parallel library for testing the Controller action?

I understand this would be considered more of an integration test, but, if done properly, it would tell me whether the images were generated and returned correctly.

Thoughts?

Do you manipulate images on the fly? Is this a similar approach? Post your comments below and let's discuss.
ASP.NET MVC ASP.NET

Published at DZone with permission of Jonathan Danylko, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • When AI Strengthens Good Old Chatbots: A Brief History of Conversational AI
  • Handling Automatic ID Generation in PostgreSQL With Node.js and Sequelize
  • A Guide To Successful DevOps in Web3
  • Explainer: Building High Performing Data Product Platform

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: