Created
February 7, 2019 06:42
-
-
Save MrClan/6e236c69dad0d51e4454ec83186a0def to your computer and use it in GitHub Desktop.
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
using System; | |
using System.IO; | |
using System.Drawing; | |
using System.Drawing.Imaging; | |
using System.Diagnostics; | |
using System.Linq; | |
namespace ImageProcessing | |
{ | |
class Program | |
{ | |
static int BorderColorRGBThreshold = 0; | |
static int JpegCompressionValue = 100; | |
static void Main(string[] args) | |
{ | |
Console.WriteLine("Program launched."); | |
try | |
{ | |
BorderColorRGBThreshold = int.Parse(System.Configuration.ConfigurationSettings.AppSettings["BorderColorRGBThreshold"]); | |
JpegCompressionValue = int.Parse(System.Configuration.ConfigurationSettings.AppSettings["JpegCompressionValue"]); | |
if (args != null && args.Length > 0) | |
{ | |
foreach (var a in args) Console.WriteLine(a); | |
if (File.Exists(args[0])) | |
{ | |
ProcessFile(args[0]); | |
} | |
else if (Directory.Exists(args[0])) | |
{ | |
Console.WriteLine("Processing all jpg and png files in this folder..."); | |
foreach (var f in Directory.EnumerateFiles(args[0], "*.*", SearchOption.TopDirectoryOnly).Where(f=> f.ToLower().EndsWith("png") || f.ToLower().EndsWith("jpg"))) | |
ProcessFile(f); | |
} | |
} | |
Console.WriteLine("Program executed successfully. Press enter to exit."); | |
} | |
catch (Exception exc) | |
{ | |
Console.WriteLine(exc.Message); | |
Console.WriteLine("Program halted. Press enter to exit."); | |
} | |
Console.ReadLine(); | |
} | |
static void ProcessFile(string fileName) | |
{ | |
Console.WriteLine(); | |
Console.WriteLine($"Processing file {Path.GetFileName(fileName)}..."); | |
Stopwatch stopwatch = new Stopwatch(); | |
stopwatch.Start(); | |
var strExePath = AppDomain.CurrentDomain.BaseDirectory; | |
var outputPathDir = $"{Path.Combine(strExePath, "ProcessedOutput")}"; | |
if (!Directory.Exists(outputPathDir)) Directory.CreateDirectory(outputPathDir); | |
var strInputImage = fileName; | |
if (!File.Exists(fileName)) return; | |
var sIn = new FileStream(strInputImage, FileMode.Open); | |
var br = new BinaryReader(sIn); | |
var bIn = br.ReadBytes((int)sIn.Length); | |
sIn.Close(); | |
var ms = new MemoryStream(bIn); | |
var inputImg = Bitmap.FromStream(ms) as Bitmap; | |
Rectangle cropRect = CalculateImageRect(inputImg); | |
var croppedImage = CropImage(cropRect, fileName); | |
croppedImage.Save($"{Path.Combine(outputPathDir,Path.GetFileName(fileName))}"); | |
SaveJpeg($"{Path.Combine(outputPathDir, Path.GetFileNameWithoutExtension(fileName) + ".jpeg")}", croppedImage, JpegCompressionValue); | |
stopwatch.Stop(); | |
Console.WriteLine($"done in {stopwatch.ElapsedMilliseconds}ms"); | |
Console.WriteLine(); | |
} | |
public static void SaveJpeg(string path, Image img, int quality) | |
{ | |
if (quality < 0 || quality > 100) | |
throw new ArgumentOutOfRangeException("quality must be between 0 and 100."); | |
// Encoder parameter for image quality | |
EncoderParameter qualityParam = new EncoderParameter(Encoder.Quality, quality); | |
// JPEG image codec | |
ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg"); | |
EncoderParameters encoderParams = new EncoderParameters(1); | |
encoderParams.Param[0] = qualityParam; | |
img.Save(path, jpegCodec, encoderParams); | |
} | |
public static ImageFormat GetImageFormat(string imgFileName) | |
{ | |
using (var img = Image.FromFile(imgFileName)) | |
{ | |
if (img.RawFormat.Equals(ImageFormat.Jpeg)) | |
return ImageFormat.Jpeg; | |
if (img.RawFormat.Equals(ImageFormat.Bmp)) | |
return ImageFormat.Bmp; | |
if (img.RawFormat.Equals(ImageFormat.Png)) | |
return ImageFormat.Png; | |
if (img.RawFormat.Equals(ImageFormat.Emf)) | |
return ImageFormat.Emf; | |
if (img.RawFormat.Equals(ImageFormat.Exif)) | |
return ImageFormat.Exif; | |
if (img.RawFormat.Equals(ImageFormat.Gif)) | |
return ImageFormat.Gif; | |
if (img.RawFormat.Equals(ImageFormat.Icon)) | |
return ImageFormat.Icon; | |
if (img.RawFormat.Equals(ImageFormat.MemoryBmp)) | |
return ImageFormat.MemoryBmp; | |
if (img.RawFormat.Equals(ImageFormat.Tiff)) | |
return ImageFormat.Tiff; | |
else | |
return ImageFormat.Wmf; | |
} | |
} | |
private static ImageCodecInfo GetEncoderInfo(string mimeType) | |
{ | |
// Get image codecs for all image formats | |
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders(); | |
// Find the correct image codec | |
for (int i = 0; i < codecs.Length; i++) | |
if (codecs[i].MimeType == mimeType) | |
return codecs[i]; | |
return null; | |
} | |
private static Bitmap CropImage(Rectangle cropRect, string fileName) | |
{ | |
Bitmap src = Image.FromFile(fileName) as Bitmap; | |
Bitmap target = new Bitmap(cropRect.Width, cropRect.Height); | |
using (Graphics g = Graphics.FromImage(target)) | |
{ | |
g.DrawImage(src, new Rectangle(0, 0, target.Width, target.Height), | |
cropRect, | |
GraphicsUnit.Pixel); | |
} | |
return target; | |
} | |
private static Rectangle CalculateImageRect(Bitmap imgEasy) | |
{ | |
var imageBounds = new Rectangle(0, 0, 0, 0); | |
var leftBorderThickness = GetBorderThickness(imgEasy, BorderColorRGBThreshold, ScanOrientation.Horizontal, false); | |
var topBorderThickness = GetBorderThickness(imgEasy, BorderColorRGBThreshold, ScanOrientation.Vertical, false); | |
var rightBorderThickness = GetBorderThickness(imgEasy, BorderColorRGBThreshold, ScanOrientation.Horizontal, true); | |
var bottomBorderThickness = GetBorderThickness(imgEasy, BorderColorRGBThreshold, ScanOrientation.Vertical, true); | |
imageBounds.X = leftBorderThickness; | |
imageBounds.Y = topBorderThickness; | |
imageBounds.Width = imgEasy.Width - leftBorderThickness - rightBorderThickness; | |
imageBounds.Height = imgEasy.Height - topBorderThickness - bottomBorderThickness; | |
return imageBounds; | |
} | |
private static int GetBorderThickness(Bitmap imgEasy, int rgbThreshold, ScanOrientation scanOrientation, bool checkInReverseDirection) | |
{ | |
// consecutive black lines will be considered as top border | |
int maxConsecutiveBlackLines = 0; | |
int consecutiveBlackLines = 0; | |
var firstDimension = (scanOrientation == ScanOrientation.Vertical ? imgEasy.Height : imgEasy.Width) - 1; | |
var secondDimension = (scanOrientation == ScanOrientation.Vertical ? imgEasy.Width : imgEasy.Height) - 1; | |
if (checkInReverseDirection) | |
{ | |
for (int row = firstDimension; row >= 0; row--) | |
{ | |
bool isCurrentRowBlack = true; | |
for (int column = secondDimension; column >= 0; column--) | |
{ | |
var x = scanOrientation == ScanOrientation.Vertical ? column : row; | |
var y = scanOrientation == ScanOrientation.Vertical ? row : column; | |
var currentPixel = imgEasy.GetPixel(x, y); | |
var isCurrentPixelBlack = (currentPixel.R <= rgbThreshold) | |
&& (currentPixel.G <= rgbThreshold) | |
&& (currentPixel.B <= rgbThreshold); | |
if (!isCurrentPixelBlack) | |
{ | |
isCurrentRowBlack = false; | |
break; | |
} | |
} | |
if (isCurrentRowBlack) | |
{ | |
consecutiveBlackLines++; | |
maxConsecutiveBlackLines = consecutiveBlackLines > maxConsecutiveBlackLines ? consecutiveBlackLines : maxConsecutiveBlackLines; | |
} | |
else | |
{ | |
consecutiveBlackLines = 0; | |
} | |
} | |
} | |
else | |
{ | |
for (int row = 0; row < firstDimension; row++) | |
{ | |
bool isCurrentRowBlack = true; | |
for (int column = 0; column < secondDimension; column++) | |
{ | |
var x = scanOrientation == ScanOrientation.Vertical ? column : row; | |
var y = scanOrientation == ScanOrientation.Vertical ? row : column; | |
var currentPixel = imgEasy.GetPixel(x, y); | |
var isCurrentPixelBlack = (currentPixel.R <= rgbThreshold) | |
&& (currentPixel.G <= rgbThreshold) | |
&& (currentPixel.B <= rgbThreshold); | |
if (!isCurrentPixelBlack) | |
{ | |
isCurrentRowBlack = false; | |
break; | |
} | |
} | |
if (isCurrentRowBlack) | |
{ | |
consecutiveBlackLines++; | |
maxConsecutiveBlackLines = consecutiveBlackLines > maxConsecutiveBlackLines ? consecutiveBlackLines : maxConsecutiveBlackLines; | |
} | |
else | |
{ | |
consecutiveBlackLines = 0; | |
} | |
} | |
} | |
return maxConsecutiveBlackLines; | |
} | |
} | |
enum ScanOrientation | |
{ | |
Horizontal, | |
Vertical | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment