Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to crop and resize image in one step in .NET

I have an Image file that I would like to crop and resize at the same time using the System.Drawing class

I am trying to build upon the ideas found in this article :http://www.schnieds.com/2011/07/image-upload-crop-and-resize-with.html

I am able to Crop and Resize seperately but when I try to combine the process, I am getting some strange output.

Here is what I have been trying

using (System.Drawing.Bitmap _bitmap = new System.Drawing.Bitmap(w, h))
{
    _bitmap.SetResolution(img.HorizontalResolution, img.VerticalResolution);
    using (Graphics _graphic = Graphics.FromImage(_bitmap))
    {
        _graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
        _graphic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
        _graphic.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
        _graphic.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;

        //Code used to crop
        _graphic.DrawImage(img, 0, 0, w, h);
        _graphic.DrawImage(img, new Rectangle(0, 0, w, h), x, y, w, h, GraphicsUnit.Pixel);

        //Code I used to resize
        _graphic.DrawImage(img, 0, 0, img.Width, img.Height);
        _graphic.DrawImage(img, new Rectangle(0, 0, W_FixedSize, H_FixedSize), 0, 0, img.Width, img.Height, GraphicsUnit.Pixel);



       //continued...
    }
}

In the above code...there are two sections commented...one to crop and one one to resize.

For cropping, I pass in the proper coords and width/height part of the image to crop(x, y, w, h).

I would like to crop based on my parameters and draw the image based on the W_FixedSize and H_Fixed size params.

like image 830
stephen776 Avatar asked Jan 24 '12 19:01

stephen776


People also ask

How do I crop an image in VB net?

Use Graphics. DrawImage Method (Image, RectangleF, RectangleF, GraphicsUnit) method.


2 Answers

One thing all of the answers missed is that the resulting image will have a 50% transparent 1 pixel border around the image, due to a bug in GDI.

To properly crop and resize, you need to apply the following settings to the graphics object:

        g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
        g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
        g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
        g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;

Then you need to make an ImageAttributes instance to fix the border bug:

ImageAttributes ia = new ImageAttributes();
ia.SetWrapMode(WrapMode.TileFlipXY);

Then, when calling DrawImage, pass ia as the last parameter.

If you're dealing with any PNG, TIFF, or ICO images and converting them to a format that doesn't support transparency, you also need to call g.Clear(bgcolor) prior to calling DrawImage.

If you're encoding to jpeg format, make sure to set the Quality parameter and dispose of the EncoderParameters object afterwards.

The Bitmap instance that you are reading from will lock the underlying file until after it is disposed. If you use the FromStream method, you must keep the stream open until after the Bitmap instance is disposed. A good way to do this is clone the stream into a MemoryStream instance and assign it to the Bitmap.Tag property.

I have a more complete list of GDI+ cropping & resizing bugs to avoid on my blog.

I usually try to push people to use my imageresizing.net library, as it's designed to operate safely on a website with optimum performance. 1 line of code, and very little room for user error.

I downloaded Schnieds' example project, and I have to say it's an (unnecessarily) complicated way of doing things. Non-destructive editing is actually much easier, as shown on this article. It's easy to combine with Uploadify, although I don't cover that on the blog.

Also, re-encoding the image during upload is very destructive, both for jpeg and png files. Validation is good, but just dispose the instance after validation, don't re-encode it. Schnieds' example also leaks memory through the undisposed Bitmap instance - running it on a high-volume server would crash it quickly.

like image 152
Lilith River Avatar answered Oct 22 '22 20:10

Lilith River


I am using this class I wrote:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;

namespace Studio.Utilities
{
    public class ImageResizer
    {
        public void ResizeImage(string origFileLocation, string newFileLocation, string origFileName, string newFileName, int newWidth, int maxHeight, bool resizeIfWider)
        {
            System.Drawing.Image FullSizeImage = System.Drawing.Image.FromFile(origFileLocation + origFileName);
            // Ensure the generated thumbnail is not being used by rotating it 360 degrees
            FullSizeImage.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
            FullSizeImage.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);

            if (resizeIfWider)
            {
                if (FullSizeImage.Width <= newWidth)
                {
                    //newWidth = FullSizeImage.Width;
                }
            }

