How to save image on the serwer using ASP.NET Core 2.0

in #utopian-io7 years ago (edited)

What Will I Learn?

  • You will learn how to correctly save image on the server using ASP.NET Core. I will show You how to save original image and his smaller copy. I will use avatar and thumbnail as example. What is more this tutorial will show you how to save image made directly from smartphone, set him correctly position and save, resize and delete old.

Requirements

  • C#
  • ASP.NET
  • Visual Studio 2015+/Visual Studio Core

Difficulty

  • Intermediate

Tutorial Contents

At the beginning we have to create new project. I will create new ASP.NET Core 2.0 Web API project. I will show you how do it using Visual Studio 2017.
project_1.JPG

project_2.JPG

In the new project I will create new folder with one class. It will be ImageService class, in this class we will define the whole logic for image management.

image.png

In this service we have main function witch is: SaveImage. This function is define in this way:

public async Task<string> SaveImage(User user, Stream imageStream)
        {
            if (imageStream == null || imageStream.Length == 0)
            {
                throw new ServiceException(ServiceErrorCodes.InvalidPhoto, "There is no photo.");
            }

            if (imageStream.Length > 5120000)
            {
                throw new ServiceException(ServiceErrorCodes.InvalidPhoto, "Photo cannot be bigger than 5120000 bytes.");
            }

            string[] photos;

            try
            {
                photos = SetThumbnails(imageStream);
            }
            catch (ArgumentException)
            {
                throw new ServiceException(ServiceErrorCodes.InvalidPhoto, "Invalid file format.");
            }

            if (photos != null)
            {
                bool userHasThumbnail = user.WebThumbnail != null;
                var oldPhoto = user.WebThumbnail;
                var oldThumbnail = user.Thumbnail;
                if (userHasThumbnail)
                {
                    DeletePhotoIfExist(oldPhoto);
                    DeletePhotoIfExist(oldThumbnail);
                }
            }
            return user.Thumbnail;
        }

As parameters take image as stream and user. User because we will save this image as his avatar.
At the beginning we have to check if stream i null or has no length, then if the image is too big.

In this function we have few more functions, the first one, and the most important is "SetThumbnails()"

 public string[] SetThumbnails(Stream imageStream)
        {
            var originalImage = Image.FromStream(imageStream);

            if (!ValidateImageFormat(originalImage))
            {
                throw new ArgumentException();
            }

            SetCorrectOrientation(originalImage);

            var photoId = Guid.NewGuid().ToString();

            var mobileThumbnail = $"Content/Photos/Users/Thumbnails/500/{photoId}.jpg";
            var webThumbnail = $"Content/Photos/Users/Thumbnails/100/{photoId}.jpg";
            CreateAndSaveThumbnail(originalImage, 500, mobileThumbnail);
            CreateAndSaveThumbnail(originalImage, 100, webThumbnail);
            originalImage.Dispose();

            return new[] { webThumbnail, mobileThumbnail };
        }

As I said earlier we will validate our image if he has correctly format and right position.

Validation image format:

 private static bool ValidateImageFormat(Image image)
        {
            if (ImageFormat.Jpeg.Equals(image.RawFormat))
            {
                return true;
            }
            if (ImageFormat.Png.Equals(image.RawFormat))
            {
                return true;
            }
            if (ImageFormat.Gif.Equals(image.RawFormat))
            {
                return true;
            }
            if (ImageFormat.Bmp.Equals(image.RawFormat))
            {
                return true;
            }
            return false;
        }

Now we have to set correct image orientation, I'm using this function because photos made by samsung and directly save on the server are rotate about 90 degrees, I don't want to display photos like this, so I rotate them.

