Skip to content

Instantly share code, notes, and snippets.

@antonfirsov
Created March 18, 2021 14:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save antonfirsov/765dc11a8f83a786bdcd0f453e534004 to your computer and use it in GitHub Desktop.
Save antonfirsov/765dc11a8f83a786bdcd0f453e534004 to your computer and use it in GitHub Desktop.
ImageSharp-1577-Repro
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;
}
[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