            int newHeight = FullSizeImage.Height * newWidth / FullSizeImage.Width;
            if (newHeight > maxHeight) // Height resize if necessary
            {
                //newWidth = FullSizeImage.Width * maxHeight / FullSizeImage.Height;
                newHeight = maxHeight;
            }
            newHeight = maxHeight;
            // Create the new image with the sizes we've calculated
            System.Drawing.Image NewImage = FullSizeImage.GetThumbnailImage(newWidth, newHeight, null, IntPtr.Zero);
            FullSizeImage.Dispose();
            NewImage.Save(newFileLocation + newFileName);
        }
        public void ResizeImageAndRatio(string origFileLocation, string newFileLocation, string origFileName, string newFileName, int newWidth, int newHeight, bool resizeIfWider)
        {

            System.Drawing.Image initImage = System.Drawing.Image.FromFile(origFileLocation + origFileName);
            int templateWidth = newWidth;
            int templateHeight = newHeight;
                double templateRate = double.Parse(templateWidth.ToString()) / templateHeight;
                double initRate = double.Parse(initImage.Width.ToString()) / initImage.Height;
                if (templateRate == initRate)
                {

                    System.Drawing.Image templateImage = new System.Drawing.Bitmap(templateWidth, templateHeight);
                    System.Drawing.Graphics templateG = System.Drawing.Graphics.FromImage(templateImage);
                    templateG.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
                    templateG.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                    templateG.Clear(Color.White);
                    templateG.DrawImage(initImage, new System.Drawing.Rectangle(0, 0, templateWidth, templateHeight), new System.Drawing.Rectangle(0, 0, initImage.Width, initImage.Height), System.Drawing.GraphicsUnit.Pixel);
                    templateImage.Save(newFileLocation + newFileName, System.Drawing.Imaging.ImageFormat.Jpeg);
                }

                else
                {

                    System.Drawing.Image pickedImage = null;
                    System.Drawing.Graphics pickedG = null;


                    Rectangle fromR = new Rectangle(0, 0, 0, 0);
                    Rectangle toR = new Rectangle(0, 0, 0, 0);


                    if (templateRate > initRate)
                    {

                        pickedImage = new System.Drawing.Bitmap(initImage.Width, int.Parse(Math.Floor(initImage.Width / templateRate).ToString()));
                        pickedG = System.Drawing.Graphics.FromImage(pickedImage);


                        fromR.X = 0;
                        fromR.Y = int.Parse(Math.Floor((initImage.Height - initImage.Width / templateRate) / 2).ToString());
                        fromR.Width = initImage.Width;
                        fromR.Height = int.Parse(Math.Floor(initImage.Width / templateRate).ToString());


                        toR.X = 0;
                        toR.Y = 0;
                        toR.Width = initImage.Width;
                        toR.Height = int.Parse(Math.Floor(initImage.Width / templateRate).ToString());
                    }

                    else
                    {
                        pickedImage = new System.Drawing.Bitmap(int.Parse(Math.Floor(initImage.Height * templateRate).ToString()), initImage.Height);
                        pickedG = System.Drawing.Graphics.FromImage(pickedImage);

                        fromR.X = int.Parse(Math.Floor((initImage.Width - initImage.Height * templateRate) / 2).ToString());
                        fromR.Y = 0;
                        fromR.Width = int.Parse(Math.Floor(initImage.Height * templateRate).ToString());
                        fromR.Height = initImage.Height;

                        toR.X = 0;
                        toR.Y = 0;
                        toR.Width = int.Parse(Math.Floor(initImage.Height * templateRate).ToString());
                        toR.Height = initImage.Height;
                    }


                    pickedG.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                    pickedG.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;


                    pickedG.DrawImage(initImage, toR, fromR, System.Drawing.GraphicsUnit.Pixel);


                    System.Drawing.Image templateImage = new System.Drawing.Bitmap(templateWidth, templateHeight);
                    System.Drawing.Graphics templateG = System.Drawing.Graphics.FromImage(templateImage);
                    templateG.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
                    templateG.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                    templateG.Clear(Color.White);
                    templateG.DrawImage(pickedImage, new System.Drawing.Rectangle(0, 0, templateWidth, templateHeight), new System.Drawing.Rectangle(0, 0, pickedImage.Width, pickedImage.Height), System.Drawing.GraphicsUnit.Pixel);
                    templateImage.Save(newFileLocation + newFileName, System.Drawing.Imaging.ImageFormat.Jpeg);


                    templateG.Dispose();
                    templateImage.Dispose();

                    pickedG.Dispose();
                    pickedImage.Dispose();
                }
                initImage.Dispose();
            }

    }
}
like image 39
kleinohad Avatar answered Oct 22 '22 21:10

kleinohad