Resize and Save Images with .NET

In this post I will present a service class for resizing and saving an image. The service has one public method, ResizeAndSave() which accepts a stream, a filename and a directory to save the file to. It uses a simple algorithm to rescale the image to fit into a maximum rectangle and then performs the actual resize using System.Drawing, and returns the dimensions of the resized image.

    public class ImageService : IImageService
    {
        private readonly IFileSystem fileSystem;
        private const int LARGEST_WIDTH = 400;
        private const int LARGEST_HEIGHT = 500;

        public ImageService(IFileSystem fileSystem)
        {
            this.fileSystem = fileSystem;
        }

        public Rectangle ResizeAndSave(Stream input, string filename, string toDirectory)
        {
            using (Image image = Image.FromStream(input))
            {
                Rectangle scaledRectangle = (image.Width > LARGEST_WIDTH)
                    ? ScaleByWidth(image.Width, image.Height, LARGEST_WIDTH)
                    : new Rectangle(0, 0, image.Width, image.Height);
                
                if (scaledRectangle.Height > LARGEST_HEIGHT)
                {
                    scaledRectangle = ScaleByHeight(scaledRectangle.Width, scaledRectangle.Height, LARGEST_HEIGHT);
                }

                Bitmap newImage = new Bitmap(scaledRectangle.Width, scaledRectangle.Height, image.PixelFormat);
                Graphics toDrawOn = Graphics.FromImage(newImage);
                toDrawOn.CompositingQuality = CompositingQuality.HighQuality;
                toDrawOn.SmoothingMode = SmoothingMode.HighQuality;
                toDrawOn.InterpolationMode = InterpolationMode.HighQualityBicubic;
                toDrawOn.DrawImage(image, scaledRectangle);
                
                fileSystem.Write(ConvertImageToMemoryStream(newImage).ToArray(), toDirectory, filename);
                newImage.Dispose();
                toDrawOn.Dispose();
                return scaledRectangle;
            }
        }

        private static MemoryStream ConvertImageToMemoryStream(Image image)
        {
            var stream = new MemoryStream();
            image.Save(stream, image.RawFormat);
            return stream;
        }

        private static Rectangle ScaleByWidth(int originalWidth, int originalHeight, int newWidth)
        {
            float scalingFactor = (float)newWidth / (float)originalWidth;
            float newHeight = originalHeight * scalingFactor;
            return new Rectangle(0, 0, newWidth, (int)newHeight);
        }

        private static Rectangle ScaleByHeight(int originalWidth, int originalHeight, int newHeight)
        {
            float scalingFactor = (float)newHeight / (float)originalHeight;
            float newWidth = originalWidth * scalingFactor;
            return new Rectangle(0, 0, (int)newWidth, newHeight);
        }

    }

The actual file writing is delegated to the IFileSystem service, which is implemented like so:

    public class FileSystem : IFileSystem
    {
        public void Write(byte[] data, string directoryPath, string fileName)
        {
            if (!Directory.Exists(directoryPath)) Directory.CreateDirectory(directoryPath);
            File.WriteAllBytes(directoryPath + fileName, data);
        }
    }

 


Comments are closed