private static void SetCorrectOrientation(Image image)
        {
            //property id = 274 describe EXIF orientation parameter
            if (Array.IndexOf(image.PropertyIdList, 274) > -1)
            {
                var orientation = (int)image.GetPropertyItem(274).Value[0];
                switch (orientation)
                {
                    case 1:
                        // No rotation required.
                        break;
                    case 2:
                        image.RotateFlip(RotateFlipType.RotateNoneFlipX);
                        break;
                    case 3:
                        image.RotateFlip(RotateFlipType.Rotate180FlipNone);
                        break;
                    case 4:
                        image.RotateFlip(RotateFlipType.Rotate180FlipX);
                        break;
                    case 5:
                        image.RotateFlip(RotateFlipType.Rotate90FlipX);
                        break;
                    case 6:
                        image.RotateFlip(RotateFlipType.Rotate90FlipNone);
                        break;
                    case 7:
                        image.RotateFlip(RotateFlipType.Rotate270FlipX);
                        break;
                    case 8:
                        image.RotateFlip(RotateFlipType.Rotate270FlipNone);
                        break;
                }
                // This EXIF data is now invalid and should be removed.
                image.RemovePropertyItem(274);
            }
        }

If we have correctly oriented photo we can save it.

private void CreateAndSaveThumbnail(Image image, int size, string thumbnailPath)
        {
            var thumbnailSize = GetThumbnailSize(image, size);

            using (var bitmap = ResizeImage(image, thumbnailSize.Width, thumbnailSize.Height))
            {
                bitmap.Save(_serverPath.ServerPath + thumbnailPath, ImageFormat.Jpeg);
            }
        }

We will save original and one smaller photo, so we have to resize it:

private static Size GetThumbnailSize(Image original, int size = 500)
        {
            var originalWidth = original.Width;
            var originalHeight = original.Height;

            double factor;
            if (originalWidth > originalHeight)
            {
                factor = (double)size / originalWidth;
            }
            else
            {
                factor = (double)size / originalHeight;
            }

            return new Size((int)(originalWidth * factor), (int)(originalHeight * factor));
        }
private Bitmap ResizeImage(Image image, int width, int height)
        {
            var result = new Bitmap(width, height);

            using (var graphics = Graphics.FromImage(result))
            {
                graphics.CompositingQuality = CompositingQuality.HighQuality;
                graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                graphics.SmoothingMode = SmoothingMode.HighQuality;

                graphics.DrawImage(image, 0, 0, result.Width, result.Height);
            }

            return result;
        }

Now we have complete logic for saving images, at the end I will show you how to delete photos from server:

        public void DeletePhotoIfExist(string photoPath)
        {
            if (photoPath == null) 
                throw new ArgumentNullException(nameof(photoPath));

            if (File.Exists(Path.Combine(_serverPath.ServerPath, photoPath)))
            {
                File.Delete(Path.Combine(_serverPath.ServerPath, photoPath));
            }
        }

This are all functions what ImageServis consist. If we want to save photo we have to create new Controller. I will name it ImageController:

image.png

public class ImageController1 : Controller
    {
        private readonly ImageService _imageService;

        public ImageController1(ImageService imageService)
        {
            _imageService = imageService;
        }

        [HttpPost]
        [Route("image")]
        public async Task<IActionResult> SaveImage(User user, IFormFile image)
        {
            var filePath = Path.GetTempFileName();

            using (var stream = new FileStream(filePath, FileMode.Create))
            {
                await image.CopyToAsync(stream);
                var avatar = _imageService.SaveImage(user, stream);
            }

            return Ok();
        }
    }

Controller has injected imageService using Dependency Injection. The Post method i taking as parametr IFormatFile, which is new interface from ASP.NET Core.

This is the end, now You know how to correctly save image using ASP.NET Core 2.0.

Curriculum



Posted on Utopian.io - Rewarding Open Source Contributors

Sort:  

Thank you for the contribution. It has been approved.

You can contact us on Discord.
[utopian-moderator]

Hey @babelek I am @utopian-io. I have just upvoted you!

Achievements

  • You have less than 500 followers. Just gave you a gift to help you succeed!
  • Seems like you contribute quite often. AMAZING!

Suggestions

  • Contribute more often to get higher and higher rewards. I wish to see you often!
  • Work on your followers to increase the votes/rewards. I follow what humans do and my vote is mainly based on that. Good luck!

Get Noticed!

  • Did you know project owners can manually vote with their own voting power or by voting power delegated to their projects? Ask the project owner to review your contributions!

Community-Driven Witness!

I am the first and only Steem Community-Driven Witness. Participate on Discord. Lets GROW TOGETHER!

mooncryption-utopian-witness-gif

Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x