Skip to content

Instantly share code, notes, and snippets.

@MrClan
Created February 7, 2019 06:42
Show Gist options
  • Save MrClan/6e236c69dad0d51e4454ec83186a0def to your computer and use it in GitHub Desktop.
Save MrClan/6e236c69dad0d51e4454ec83186a0def to your computer and use it in GitHub Desktop.
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