mirror of
https://github.com/revenz/FileFlowsPlugins.git
synced 2025-12-30 17:39:57 -06:00
tweaked autocrop
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using SixLabors.ImageSharp.Formats;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using System.ComponentModel;
|
||||
|
||||
@@ -27,16 +28,124 @@ public class AutoCropImage : ImageNode
|
||||
if (threshold < 0)
|
||||
threshold = 0.5f;
|
||||
|
||||
args.Logger?.ILog("Attempting to auto crop using threshold: " + threshold);
|
||||
image.Mutate(c => c.EntropyCrop(threshold));
|
||||
var scaleFactor = originalWidth > 4000 && originalHeight > 4000 ? 10 :
|
||||
originalWidth > 2000 && originalHeight > 2000 ? 6 :
|
||||
4;
|
||||
|
||||
if (image.Width == originalWidth && image.Height == originalHeight)
|
||||
// entropycrop of Sixlabors does not give good results if the image has artifacts in it, eg from a scanned in image
|
||||
// so we need to detect the whitespace ourselves. first we convert to greyscale and downscale, this should remove some artifacts for us
|
||||
// when then look for the outer most non white pixels for out bounds
|
||||
// then we upscale those bounds to the original dimensions and crop with those bounds
|
||||
image.Mutate(c =>
|
||||
{
|
||||
c.Grayscale().Resize(originalWidth / scaleFactor, originalHeight / scaleFactor);
|
||||
});
|
||||
string temp = Path.Combine(args.TempPath, Guid.NewGuid() + ".jpg");
|
||||
image.SaveAsJpeg(temp);
|
||||
var bounds = GetTrimBounds(temp);
|
||||
bounds.X *= scaleFactor;
|
||||
bounds.Y *= scaleFactor;
|
||||
bounds.Width *= scaleFactor;
|
||||
bounds.Height *= scaleFactor;
|
||||
image.Dispose();
|
||||
|
||||
args.Logger?.ILog("Attempting to auto crop using threshold: " + threshold);
|
||||
if (bounds.Width == originalWidth && bounds.Height == originalHeight)
|
||||
return 2;
|
||||
|
||||
using var image2 = Image.Load(args.WorkingFile, out format);
|
||||
|
||||
|
||||
image2.Mutate(c =>
|
||||
{
|
||||
c.Crop(bounds);
|
||||
//c.EntropyCrop(threshold);
|
||||
});
|
||||
|
||||
if (image2.Width == originalWidth && image2.Height == originalHeight)
|
||||
return 2;
|
||||
|
||||
var formatOpts = GetFormat(args);
|
||||
SaveImage(args, image, formatOpts.file, formatOpts.format ?? format);
|
||||
args.Logger?.ILog($"Image cropped from '{originalWidth}x{originalHeight}' to '{image.Width}x{image.Height}'");
|
||||
SaveImage(args, image2, formatOpts.file, formatOpts.format ?? format);
|
||||
args.Logger?.ILog($"Image cropped from '{originalWidth}x{originalHeight}' to '{image2.Width}x{image2.Height}'");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public Rectangle GetTrimBounds(string file)
|
||||
{
|
||||
int threshhold = 255 - (this.Threshold / 4);
|
||||
|
||||
|
||||
int topOffset = 0;
|
||||
int bottomOffset = 0;
|
||||
int leftOffset = 0;
|
||||
int rightOffset = 0;
|
||||
|
||||
|
||||
using Image<Rgba32> image = Image.Load<Rgba32>(file);
|
||||
bool foundColor = false;
|
||||
// Get left bounds to crop
|
||||
for (int x = 1; x < image.Width && foundColor == false; x++)
|
||||
{
|
||||
for (int y = 1; y < image.Height && foundColor == false; y++)
|
||||
{
|
||||
var color = image[x, y];
|
||||
if (color.R < threshhold || color.G < threshhold || color.B < threshhold)
|
||||
foundColor = true;
|
||||
}
|
||||
leftOffset += 1;
|
||||
}
|
||||
|
||||
|
||||
foundColor = false;
|
||||
// Get top bounds to crop
|
||||
for (int y = 1; y < image.Height && foundColor == false; y++)
|
||||
{
|
||||
for (int x = 1; x < image.Width && foundColor == false; x++)
|
||||
{
|
||||
var color = image[x, y];
|
||||
if (color.R < threshhold || color.G < threshhold || color.B < threshhold)
|
||||
foundColor = true;
|
||||
}
|
||||
topOffset += 1;
|
||||
}
|
||||
|
||||
|
||||
foundColor = false;
|
||||
// Get right bounds to crop
|
||||
for (int x = image.Width - 1; x >= 1 && foundColor == false; x--)
|
||||
{
|
||||
for (int y = 1; y < image.Height && foundColor == false; y++)
|
||||
{
|
||||
var color = image[x, y];
|
||||
if (color.R < threshhold || color.G < threshhold || color.B < threshhold)
|
||||
foundColor = true;
|
||||
}
|
||||
rightOffset += 1;
|
||||
}
|
||||
|
||||
|
||||
foundColor = false;
|
||||
// Get bottom bounds to crop
|
||||
for (int y = image.Height - 1; y >= 1 && foundColor == false; y--)
|
||||
{
|
||||
for (int x = 1; x < image.Width && foundColor == false; x++)
|
||||
{
|
||||
var color = image[x, y];
|
||||
if (color.R < threshhold || color.G < threshhold || color.B < threshhold)
|
||||
foundColor = true;
|
||||
}
|
||||
bottomOffset += 1;
|
||||
}
|
||||
|
||||
|
||||
var bounds = new Rectangle(
|
||||
leftOffset,
|
||||
topOffset,
|
||||
image.Width - leftOffset - rightOffset,
|
||||
image.Height - topOffset - bottomOffset
|
||||
);
|
||||
return bounds;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ public class ImageNodesTests
|
||||
string TestImage1;
|
||||
string TestImage2;
|
||||
string TempDir;
|
||||
string TestCropImage1, TestCropImage2, TestCropImage3, TestCropImageNoCrop;
|
||||
string TestCropImage1, TestCropImage2, TestCropImage3, TestCropImage4, TestCropImageNoCrop;
|
||||
|
||||
public ImageNodesTests()
|
||||
{
|
||||
@@ -25,6 +25,7 @@ public class ImageNodesTests
|
||||
TestCropImage1 = @"D:\images\testimages\crop01.jpg";
|
||||
TestCropImage2 = @"D:\images\testimages\crop02.jpg";
|
||||
TestCropImage3 = @"D:\images\testimages\crop03.jpg";
|
||||
TestCropImage4 = @"D:\images\testimages\crop04.jpg";
|
||||
TestCropImageNoCrop = @"D:\images\testimages\nocrop.jpg";
|
||||
}
|
||||
else
|
||||
@@ -126,6 +127,8 @@ public class ImageNodesTests
|
||||
};
|
||||
|
||||
var node = new AutoCropImage();
|
||||
node.Threshold = 50;
|
||||
node.PreExecute(args);
|
||||
int result = node.Execute(args);
|
||||
|
||||
string log = logger.ToString();
|
||||
@@ -159,6 +162,32 @@ public class ImageNodesTests
|
||||
};
|
||||
|
||||
var node = new AutoCropImage();
|
||||
node.Threshold = 50;
|
||||
node.PreExecute(args);
|
||||
int result = node.Execute(args);
|
||||
|
||||
string log = logger.ToString();
|
||||
Assert.AreEqual(1, result);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ImageNodes_Basic_AutoCrop_04()
|
||||
{
|
||||
var logger = new TestLogger();
|
||||
var args = new NodeParameters(TestCropImage4, logger, false, string.Empty)
|
||||
{
|
||||
TempPath = TempDir
|
||||
};
|
||||
|
||||
//var rotate = new ImageRotate();
|
||||
//rotate.Angle = 270;
|
||||
//rotate.PreExecute(args);
|
||||
//rotate.Execute(args);
|
||||
|
||||
|
||||
var node = new AutoCropImage();
|
||||
node.Threshold = 70;
|
||||
node.PreExecute(args);
|
||||
int result = node.Execute(args);
|
||||
|
||||
string log = logger.ToString();
|
||||
@@ -175,6 +204,8 @@ public class ImageNodesTests
|
||||
};
|
||||
|
||||
var node = new AutoCropImage();
|
||||
node.Threshold = 50;
|
||||
node.PreExecute(args);
|
||||
int result = node.Execute(args);
|
||||
|
||||
string log = logger.ToString();
|
||||
|
||||
Reference in New Issue
Block a user