рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдореИрдВ .NET рдХреЛрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рдЫрд╡рд┐рдпреЛрдВ рдХреЛ рд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рддрдВрддреНрд░ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рдЕрдкрдиреЗ рдЕрдиреБрднрд╡ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ, рдЗрд╕рдХреЗ рдмрд╛рдж рдЙрдирдХреЗ рдЖрдХрд╛рд░ рдФрд░ рдлрд╝рд╛рдЗрд▓ рд╕рд┐рд╕реНрдЯрдо рдореЗрдВ рд╕рд╣реЗрдЬреЗрдВред рдЗрдореЗрдЬ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рд╕рд┐рдХреНрд╕ рд▓реЗрдмрд░реНрд╕ рд╕реЗ рдХреНрд░реЙрд╕-рдкреНрд▓реЗрдЯрдлреЙрд░реНрдо ImageSharp рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ ред рдЫрд╡рд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрдИ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╣реИрдВ, рд▓реЗрдХрд┐рди рдХреНрдпреЛрдВрдХрд┐ рдореИрдВ рдПрдХ рдХреНрд░реЙрд╕-рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╡рд┐рдХрд╕рд┐рдд рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рдореИрдВ рдПрдХ рдХреНрд░реЙрд╕-рдкреНрд▓реЗрдЯрдлреЙрд░реНрдо рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдвреВрдВрдврдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛ред рд▓реЗрдЦрди рдХреЗ рд╕рдордп, рд╡реЗ рдЕрднреА рднреА рд░рд┐рд▓реАрдЬ рдХреЗ рдЙрдореНрдореАрджрд╡рд╛рд░ рдХреЗ рдЪрд░рдг рдореЗрдВ рд╣реИрдВ, рд▓реЗрдХрд┐рди рд╕рдореБрджрд╛рдп рдХрд╛ рдХрд╣рдирд╛ рд╣реИ рдХрд┐ рд╕рдм рдХреБрдЫ рдареАрдХ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдФрд░ рд╕реБрд░рдХреНрд╖рд┐рдд рд░реВрдк рд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИредрдХрд╛рд░реНрдп рд╕рд╛рдордиреЗ рд╕реЗ рдЫрд╡рд┐ рдХреЛ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░рдирд╛ рдерд╛, рдЗрд╕реЗ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдкрд╣рд▓реВ рдЕрдиреБрдкрд╛рдд рдореЗрдВ рдХреНрд░реЙрдк рдХрд░рдирд╛ рдФрд░ рдЖрдХрд╛рд░ рдмрджрд▓рдирд╛ рддрд╛рдХрд┐ рд╕рд╣реЗрдЬреЗ рдЧрдП рдЪрд┐рддреНрд░ рдмрд╣реБрдд рд╕рд╛рд░реЗ рдбрд┐рд╕реНрдХ рд╕реНрдерд╛рди рдирд╣реАрдВ рдЦрд╛рдПрдВ, рдХреНрдпреЛрдВрдХрд┐ рдХреНрд▓рд╛рдЙрдб рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рдореЗрдЧрд╛рдмрд╛рдЗрдЯ рдкреИрд╕рд╛ рд╣реИредрдореЛрд░реНрдЪреЗ рдкрд░, рдПрдХ рдХреЛрдгреАрдп рдШрдЯрдХ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рдЬреЛ рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдХреЗ рддреБрд░рдВрдд рдмрд╛рдж рдЗрд╕реЗ рд╕рд╣реЗрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдкреАрдЖрдИ рд╡рд┐рдзрд┐ рдХреЛ рднреЗрдЬрддрд╛ рд╣реИред рдПрдкреАрдЖрдИ, рдмрджрд▓реЗ рдореЗрдВ, рдкрд╣рд▓реЗ рд╕реЗ рд╕рд╣реЗрдЬреА рдЧрдИ рдЫрд╡рд┐ рдХреЗ рд▓рд┐рдП рдкрде рджреЗрддрд╛ рд╣реИ, рдЬреЛ рддрдм рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рд╕рд╣реЗрдЬрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЪреВрдВрдХрд┐ рдЪреВрдВрдХрд┐ рдпрд╣ рд▓реЗрдЦ рдПрдВрдЧреБрд▓рд░ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдирд╣реАрдВ рд╣реИ, рд╣рдо рдШрдЯрдХ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЛ рдЫреЛрдбрд╝ рджреЗрддреЗ рд╣реИрдВ рдФрд░ рд╕реАрдзреЗ рдПрдкреАрдЖрдИ рд╡рд┐рдзрд┐ рдкрд░ рдЬрд╛рддреЗ рд╣реИрдВред[HttpPost]
[Route("upload/box")]
public IActionResult UploadBoxImage(IFormFile file)
{
return UploadImage(file, ImageType.Box);
}
[HttpPost]
[Route("upload/logo")]
public IActionResult UploadLogoImage(IFormFile file)
{
return UploadImage(file, ImageType.Logo);
}
private IActionResult UploadImage(IFormFile file, ImageType type)
{
if (file.Length == 0)
return BadRequest(new ApiResponse(ErrorCodes.EmptyFile, Strings.EmptyFile));
try
{
var filePath = _imageService.SaveImage(file, type);
return Ok(new ApiResponse<string>(filePath));
}
catch (ImageProcessingException ex)
{
var response = new ApiResponse(ErrorCodes.ImageProcessing, ex.Message);
return BadRequest(response);
}
catch (Exception ex)
{
var response = new ApiResponse(ErrorCodes.Unknown, ex.Message);
return BadRequest(response);
}
}
рдФрд░ рдЕрдзрд┐рдХ рд╕рдЯреАрдХ рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП, рдлрд┐рд░ рджреЛ рддрд░реАрдХреЛрдВ рд╕реЗред рдореЗрд░рд╛ рдХрд╛рдо рджреЛ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдЙрджреНрджреЗрд╢реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рдЫрд╡рд┐рдпрд╛рдВ рдЕрдкрд▓реЛрдб рдХрд░рдирд╛ рдерд╛, рдЬреЛ рд╡рд┐рднрд┐рдиреНрди рдЖрдХрд╛рд░реЛрдВ рдХрд╛ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рд╡рд┐рднрд┐рдиреНрди рд╕реНрдерд╛рдиреЛрдВ рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рдЫрд╡рд┐ рдкреНрд░рдХрд╛рд░ Enum рдореЗрдВ рд╕реВрдЪреАрдмрджреНрдз рд╣реИрдВ ImageType
ред рдФрд░ рдЫрд╡рд┐ рдХреЗ рдкреНрд░рдХрд╛рд░ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ IImageProfile
рдкреНрд░рддреНрдпреЗрдХ рдкреНрд░рдХрд╛рд░ рдХреА рдЫрд╡рд┐ рдХреЗ рд▓рд┐рдП рдПрдХ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдФрд░ рджреЛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдмрдирд╛рдП , рдЬрд┐рд╕рдореЗрдВ рдЗрд╕ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рд╢рд╛рдорд┐рд▓ рд╣реИ рдХрд┐ рдЫрд╡рд┐ рдХреЛ рдХреИрд╕реЗ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПредpublic interface IImageProfile
{
ImageType ImageType { get; }
string Folder { get; }
int Width { get; }
int Height { get; }
int MaxSizeBytes { get; }
IEnumerable<string> AllowedExtensions { get; }
}
public class BoxImageProfile : IImageProfile
{
private const int mb = 1048576;
public BoxImageProfile()
{
AllowedExtensions = new List<string> { ".jpg", ".jpeg", ".png", ".gif" };
}
public ImageType ImageType => ImageType.Box;
public string Folder => "boxes";
public int Width => 500;
public int Height => 500;
public int MaxSizeBytes => 10 * mb;
public IEnumerable<string> AllowedExtensions { get; }
}
public class LogoImageProfile : IImageProfile
{
private const int mb = 1048576;
public LogoImageProfile()
{
AllowedExtensions = new List<string> { ".jpg", ".jpeg", ".png", ".gif" };
}
public ImageType ImageType => ImageType.Logo;
public string Folder => "logos";
public int Width => 300;
public int Height => 300;
public int MaxSizeBytes => 5 * mb;
public IEnumerable<string> AllowedExtensions { get; }
}
рдЕрдЧрд▓рд╛, рдореИрдВ рдЗрди рдЫрд╡рд┐ рдкреНрд░реЛрдлрд╛рдЗрд▓ рдХреЛ рд╕реЗрд╡рд╛ рдкрджреНрдзрддрд┐ рдореЗрдВ рдЗрдВрдЬреЗрдХреНрдЯ рдХрд░реВрдВрдЧрд╛, рдЗрд╕рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рдЙрдиреНрд╣реЗрдВ рдбреАрдЖрдИ рдХрдВрдЯреЗрдирд░ рдореЗрдВ рдкрдВрдЬреАрдХреГрдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред...
services.AddTransient<IImageProfile, BoxImageProfile>();
services.AddTransient<IImageProfile, LogoImageProfile>();
...
рдЙрд╕рдХреЗ рдмрд╛рдж, рдЖрдк рдПрдХ рд╕рдВрдЧреНрд░рд╣ рдХреЛ рдирд┐рдпрдВрддреНрд░рдХ рдпрд╛ рд╕реЗрд╡рд╛ рдореЗрдВ рдЗрдВрдЬреЗрдХреНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ IImageProfile
...
private readonly IEnumerable<IImageProfile> _imageProfiles;
public ImageService(IEnumerable<IImageProfile> imageProfiles)
{
...
_imageProfiles = imageProfiles;
}
рдЕрдм рд╣рдо рд╕реЗрд╡рд╛ рдкрджреНрдзрддрд┐ рдХреЛ рджреЗрдЦрддреЗ рд╣реИрдВ, рдЬрд╣рд╛рдВ рд╣рдо рдпрд╣ рд╕рдм рдкреНрд░рдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред рдЖрдкрдХреЛ рдпрд╛рдж рджрд┐рд▓рд╛ рджреВрдВ рдХрд┐ рдЗрдореЗрдЬ рдкреНрд░реЛрд╕реЗрд╕рд┐рдВрдЧ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛ ImageSharp
, рдЬреЛ рдиреБрдЧреЗрдЯ рдореЗрдВ рдорд┐рд▓ рд╕рдХрддреА рд╣реИред рдЕрдЧрд▓реА рд╡рд┐рдзрд┐ рдореЗрдВ, рдореИрдВ Image
рдЫрд╡рд┐ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд░рдХрд╛рд░ рдФрд░ рдЙрд╕рдХреЗ рддрд░реАрдХреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реВрдБрдЧрд╛ ред рд╡рд┐рд╕реНрддреГрдд рдкреНрд░рд▓реЗрдЦрди рдпрд╣рд╛рдБ рдкрдврд╝рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИредpublic string SaveImage(IFormFile file, ImageType imageType)
{
var imageProfile = _imageProfiles.FirstOrDefault(profile =>
profile.ImageType == imageType);
if (imageProfile == null)
throw new ImageProcessingException("Image profile has not found");
ValidateExtension(file, imageProfile);
ValidateFileSize(file, imageProfile);
var image = Image.Load(file.OpenReadStream());
ValidateImageSize(image, imageProfile);
var folderPath = Path.Combine(_hostingEnvironment.WebRootPath, imageProfile.Folder);
if (!Directory.Exists(folderPath))
Directory.CreateDirectory(folderPath);
string filePath;
string fileName;
do
{
fileName = GenerateFileName(file);
filePath = Path.Combine(folderPath, fileName);
} while (File.Exists(filePath));
Resize(image, imageProfile);
Crop(image, imageProfile);
image.Save(filePath, new JpegEncoder { Quality = 75 });
return Path.Combine(imageProfile.Folder, fileName);
}
рдФрд░ рдХреБрдЫ рдирд┐рдЬреА рддрд░реАрдХреЗ рдЬреЛ рдЗрд╕реЗ рдкрд░реЛрд╕рддреЗ рд╣реИрдВprivate void ValidateExtension(IFormFile file, IImageProfile imageProfile)
{
var fileExtension = Path.GetExtension(file.FileName);
if (imageProfile.AllowedExtensions.Any(ext => ext == fileExtension.ToLower()))
return;
throw new ImageProcessingException(Strings.WrongImageFormat);
}
private void ValidateFileSize(IFormFile file, IImageProfile imageProfile)
{
if (file.Length > imageProfile.MaxSizeBytes)
throw new ImageProcessingException(Strings.ImageTooLarge);
}
private void ValidateImageSize(Image image, IImageProfile imageProfile)
{
if (image.Width < imageProfile.Width || image.Height < imageProfile.Height)
throw new ImageProcessingException(Strings.ImageTooSmall);
}
private string GenerateFileName(IFormFile file)
{
var fileExtension = Path.GetExtension(file.FileName);
var fileName = Path.GetFileNameWithoutExtension(Path.GetRandomFileName());
return $"{fileName}{fileExtension}";
}
private void Resize(Image image, IImageProfile imageProfile)
{
var resizeOptions = new ResizeOptions
{
Mode = ResizeMode.Min,
Size = new Size(imageProfile.Width)
};
image.Mutate(action => action.Resize(resizeOptions));
}
private void Crop(Image image, IImageProfile imageProfile)
{
var rectangle = GetCropRectangle(image, imageProfile);
image.Mutate(action => action.Crop(rectangle));
}
private Rectangle GetCropRectangle(IImageInfo image, IImageProfile imageProfile)
{
var widthDifference = image.Width - imageProfile.Width;
var heightDifference = image.Height - imageProfile.Height;
var x = widthDifference / 2;
var y = heightDifference / 2;
return new Rectangle(x, y, imageProfile.Width, imageProfile.Height);
}
рд╡рд┐рдзрд┐ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреБрдЫ рд╢рдмреНрдж Resize
ред рдореЗрдВ ResizeOptions
рдореИрдВ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛ ResizeMode.Min
, рдЗрд╕ рдореЛрдб рдЬрдм рдЫрд╡рд┐ рдЫрд╡рд┐ рдХреЗ рдЫреЛрдЯреЗ рдкрдХреНрд╖ рдХреА рдЗрдЪреНрдЫрд┐рдд рд▓рдВрдмрд╛рдИ рддрдХ рдХрд╛ рдЖрдХрд╛рд░ рдмрджрд▓рдиреЗ рдкрд░ рдкрд╣реБрдБрдЪ рдЬрд╛рддрд╛ рд╣реИ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рдореВрд▓ рдЫрд╡рд┐ 1000x2000 рд╣реИ, рдФрд░ рдореЗрд░рд╛ рд▓рдХреНрд╖реНрдп 500x500 рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рд╣реИ, рддреЛ рдЖрдХрд╛рд░ рдмрджрд▓рдиреЗ рдХреЗ рдмрд╛рдж рдпрд╣ 500x1000 рд╣реЛ рдЬрд╛рдПрдЧрд╛, рдлрд┐рд░ рдЗрд╕реЗ 500x500 рдкрд░ рдХреНрд░реЙрдк рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдмрдЪрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИредрдпрд╣ рдПрдХ рдХреНрд╖рдг рдХреЛ рдЫреЛрдбрд╝рдХрд░ рд▓рдЧрднрдЧ рд╕рдм рдХреБрдЫ рд╣реИред рд╕реЗрд╡рд╛ рдкрджреНрдзрддрд┐ рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдкрде рд╡рд╛рдкрд╕ рдХрд░ рджреЗрдЧреА, рд▓реЗрдХрд┐рди рдпрд╣ URL рдирд╣реАрдВ рд╣реЛрдЧрд╛, рдмрд▓реНрдХрд┐ рдПрдХ PATH рд╣реЛрдЧрд╛ рдФрд░ рдпрд╣ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦреЗрдЧрд╛:logos\\yourFile.jpg
ред рдпрджрд┐ рдЖрдк рдЗрд╕ PATH рдХреЛ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдХреЛ рдЦрд┐рд▓рд╛рддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рд╕рдлрд▓рддрд╛рдкреВрд░реНрд╡рдХ рдЗрд╕рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдПрдЧрд╛ рдФрд░ рдЖрдкрдХреЛ рдЫрд╡рд┐ рджрд┐рдЦрд╛рдПрдЧрд╛, рд▓реЗрдХрд┐рди рдпрджрд┐ рдЖрдк рдЗрд╕реЗ рджреВрд░ рдХрд░рддреЗ рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдореЛрдмрд╛рдЗрд▓ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдкрд░, рддреЛ рдЖрдкрдХреЛ рдЫрд╡рд┐ рджрд┐рдЦрд╛рдИ рдирд╣реАрдВ рджреЗрдЧреАред рдЗрд╕рдХреЗ рдмрд╛рд╡рдЬреВрдж, рдореИрдВрдиреЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ PATH рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛, рддрд╛рдХрд┐ рдпрджрд┐ рдЖрд╡рд╢реНрдпрдХ рд╣реЛ рддреЛ рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛ, рдФрд░ рдбреАрдЯреАрдУ рдореЗрдВ, рдЬреЛ рд╕рд╛рдордиреЗ рдХреА рдУрд░ рдЙрдбрд╝рддрд╛ рд╣реИ, рдореИрдВ рдЗрд╕реЗ URL рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рдХреЗ рдЗрд╕ рдлрд╝реАрд▓реНрдб рдХреЛ рдореИрдк рдХрд░рддрд╛ рд╣реВрдВред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореБрдЭреЗ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдПрдХреНрд╕рдЯреЗрдВрд╢рди рд╡рд┐рдзрд┐ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИpublic static string PathToUrl(this string path)
{
return path?.Replace("\\", "/");
}
рдЖрдкрдХрд╛ рдзреНрдпрд╛рди рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж, рд╕реНрд╡рдЪреНрдЫ рдХреЛрдб рд▓рд┐рдЦреЗрдВ рдФрд░ рдмреАрдорд╛рд░ рди рд╣реЛрдВ!