ASP.NET Core Image Utility

This small library requires adding System.Drawing.Common to the ASP.NET Core Project. This makes it incompatible with Linux and MacOS. It can resize an image based on the number of megapixels or length by width and can preserve the aspect ratio. It also can do a histogram of an image both in luminosity and RGB channels.

using System;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;

namespace ImageUtil
{
	public class GetSize
	{
		public GetSize(Stream stream)
		{
			Image iOriginal = new Bitmap(stream);
			Width = iOriginal.Width;
			Height = iOriginal.Height;
			iOriginal.Dispose();
		}
		public GetSize(string fileName)
		{
			Image iOriginal = new Bitmap(fileName);
			Width = iOriginal.Width;
			Height = iOriginal.Height;
			iOriginal.Dispose();
		}
		public int Width { get; }
		public int Height { get; }
	}
	static public class Resize
	{
		public enum SaveImageAsType
		{
			JPEG,
			GIF,
			PNG,
			TIFF,
			WMF,
			ICON,
			BMP,
			EMF
		}
		// ############# save to stream ################
		static public void Image(string fileName, int newWidth, int newHeight, bool preserveImageRatio, Stream saveToStream, SaveImageAsType imageFormat)
		{
			Bitmap iOriginal = new Bitmap(fileName);

			if (preserveImageRatio)
			{
				float percentWidth = newWidth / (float)iOriginal.Width;
				float percentHeight = newHeight / (float)iOriginal.Height;
				float percent = percentHeight < percentWidth ? percentHeight : percentWidth;
				newWidth = (int)Math.Round(iOriginal.Width * percent, 0);
				newHeight = (int)Math.Round(iOriginal.Height * percent, 0);
			}
			resize(iOriginal, newWidth, newHeight, saveToStream, imageFormat);

			iOriginal.Dispose();
		}
		static public void Image(Stream stream, int newWidth, int newHeight, bool preserveImageRatio, Stream saveToStream, SaveImageAsType imageFormat)
		{
			Bitmap iOriginal = new Bitmap(stream);

			if (preserveImageRatio)
			{
				float percentWidth = newWidth / (float)iOriginal.Width;
				float percentHeight = newHeight / (float)iOriginal.Height;
				float percent = percentHeight < percentWidth ? percentHeight : percentWidth;
				newWidth = (int)Math.Round(iOriginal.Width * percent, 0);
				newHeight = (int)Math.Round(iOriginal.Height * percent, 0);
			}
			resize(iOriginal, newWidth, newHeight, saveToStream, imageFormat);

			iOriginal.Dispose();
		}
		static public void Image(string fileName, int newNumberOfPixels, Stream saveToStream, SaveImageAsType imageFormat)
		{
			Bitmap iOriginal = new Bitmap(fileName);

			double ratio = Math.Sqrt(newNumberOfPixels / (double)(iOriginal.Width * iOriginal.Height));
			resize(iOriginal, (int)Math.Round(iOriginal.Width * ratio, 0), (int)Math.Round(iOriginal.Height * ratio, 0), saveToStream, imageFormat);

			iOriginal.Dispose();
		}
		static public void Image(Stream stream, int newNumberOfPixels, Stream saveToStream, SaveImageAsType imageFormat)
		{
			Bitmap iOriginal = new Bitmap(stream);

			double ratio = Math.Sqrt(newNumberOfPixels / (double)(iOriginal.Width * iOriginal.Height));
			resize(iOriginal, (int)Math.Round(iOriginal.Width * ratio, 0), (int)Math.Round(iOriginal.Height * ratio, 0), saveToStream, imageFormat);

			iOriginal.Dispose();
		}
		// ############# save to filename ################
		static public void Image(string fileName, int newWidth, int newHeight, bool preserveImageRatio, string saveAsFileName, SaveImageAsType imageFormat)
		{
			Bitmap iOriginal = new Bitmap(fileName);

			if (preserveImageRatio)
			{
				float percentWidth = newWidth / (float)iOriginal.Width;
				float percentHeight = newHeight / (float)iOriginal.Height;
				float percent = percentHeight < percentWidth ? percentHeight : percentWidth;
				newWidth = (int)Math.Round(iOriginal.Width * percent, 0);
				newHeight = (int)Math.Round(iOriginal.Height * percent, 0);
			}
			resize(iOriginal, newWidth, newHeight, saveAsFileName, imageFormat);

			iOriginal.Dispose();
		}
		static public void Image(Stream stream, int newWidth, int newHeight, bool preserveImageRatio, string saveAsFileName, SaveImageAsType imageFormat)
		{
			Bitmap iOriginal = new Bitmap(stream);

			if (preserveImageRatio)
			{
				float percentWidth = newWidth / (float)iOriginal.Width;
				float percentHeight = newHeight / (float)iOriginal.Height;
				float percent = percentHeight < percentWidth ? percentHeight : percentWidth;
				newWidth = (int)Math.Round(iOriginal.Width * percent, 0);
				newHeight = (int)Math.Round(iOriginal.Height * percent, 0);
			}
			resize(iOriginal, newWidth, newHeight, saveAsFileName, imageFormat);

			iOriginal.Dispose();
		}
		static public void Image(string fileName, int newNumberOfPixels, string saveAsFileName, SaveImageAsType imageFormat)
		{
			Bitmap iOriginal = new Bitmap(fileName);

			double ratio = Math.Sqrt(newNumberOfPixels / (double)(iOriginal.Width * iOriginal.Height));
			resize(iOriginal, (int)Math.Round(iOriginal.Width * ratio, 0), (int)Math.Round(iOriginal.Height * ratio, 0), saveAsFileName, imageFormat);

			iOriginal.Dispose();
		}
		static public void Image(Stream stream, int newNumberOfPixels, string saveAsFileName, SaveImageAsType imageFormat)
		{
			Bitmap iOriginal = new Bitmap(stream);

			double ratio = Math.Sqrt(newNumberOfPixels / (double)(iOriginal.Width * iOriginal.Height));
			resize(iOriginal, (int)Math.Round(iOriginal.Width * ratio, 0), (int)Math.Round(iOriginal.Height * ratio, 0), saveAsFileName, imageFormat);

			iOriginal.Dispose();
		}
		static private void resize(Bitmap iOriginal, int newWidth, int newHeight, object save, SaveImageAsType imageType)
		{
			ImageFormat imageFormat;
			PixelFormat pixelFormat;
			switch (imageType)
			{
				case SaveImageAsType.BMP:
					imageFormat = ImageFormat.Bmp;
					pixelFormat = PixelFormat.Format24bppRgb;
					break;
				case SaveImageAsType.EMF:
					imageFormat = ImageFormat.Emf;
					pixelFormat = PixelFormat.Format24bppRgb;
					break;
				case SaveImageAsType.GIF:
					imageFormat = ImageFormat.Gif;
					pixelFormat = PixelFormat.Format8bppIndexed;
					break;
				case SaveImageAsType.ICON:
					imageFormat = ImageFormat.Icon;
					pixelFormat = PixelFormat.Format32bppArgb;
					break;
				case SaveImageAsType.JPEG:
					imageFormat = ImageFormat.Jpeg;
					pixelFormat = PixelFormat.Format24bppRgb;
					break;
				case SaveImageAsType.PNG:
					imageFormat = ImageFormat.Png;
					pixelFormat = PixelFormat.Format32bppArgb;
					break;
				case SaveImageAsType.TIFF:
					imageFormat = ImageFormat.Tiff;
					pixelFormat = PixelFormat.Format24bppRgb;
					break;
				case SaveImageAsType.WMF:
					imageFormat = ImageFormat.Wmf;
					pixelFormat = PixelFormat.Format24bppRgb;
					break;
				default:
					imageFormat = ImageFormat.Jpeg;
					pixelFormat = PixelFormat.Format24bppRgb;
					break;
			}
			Bitmap iSave = new Bitmap(newWidth, newHeight, pixelFormat);

			//Copy the original image over to the temp image
			Graphics gSave = Graphics.FromImage(iSave);
			gSave.DrawImage(iOriginal, 0, 0, newWidth, newHeight);
			gSave.Dispose();

			if (save is Stream)
				iSave.Save((Stream)save, imageFormat);
			else if (save is string)
				iSave.Save((string)save, imageFormat);
			iSave.Dispose();
		}
	}
	static public class Histogram
	{
		static private MemoryStream create(Bitmap bmp, int width, int height, LRGB lrgb, byte alpha, bool clip)
		{
			ulong[] lumin = new ulong[256];
			ulong[] red = new ulong[256];
			ulong[] green = new ulong[256];
			ulong[] blue = new ulong[256];
			int w = bmp.Width;
			int h = bmp.Height;
			for (int x = 0; x < w; x++)
			{
				for (int y = 0; y < h; y++)
				{
					Color c = bmp.GetPixel(x, y);
					lumin[(int)Math.Round((c.R + c.G + c.B) / 3.0)]++;
					red[c.R]++;
					green[c.G]++;
					blue[c.B]++;
				}
			}
			ulong max = 0;
			int a = (clip ? 1 : 0), b = (clip ? 255 : 256);
			for (int i = a; i < b; i++)
			{
				if(lrgb != (byte)LRGB.LUMINANCE)
				{
					if((lrgb & LRGB.RED) != 0)
						if (max < red[i])
							max = red[i];
					if ((lrgb & LRGB.GREEN) != 0)
						if (max < green[i])
							max = green[i];
					if ((lrgb & LRGB.BLUE) != 0)
						if (max < blue[i])
							max = blue[i];
				}
				else if (max < lumin[i])
					max = lumin[i];
			}
			double HEIGHTFACTOR = 300.0 / max;
			using (Bitmap bmppre = new Bitmap(256, 300, PixelFormat.Format32bppArgb))
			{
				using (Pen penwhite = new Pen(Color.FromArgb(alpha, 255, 255, 255)))
				{
					using (Pen penred = new Pen(Color.FromArgb(64, 255, 0, 0)))
					{
						using (Pen pengreen = new Pen(Color.FromArgb(64, 0, 255, 0)))
						{
							using (Pen penblue = new Pen(Color.FromArgb(64, 0, 0, 255)))
							{
								using (Graphics gfx = Graphics.FromImage(bmppre))
								{
									Point pt1, pt2;
									if (lrgb != LRGB.LUMINANCE)
										for (int i = 0; i < 256; i++)
										{
											if ((lrgb & LRGB.RED) != 0)
											{
												pt1 = new Point(i, 299);
												pt2 = new Point(i, 299 - (int)(red[i] * HEIGHTFACTOR));
												gfx.DrawLine(penred, pt1, pt2);
											}
											if ((lrgb & LRGB.GREEN) != 0)
											{
												pt1 = new Point(i, 299);
												pt2 = new Point(i, 299 - (int)(green[i] * HEIGHTFACTOR));
												gfx.DrawLine(pengreen, pt1, pt2);
											}
											if ((lrgb & LRGB.BLUE) != 0)
											{
												pt1 = new Point(i, 299);
												pt2 = new Point(i, 299 - (int)(blue[i] * HEIGHTFACTOR));
												gfx.DrawLine(penblue, pt1, pt2);
											}
										}
									else
										for (int i = 0; i < 256; i++)
										{
											pt1 = new Point(i, 299);
											pt2 = new Point(i, 299 - (int)(lumin[i] * HEIGHTFACTOR));
											gfx.DrawLine(penwhite, pt1, pt2);
										}
								}
							}
						}
					}
					using (Bitmap histogram = new Bitmap(width, height, PixelFormat.Format32bppArgb))
					{
						using (Graphics gfx = Graphics.FromImage(histogram))
						{
							gfx.DrawImage(bmppre, 0, 0, width, height);
							using (MemoryStream ms = new MemoryStream())
							{
								histogram.Save(ms, ImageFormat.Png);
								return ms;
							}
						}
					}
				}
			}
		}
		public enum LRGB
		{
			LUMINANCE = 0,
			RED = 1,
			GREEN = 2,
			BLUE = 4,
			REDBLUE = 1 | 4,
			REDGREEN = 1 | 2,
			BLUEGREEN = 2 | 4,
			REDBLUEGREEN = 1 | 2 | 4
		}
		static public MemoryStream CreatePNG(Stream stream, int width, int height, LRGB lrgb, byte luminanceAlphaChannel, bool clipWhiteAndBlack)
		{
			using (Bitmap bmp = new Bitmap(stream))
			{
				return create(bmp, width, height, lrgb, luminanceAlphaChannel, clipWhiteAndBlack);
			}
		}
		static public MemoryStream CreatePNG(string filename, int width, int height, LRGB lrgb, byte luminanceAlphaChannel, bool clipWhiteAndBlack)
		{
			using (Bitmap bmp = new Bitmap(filename))
			{
				return create(bmp, width, height, lrgb, luminanceAlphaChannel, clipWhiteAndBlack);
			}
		}
	}
}

Using EXIFTOOL (See .NET processes for more information):

// this function returns all the exif data which is much faster than extracting the data one field at a time
string ExifExtractAllData(string imageFilePath)
{
	using (var proc = new System.Diagnostics.Process
	{
		StartInfo = new System.Diagnostics.ProcessStartInfo
		{
			FileName = "exiftool.exe", // make sure this path is found
			Arguments = '"' + imageFilePath + '"',
			UseShellExecute = false,
			RedirectStandardOutput = true,
			CreateNoWindow = true
		}
	})
	{
		proc.Start();
		if (!proc.StandardOutput.EndOfStream)
			return proc.StandardOutput.ReadToEnd();
	}
	return null;
}
// this parses the data returned by ExifExtractAllData()
// this returns an array of string values because "field" can be a wildcard,
// for example, every field beginning with Lens would be "Lens*"
public static string[] ExifExtractValue(string exifdata, string field)
{
	string ret = "\0";
	if (field.Length > 0 && field[0] == '-')
		field = field.Substring(1);
	bool multi = field.Contains('*');
	if (multi)
		field = field.Substring(0, field.IndexOf('*'));
	using (System.IO.StringReader reader = new System.IO.StringReader(exifdata))
	{
		while (true)
		{
			string line = reader.ReadLine();
			if (line == null)
				return ret.Split(new char[] { '\0' }, System.StringSplitOptions.RemoveEmptyEntries);
			int i = line.IndexOf(':');
			string f = line.Substring(0, i).Trim().Replace(" ", "");
			if (f == field || (multi && f.StartsWith(field)))
			{
				ret += (f + '|' + line.Substring(i + 1, line.Length - (i + 1)).Trim() + '\0');
				if (!multi)
					return ret.Split(new char[] { '\0' }, System.StringSplitOptions.RemoveEmptyEntries);
			}
		}
	}
}