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.
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.
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:
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
Thank you for the contribution. It has been approved.
You can contact us on Discord.
[utopian-moderator]
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit
Hey @babelek I am @utopian-io. I have just upvoted you!
Achievements
Suggestions
Get Noticed!
Community-Driven Witness!
I am the first and only Steem Community-Driven Witness. Participate on Discord. Lets GROW TOGETHER!
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
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit