Created
March 18, 2021 14:51
-
-
Save antonfirsov/765dc11a8f83a786bdcd0f453e534004 to your computer and use it in GitHub Desktop.
ImageSharp-1577-Repro
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static void TransformImage(ImageEditModel imageEdit, MemoryStream destinationStream) | |
{ | |
if (destinationStream == null) | |
{ | |
throw new ArgumentNullException(nameof(destinationStream)); | |
} | |
var sourceImage = Image.Load(imageEdit.SourceStream); | |
var blur = imageEdit.History.Where(h => h.Tool == ImageTool.Blur).FirstOrDefault(); | |
bool filtersOnly = imageEdit.Tool == ImageTool.Overwrite; | |
// Undo is first | |
if (imageEdit.IsUndo && imageEdit.History.Count > 0) | |
{ | |
// Remove last entered history item | |
imageEdit.History.RemoveAt(imageEdit.History.Count - 1); | |
} | |
//lets do all of the cropping and blur | |
//put in a for each because we have to step through them all. | |
//Only if there are any | |
if (!filtersOnly) | |
{ | |
foreach (var item in imageEdit.History.Where(h => h.Tool == ImageTool.Blur || h.Tool == ImageTool.Zoom)) | |
{ | |
sourceImage = ApplyTool(sourceImage, item.StartRect(), item.CropRect(), item.Tool); | |
} | |
} | |
Rectangle startRect = new Rectangle(0, 0, imageEdit.DispWidth, imageEdit.DispHeight); | |
if (imageEdit.IsUndo && imageEdit.History.Any()) | |
{ | |
// Resize image to fix canvas before applying filters | |
sourceImage.Mutate(x => x.Resize(startRect.Width, startRect.Height)); | |
// Rollback image edit values and apply previous filters | |
var item = imageEdit.History.Last(); | |
imageEdit.Brightness = item.Brightness; | |
imageEdit.Contrast = item.Contrast; | |
imageEdit.Hue = item.Hue; | |
imageEdit.Sharpen = item.Sharpen; | |
imageEdit.CropHeight = item.CropRect().Height; | |
imageEdit.CropStartX = item.CropRect().X; | |
imageEdit.CropStartY = item.CropRect().Y; | |
imageEdit.CropWidth = item.CropRect().Width; | |
imageEdit.IsPrimaryImage = item.isPrimary; | |
double ratioHeight = (double)sourceImage.Height / startRect.Height; | |
sourceImage = ApplyFilter(sourceImage, imageEdit.Tool, imageEdit.Brightness, imageEdit.Contrast, imageEdit.Hue, imageEdit.Sharpen,imageEdit.IsPrimaryImage,ratioHeight); | |
} | |
else if (imageEdit.Tool != 0) | |
{ | |
Rectangle cropRect = new Rectangle(imageEdit.CropStartX, imageEdit.CropStartY, imageEdit.CropWidth, imageEdit.CropHeight); | |
if (!filtersOnly) | |
{ | |
sourceImage = ApplyTransformImage(sourceImage, startRect, cropRect, imageEdit.Tool, | |
imageEdit.Brightness, imageEdit.Contrast, imageEdit.Hue, imageEdit.Sharpen,false,imageEdit.IsPrimaryImage); | |
} | |
else if(filtersOnly && blur != null) | |
{ | |
Rectangle zoomRect = new Rectangle(sourceImage.Bounds().X,sourceImage.Bounds().Y, | |
sourceImage.Bounds().Width,sourceImage.Bounds().Height); | |
var imageEditList = imageEdit.History.Where(h => h.Tool == ImageTool.Blur || h.Tool == ImageTool.Zoom).ToList(); | |
foreach (var item in imageEditList) | |
{ | |
if (item.Tool.Equals(ImageTool.Zoom)) | |
{ | |
Rectangle sourceRec = zoomRect; | |
//get the ratios | |
double ratioWidth = (double)sourceRec.Width / item.StartRect().Width; | |
double ratioHeight = (double)sourceRec.Height / item.StartRect().Height; | |
//Have to shift left on the selection a bit based on ratio. | |
int leftShift = 15 * (int)Math.Round((decimal)ratioWidth, 0); | |
//lets get the projection | |
zoomRect.X += (int)Math.Round((double)(item.CropRect().X * ratioWidth) - leftShift, 0); | |
zoomRect.Y += (int)Math.Round((double)(item.CropRect().Y * ratioHeight), 0); | |
zoomRect.Width = (int)Math.Round((double)(item.CropRect().Width * ratioWidth), 0); | |
zoomRect.Height = (int)Math.Round((double)(item.CropRect().Height * ratioHeight), 0); | |
} | |
else | |
{ | |
Rectangle sourceRec = sourceImage.Bounds(); | |
Rectangle zoomRectangle = zoomRect; | |
//get the ratios | |
double ratioWidth = (double)zoomRectangle.Width / item.StartRect().Width; | |
double ratioHeight = (double)zoomRectangle.Height / item.StartRect().Height; | |
//Have to shift left on the selection a bit based on ratio. | |
int leftShift = 15 * (int)Math.Round((decimal)ratioWidth, 0); | |
//lets get the projection | |
sourceRec.X = zoomRectangle.X + (int)Math.Round((double)(item.CropRect().X * ratioWidth) - leftShift, 0); | |
sourceRec.Y = zoomRectangle.Y + (int)Math.Round((double)(item.CropRect().Y * ratioHeight), 0); | |
sourceRec.Width = (int)Math.Round((double)(item.CropRect().Width * ratioWidth), 0); | |
sourceRec.Height = (int)Math.Round((double)(item.CropRect().Height * ratioHeight), 0); | |
sourceImage.Mutate(x => x.GaussianBlur((float)50.5, sourceRec)); | |
} | |
} | |
sourceImage = ApplyFilter(sourceImage, imageEdit.Tool, imageEdit.Brightness, imageEdit.Contrast, imageEdit.Hue, imageEdit.Sharpen, imageEdit.IsPrimaryImage, 0.0); | |
} | |
else | |
{ | |
// On overwrite, no resize | |
sourceImage = ApplyFilter(sourceImage, imageEdit.Tool, imageEdit.Brightness, imageEdit.Contrast, imageEdit.Hue, imageEdit.Sharpen, imageEdit.IsPrimaryImage, 0.0); | |
} | |
if (imageEdit.Tool != ImageTool.Overwrite && imageEdit.Tool != ImageTool.Face && | |
imageEdit.Tool != ImageTool.Plate && imageEdit.Tool != ImageTool.Make) | |
{ | |
ImageHistoryModel icm = new ImageHistoryModel | |
{ | |
cropRect = CleanRectangle(cropRect), | |
startRect = CleanRectangle(startRect), | |
Brightness = imageEdit.Brightness, | |
Contrast = imageEdit.Contrast, | |
Hue = imageEdit.Hue, | |
Tool = imageEdit.Tool, | |
Sharpen = imageEdit.Sharpen, | |
isPrimary = imageEdit.IsPrimaryImage | |
}; | |
imageEdit.History.Add(icm); | |
} | |
} | |
else | |
{ | |
// Resize image to fix canvas before sending back unalter image | |
sourceImage.Mutate(x => x.Resize(startRect.Width, startRect.Height)); | |
} | |
sourceImage.SaveAsJpeg(destinationStream); | |
destinationStream.Seek(0, SeekOrigin.Begin); | |
imageEdit.SourceStream.Dispose(); | |
imageEdit.SourceStream = null; | |
sourceImage.Dispose(); | |
sourceImage = null; | |
if (!imageEdit.IsSave) | |
{ | |
// Reset Tool for next edit | |
imageEdit.Tool = 0; | |
} | |
} | |
private static Image<Rgba32> ApplyTransformImage(Image<Rgba32> sourceImage, Rectangle startRect, Rectangle cropRect, ImageTool tool, int bright, int cont, int hue, int sharp, bool isHistory = false,bool isPrimary = false) | |
{ | |
if (tool == ImageTool.Blur || tool == ImageTool.Zoom) | |
{ | |
sourceImage = ApplyTool(sourceImage, startRect, cropRect, tool); | |
} | |
if (!isHistory) | |
{ | |
// Resize image to fix canvas before applying filters | |
//Required because the Zoom tool will change the size of the image if it is not bigger than the canvas. | |
if (startRect.Height <= 400) startRect.Height = 400; | |
if (startRect.Width <= 600) startRect.Width = 600; | |
//used for the transform | |
double ratioHeight = (double)sourceImage.Height / startRect.Height; | |
sourceImage.Mutate(x => x.Resize(startRect.Width, startRect.Height)); | |
sourceImage = ApplyFilter(sourceImage, tool, bright, cont, hue, sharp, isPrimary, ratioHeight); | |
} | |
return sourceImage; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[HttpPost("api/[controller]/{contractId}/imageedit")] | |
public async Task<IActionResult> ImageEdit([FromBody] ImageEditModel model) | |
{ | |
if (model.Id == Guid.Empty) | |
{ | |
throw new ArgumentException(nameof(model.Id)); | |
} | |
var physicalAsset = await _storageUtility.DownloadAssetAsync(model.Id); | |
model.SourceStream = physicalAsset.ContentsStream; | |
using (var destinationStream = new MemoryStream()) | |
{ | |
ImageEditUtility.TransformImage(model, destinationStream); | |
if (model.IsSave) | |
{ | |
var assetRecord = await _assetService.FindByIdAsync(model.Id); | |
bool setThumbs = false; | |
Guid assetType = assetRecord.AssetTypeId; | |
switch (model.Tool) | |
{ | |
// Ww will never overwrite core images, figure out destination type | |
case ImageTool.Face: | |
assetType = EntityConstants.AssetType_Face; | |
break; | |
case ImageTool.Plate: | |
assetType = EntityConstants.AssetType_Plate; | |
break; | |
case ImageTool.Make: | |
assetType = EntityConstants.AssetType_Make; | |
break; | |
default: | |
if (assetType == EntityConstants.AssetType_Front1) | |
assetType = EntityConstants.AssetType_OverrideFront1; | |
else if (assetType == EntityConstants.AssetType_Front2) | |
assetType = EntityConstants.AssetType_OverrideFront2; | |
else if (assetType == EntityConstants.AssetType_Rear1) | |
assetType = EntityConstants.AssetType_OverrideRear1; | |
else if (assetType == EntityConstants.AssetType_Rear2) | |
assetType = EntityConstants.AssetType_OverrideRear2; | |
model.IsPrimaryImage = true; | |
setThumbs = true; | |
break; | |
} | |
var existingAsset = _assetService.All().SingleOrDefault(x => x.AssetTypeId == assetType | |
&& x.AssetDescriptorTypeId == | |
EntityConstants | |
.AssetDescriptorType_OriginalId | |
&& x.EventId == assetRecord.EventId); | |
if (existingAsset != null) | |
{ | |
// The asset we want to write already exists, overwrite it in storage. | |
await _assetService.UpdateAsync(existingAsset); | |
await _storageUtility.UploadAssetAsync(existingAsset.Id, destinationStream, setThumbs); | |
} | |
else | |
{ | |
var newAsset = new Asset() | |
{ | |
EventId = assetRecord.EventId, | |
AssetTypeId = assetType, | |
AssetDescriptorTypeId = EntityConstants.AssetDescriptorType_OriginalId | |
}; | |
var assetId = await _assetService.AddAsync(newAsset); | |
// Save file | |
await _storageUtility.UploadAssetAsync(assetId, destinationStream, setThumbs); | |
} | |
} | |
else | |
{ | |
//Need to set the assetType so we can crop out the info bar from all the filters. | |
var assetRecord = await _assetService.FindByIdAsync(model.Id); | |
Guid assetType = assetRecord.AssetTypeId; | |
if (assetType != EntityConstants.AssetType_Face && assetType != EntityConstants.AssetType_Make && | |
assetType != EntityConstants.AssetType_Plate) | |
model.IsPrimaryImage = true; | |
} | |
model.Image = destinationStream.ToArray(); | |
} | |
physicalAsset.Dispose(); | |
physicalAsset = null; | |
return Ok(model); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment