articles » current » asp-net-core » image-utility-for-sixlabors-imagesharp

ASP.NET Core: Image Utility for SixLabors.ImageSharp

Manipulate images on Windows and Linux servers including creating a histogram and rotating them as needed to display properly

This small utility library requires adding the NuGet SixLabors.ImageSharp package (version 1.0.4) to the .NET Core/.NET Project. This is compatible with Windows, 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. It rotates/flips the image based on EXIF data. This is to accommodate mobile devices.


using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Formats.Png;

namespace ImageUtil
{
	public class GetSize
	{
		public GetSize(Stream stream)
		{
			using (SixLabors.ImageSharp.Image iOriginal = SixLabors.ImageSharp.Image.Load(stream))
			{
				stream.Position = 0;
				Width = iOriginal.Width;
				Height = iOriginal.Height;
			}
		}
		public int Width { get; }
		public int Height { get; }
	}

	static public class Resize
	{
		public static void SaveImage(Stream imageStream, int newWidth, int newHeight, bool preserveImageRatio, Stream saveToStream)
		{
			using (SixLabors.ImageSharp.Image iOriginal = SixLabors.ImageSharp.Image.Load(imageStream))
			{
				imageStream.Position = 0;
				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(imageStream, iOriginal, newWidth, newHeight, saveToStream);
			}
		}
		public static void SaveImage(Stream imageStream, int newNumberOfPixels, Stream saveToStream)
		{
			using (SixLabors.ImageSharp.Image iOriginal = SixLabors.ImageSharp.Image.Load(imageStream))
			{
				imageStream.Position = 0;
				double ratio = Math.Sqrt(newNumberOfPixels / (double)(iOriginal.Width * iOriginal.Height));
				resize(imageStream, iOriginal, (int)Math.Round(iOriginal.Width * ratio, 0), (int)Math.Round(iOriginal.Height * ratio, 0), saveToStream);
			}
		}
		private static void resize(Stream origSource, SixLabors.ImageSharp.Image image, int newWidth, int newHeight, Stream saveTo)
		{
			image.Mutate(x => x.Resize(newWidth, newHeight));
			transformImage(image); // NOTE: transform image AFTER resizing it!!!
			image.Save(saveTo, SixLabors.ImageSharp.Image.DetectFormat(origSource));
		}
		private static void transformImage(SixLabors.ImageSharp.Image image)
		{
			IExifValue exifOrientation = image.Metadata?.ExifProfile?.GetValue(ExifTag.Orientation);

			if (exifOrientation == null)
				return;

			RotateMode rotateMode;
			FlipMode flipMode;
			setRotateFlipMode(exifOrientation, out rotateMode, out flipMode);

			image.Mutate(x => x.RotateFlip(rotateMode, flipMode));
			image.Metadata.ExifProfile.SetValue(ExifTag.Orientation, (ushort)1);
		}
		private static void setRotateFlipMode(IExifValue exifOrientation, out RotateMode rotateMode, out FlipMode flipMode)
		{
			var orientation = (ushort)exifOrientation.GetValue();

			switch (orientation)
			{
				case 2:
					rotateMode = RotateMode.None;
					flipMode = FlipMode.Horizontal;
					break;
				case 3:
					rotateMode = RotateMode.Rotate180;
					flipMode = FlipMode.None;
					break;
				case 4:
					rotateMode = RotateMode.Rotate180;
					flipMode = FlipMode.Horizontal;
					break;
				case 5:
					rotateMode = RotateMode.Rotate90;
					flipMode = FlipMode.Horizontal;
					break;
				case 6:
					rotateMode = RotateMode.Rotate90;
					flipMode = FlipMode.None;
					break;
				case 7:
					rotateMode = RotateMode.Rotate90;
					flipMode = FlipMode.Vertical;
					break;
				case 8:
					rotateMode = RotateMode.Rotate270;
					flipMode = FlipMode.None;
					break;
				default:
					rotateMode = RotateMode.None;
					flipMode = FlipMode.None;
					break;
			}
		}
	}
	internal class VerticalPen
	{
		private Rgba32 color;
		public VerticalPen(Rgba32 color)
		{
			this.color = color;
		}
		public void Draw(SixLabors.ImageSharp.Image<Rgba32> bmp, int row, int height)
		{
			if (height <= bmp.Height)
				for (int y = height - 1; y >= 0; y--)
					bmp[row, bmp.Height - 1 - y] = color;
		}
	}
	static public class Histogram
	{
		static private MemoryStream create(SixLabors.ImageSharp.Image 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;
			var bmp2 = bmp.CloneAs<Rgb24>();
			for (int y = 0; y < h; y++)
			{
				Span<Rgb24> pixelRow = bmp2.GetPixelRowSpan(y);
				for (int x = 0; x < w; x++)
				{
					var c = pixelRow[x];
					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 != 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 (var bmppre = new SixLabors.ImageSharp.Image<Rgba32>(256, 300))
			{
				var penwhite = new VerticalPen(new Rgba32(255, 255, 255, alpha));
				var penred = new VerticalPen(new Rgba32(255, 0, 0, 64));
				var pengreen = new VerticalPen(new Rgba32(0, 255, 0, 64));
				var penblue = new VerticalPen(new Rgba32(0, 0, 255, 64));
				if (lrgb != LRGB.LUMINANCE)
					for (int i = 0; i < 256; i++)
					{
						if ((lrgb & LRGB.RED) != 0)
							penred.Draw(bmppre, i, (int)(red[i] * HEIGHTFACTOR));
						if ((lrgb & LRGB.GREEN) != 0)
							pengreen.Draw(bmppre, i, (int)(green[i] * HEIGHTFACTOR));
						if ((lrgb & LRGB.BLUE) != 0)
							penblue.Draw(bmppre, i, (int)(blue[i] * HEIGHTFACTOR));
					}
				else
					for (int i = 0; i < 256; i++)
						penwhite.Draw(bmppre, i, (int)(lumin[i] * HEIGHTFACTOR));
				bmppre.Mutate(x => x.Resize(width, height));
				MemoryStream ms = new MemoryStream();
				bmppre.Save(ms, new PngEncoder());
				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 = 255, bool clipWhiteAndBlack = true)
		{
			using (var bmp = SixLabors.ImageSharp.Image<Rgb24>.Load(stream))
			{
				return create(bmp, width, height, lrgb, luminanceAlphaChannel, clipWhiteAndBlack);
			}
		}
		static public MemoryStream CreatePNG(string filename, int width, int height, LRGB lrgb, byte luminanceAlphaChannel = 255, bool clipWhiteAndBlack = true)
		{
			using (var bmp = SixLabors.ImageSharp.Image<Rgb24>.Load(filename))
			{
				return create(bmp, width, height, lrgb, luminanceAlphaChannel, clipWhiteAndBlack);
			}
		}
	}
}

This site uses cookies. Cookies are simple text files stored on the user's computer. They are used for adding features and security to this site. Read the privacy policy.
CLOSE