ASP.NET Core Image Utility/Library

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 preserve the aspect ratio if so desired, rotate the image, and it can square-crop an image (without destorting it). 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; }
	}
	public enum SaveImageAsType
	{
		JPEG,
		GIF,
		PNG,
		TIFF,
		WMF,
		ICON,
		BMP,
		EMF
	}
	public enum RotateImage
	{
		By0,
		By90,
		By180,
		By270
	}
	static public class Square // use to square an image by cropping it
	{
		// ############# save to stream ################
		static public void Image(string fileName, Stream saveToStream, SaveImageAsType imageFormat, RotateImage rotateBy = RotateImage.By0)
		{
			Bitmap iOriginal = new Bitmap(fileName);

			square(iOriginal, saveToStream, imageFormat, rotateBy);

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

			square(iOriginal, saveToStream, imageFormat, rotateBy);

			iOriginal.Dispose();
		}
		// ############# save to filename ################
		static public void Image(string fileName, string saveAsFileName, SaveImageAsType imageFormat, RotateImage rotateBy = RotateImage.By0)
		{
			Bitmap iOriginal = new Bitmap(fileName);

			square(iOriginal, saveAsFileName, imageFormat, rotateBy);

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

			square(iOriginal, saveAsFileName, imageFormat, rotateBy);

			iOriginal.Dispose();
		}
		static private void square(Bitmap iOriginal, object save, SaveImageAsType imageType, RotateImage rotateBy)
		{
			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;
			}

			int newWidth, newHeight;
			newWidth = newHeight = Math.Min(iOriginal.Width, iOriginal.Height);

			Bitmap iSave = new Bitmap(newWidth, newHeight, pixelFormat);

			//Copy the original image over to the temp image
			Graphics gSave = Graphics.FromImage(iSave);
			Rectangle rect;
			if (iOriginal.Width > iOriginal.Height)
				rect = new Rectangle((iOriginal.Width - newWidth) / -2, 0, newWidth + (iOriginal.Width - newWidth) / 2, newHeight);
			else
				rect = new Rectangle(0, (iOriginal.Height - newHeight) / -2, newWidth, newHeight + (iOriginal.Height - newHeight) / 2);
			gSave.DrawImageUnscaledAndClipped(iOriginal, rect);
			gSave.Dispose();

			switch(rotateBy)
			{
				case RotateImage.By90:
					iSave.RotateFlip(RotateFlipType.Rotate90FlipNone);
					break;
				case RotateImage.By180:
					iSave.RotateFlip(RotateFlipType.Rotate180FlipNone);
					break;
				case RotateImage.By270:
					iSave.RotateFlip(RotateFlipType.Rotate270FlipNone);
					break;
			}

			if (save is Stream)
				iSave.Save((Stream)save, imageFormat);
			else if (save is string)
				iSave.Save((string)save, imageFormat);
			iSave.Dispose();
		}
	}
	static public class Resize
	{
		// ############# save to stream ################
		static public void Image(string fileName, int newWidth, int newHeight, bool preserveImageRatio, Stream saveToStream, SaveImageAsType imageFormat, RotateImage rotateBy = RotateImage.By0)
		{
			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, rotateBy);

			iOriginal.Dispose();
		}
		static public void Image(Stream stream, int newWidth, int newHeight, bool preserveImageRatio, Stream saveToStream, SaveImageAsType imageFormat, RotateImage rotateBy = RotateImage.By0)
		{
			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, rotateBy);

			iOriginal.Dispose();
		}
		static public void Image(string fileName, int newNumberOfPixels, Stream saveToStream, SaveImageAsType imageFormat, RotateImage rotateBy = RotateImage.By0)
		{
			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, rotateBy);

			iOriginal.Dispose();
		}
		static public void Image(Stream stream, int newNumberOfPixels, Stream saveToStream, SaveImageAsType imageFormat, RotateImage rotateBy = RotateImage.By0)
		{
			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, rotateBy);

			iOriginal.Dispose();
		}
		// ############# save to filename ################
		static public void Image(string fileName, int newWidth, int newHeight, bool preserveImageRatio, string saveAsFileName, SaveImageAsType imageFormat, RotateImage rotateBy = RotateImage.By0)
		{
			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, rotateBy);

			iOriginal.Dispose();
		}
		static public void Image(Stream stream, int newWidth, int newHeight, bool preserveImageRatio, string saveAsFileName, SaveImageAsType imageFormat, RotateImage rotateBy = RotateImage.By0)
		{
			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, rotateBy);

			iOriginal.Dispose();
		}
		static public void Image(string fileName, int newNumberOfPixels, string saveAsFileName, SaveImageAsType imageFormat, RotateImage rotateBy = RotateImage.By0)
		{
			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, rotateBy);

			iOriginal.Dispose();
		}
		static public void Image(Stream stream, int newNumberOfPixels, string saveAsFileName, SaveImageAsType imageFormat, RotateImage rotateBy = RotateImage.By0)
		{
			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, rotateBy);

			iOriginal.Dispose();
		}
		static private void resize(Bitmap iOriginal, int newWidth, int newHeight, object save, SaveImageAsType imageType, RotateImage rotateBy)
		{
			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();

			switch (rotateBy)
			{
				case RotateImage.By90:
					iSave.RotateFlip(RotateFlipType.Rotate90FlipNone);
					break;
				case RotateImage.By180:
					iSave.RotateFlip(RotateFlipType.Rotate180FlipNone);
					break;
				case RotateImage.By270:
					iSave.RotateFlip(RotateFlipType.Rotate270FlipNone);
					break;
			}

			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);
			}
		}
	}
}