.NETSixLabors.ImageSharpv1.0图像实用程序控制台示例
- 互联网
- 2025-08-31 08:18:01

使用 C# 控制台应用程序示例在 Windows、Linux 和 MacOS 机器上处理图像,包括创建散点图和直方图,以及根据需要旋转图像以便正确显示。 这个小型实用程序库需要将 NuGet SixLabors.ImageSharp包(版本 1.0.4)添加到.NET Core 3.1/ .NET 6 / .NET 8项目中。它与Windows、Linux和 MacOS兼容。
这已针对ImageSharp v3.0.1 进行了重新设计。
它可以根据百万像素数或长度乘以宽度来调整图像大小,并根据需要保留纵横比。
它根据EXIF数据旋转/翻转图像。这是为了适应移动设备。
它还创建散点图和直方图。
using SixLabors.ImageSharp; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Formats.Png; using System.IO; using System; using SixLabors.ImageSharp.Formats.Jpeg;
namespace ImageUtil { public class GetSize { public GetSize(Stream stream) { using (Image iOriginal = Image.Load(stream)) { stream.Position = 0; Width = iOriginal.Width; Height = iOriginal.Height; } }
/// <summary> /// The width of the image specified in the class constructor's Stream parameter /// </summary> public int Width { get; }
/// <summary> /// The height of the image specified in the class constructor's Stream parameter /// </summary> public int Height { get; } }
public static class Resize { /// <summary> /// Resize and save an image to a Stream specifying its new width and height /// </summary> public static void SaveImage(Stream imageStream, int newWidth, int newHeight, bool preserveImageRatio, Stream saveToStream, int jpegQuality = 100) { using (Image iOriginal = 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, jpegQuality); } }
/// <summary> /// Resize and save an image to a Stream specifying the number of pixels to resize to /// </summary> public static void SaveImage(Stream imageStream, int newNumberOfPixels, Stream saveToStream, int jpegQuality = 100) { using (Image iOriginal = 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, jpegQuality); } }
private static void resize(Stream origSource, Image image, int newWidth, int newHeight, Stream saveTo, int jpegQuality) { image.Mutate(x => x.Resize(newWidth, newHeight)); transformImage(image); // NOTE: transform image AFTER resizing it!!! var format = Image.DetectFormat(origSource); if (format.Name.ToLower() == "jpeg") { var encoder = new JpegEncoder(); encoder.Quality = jpegQuality; image.SaveAsJpeg(saveTo, encoder); } else image.Save(saveTo, format); } private static void transformImage(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; } } }
/* CREATE A SCATTER PLOT JPEG/PNG IMAGE */ public static class ScatterPlot { static readonly Rgba32 WHITE = new Rgba32(255, 255, 255); static readonly Rgba32 BLACK = new Rgba32(0, 0, 0); static readonly Rgba32 RED = new Rgba32(255, 0, 0); static readonly Rgba32 BLUE = new Rgba32(0, 0, 255); static readonly Rgba32 GREEN = new Rgba32(0, 192, 0); static readonly Rgba32 PURPLE = new Rgba32(128, 0, 128); static readonly Rgba32 ORANGE = new Rgba32(255, 164, 0); static readonly Rgba32 YELLOW = new Rgba32(255, 225, 0); static readonly Rgba32 MAGENTA = new Rgba32(255, 0, 255); static readonly Rgba32 AQUA = new Rgba32(0, 225, 255); static readonly Rgba32 BLUEJEAN = new Rgba32(0, 128, 255); static readonly Rgba32 BROWN = new Rgba32(150, 75, 50); static readonly Rgba32 CHARTREUSE = new Rgba32(223, 255, 0); static readonly Rgba32 DODGERBLUE = new Rgba32(30, 144, 255); static readonly Rgba32 NAVY = new Rgba32(0, 0, 128); static readonly Rgba32 DARKRED = new Rgba32(139, 0, 0); static readonly Rgba32[] colors = new Rgba32[] { WHITE, BLACK, RED, BLUE, GREEN, PURPLE, ORANGE, YELLOW, MAGENTA, AQUA, BLUEJEAN, BROWN, DODGERBLUE, CHARTREUSE, NAVY, DARKRED }; public static void CreateJPEG(Stream stream, ScatterPlotColors backgroundColor, IEnumerable<PlotPoint> points, int width, int height, int pointSize, int jpegQuality = 100) { using (var bmp = new Image<Rgba32>(width / pointSize + 6, height / pointSize + 6, colors[(int)backgroundColor])) create(stream, width, height, bmp, points, pointSize, new JpegEncoder() { Quality = jpegQuality }); } public static void CreateJPEG(string filename, ScatterPlotColors backgroundColor, IEnumerable<PlotPoint> points, int width, int height, int pointSize, int jpegQuality = 100) { using (var stream = File.Create(filename)) CreateJPEG(stream, backgroundColor, points, width, height, pointSize, jpegQuality); }
public static void CreatePNG(Stream stream, IEnumerable<PlotPoint> points, int width, int height, int pointSize) { using (var bmp = new Image<Rgba32>(width / pointSize + 6, height / pointSize + 6)) create(stream, width, height, bmp, points, pointSize, new PngEncoder()); } public static void CreatePNG(string filename, IEnumerable<PlotPoint> points, int width, int height, int pointSize) { using (var stream = File.Create(filename)) CreatePNG(stream, points, width, height, pointSize); }
private static double normalize(float min, float max, float value) { double x = max - min; if(x == 0) return 0; return (value - min) / x; }
private static void create(Stream stream, int width, int height, Image<Rgba32> bmp, IEnumerable<PlotPoint> points, int pointSize, SixLabors.ImageSharp.Formats.IImageEncoder imageEncoder) { float xMax = float.MinValue, xMin = float.MaxValue, yMax = float.MinValue, yMin = float.MaxValue; foreach (var pt in points) { xMax = Math.Max(pt.x, xMax); xMin = Math.Min(pt.x, xMin); yMax = Math.Max(pt.y, yMax); yMin = Math.Min(pt.y, yMin); } float xDelta = Math.Max(1, xMax - xMin), yDelta = Math.Max(1, yMax - yMin); int w = width / pointSize; int h = height / pointSize; foreach (var pt in points) { int x = (int)(w * normalize(xMin, xMax, pt.x)); int y = (int)(h * normalize(yMin, yMax, pt.y)); bmp[x + 3, y + 3] = colors[((int)pt.color) % colors.Length]; } bmp.Mutate(x => x.Flip(FlipMode.Vertical)); bmp.Mutate(x => x.Resize(width, height)); bmp.Save(stream, imageEncoder); } } public class PlotPoint { public ScatterPlotColors color { get; } public float x { get; } public float y { get; } public PlotPoint(float x, float y, ScatterPlotColors color) { this.x = x; this.y = y; this.color = color; } } public enum ScatterPlotColors { WHITE, BLACK, RED, BLUE, GREEN, PURPLE, ORANGE, YELLOW, MAGENTA, AQUA, BLUEJEAN, BROWN, CHARTREUSE, DODGERBLUE, NAVY, DARKRED }
/* CREATE A PNG HISTOGRAM OF AN IMAGE */ public static class Histogram { /// <summary> /// Create a histogram from the data in a stream /// </summary> public static MemoryStream CreatePNG(Stream stream, int width, int height, LRGB lrgb, byte alphaChannel = 128, bool clipBlackAndWhite = true, byte luminanceShade = 255) { using (var bmp = Image<Rgb24>.Load(stream)) { return create(bmp, width, height, lrgb, alphaChannel, clipBlackAndWhite, luminanceShade); } }
/// <summary> /// Create a histogram from the data in a file /// </summary> public static MemoryStream CreatePNG(string filename, int width, int height, LRGB lrgb, byte alphaChannel = 128, bool clipBlackAndWhite = true, byte luminanceShade = 255) { using (var bmp = Image<Rgb24>.Load(filename)) { return create(bmp, width, height, lrgb, alphaChannel, clipBlackAndWhite, luminanceShade); } }
private static MemoryStream create(Image bmp, int width, int height, LRGB lrgb, byte alpha, bool clip, byte shade) { ulong[] lumin = new ulong[256]; ulong[] red = new ulong[256]; ulong[] green = new ulong[256]; ulong[] blue = new ulong[256]; var bred = (lrgb & LRGB.RED) != 0; var bgreen = (lrgb & LRGB.GREEN) != 0; var bblue = (lrgb & LRGB.BLUE) != 0; var blumin = (lrgb == LRGB.LUMINANCE); 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 (!blumin) { if (bred) if (max < red[i]) max = red[i]; if (bgreen) if (max < green[i]) max = green[i]; if (bblue) if (max < blue[i]) max = blue[i]; } else if (max < lumin[i]) max = lumin[i]; } double HEIGHTFACTOR = 256.0 / max; if (blumin) { using (var bmplum = new Image<Rgba32>(256, 256)) { var penlum = new VerticalPen(new Rgba32(shade, shade, shade, alpha)); for (int i = 0; i < 256; i++) penlum.Draw(bmplum, i, (int)(lumin[i] * HEIGHTFACTOR)); bmplum.Mutate(x => x.Resize(width, height)); MemoryStream ms = new MemoryStream(); bmplum.Save(ms, new PngEncoder()); return ms; } } else { using (var bmppre = new Image<Rgba32>(256, 256)) { Image<Rgba32>? bmpred = null, bmpgreen = null, bmpblue = null; VerticalPen? penred = null, pengreen = null, penblue = null; if (bred) { bmpred = new Image<Rgba32>(256, 256); penred = new VerticalPen(new Rgba32(255, 0, 0, alpha)); } if (bgreen) { bmpgreen = new Image<Rgba32>(256, 256); pengreen = new VerticalPen(new Rgba32(0, 255, 0, alpha)); } if (bblue) { bmpblue = new Image<Rgba32>(256, 256); penblue = new VerticalPen(new Rgba32(0, 0, 255, alpha)); }
for (int i = 0; i < 256; i++) { if (bred) penred.Draw(bmpred, i, (int)(red[i] * HEIGHTFACTOR)); if (bgreen) pengreen.Draw(bmpgreen, i, (int)(green[i] * HEIGHTFACTOR)); if (bblue) penblue.Draw(bmpblue, i, (int)(blue[i] * HEIGHTFACTOR)); }
if (bred) { bmppre.Mutate(x => x.DrawImage(bmpred, 1)); bmpred.Dispose(); } if (bgreen) { bmppre.Mutate(x => x.DrawImage(bmpgreen, 1)); bmpgreen.Dispose(); } if (bblue) { bmppre.Mutate(x => x.DrawImage(bmpblue, 1)); bmpblue.Dispose(); } bmppre.Mutate(x => x.Resize(width, height)); MemoryStream ms = new MemoryStream(); bmppre.Save(ms, new PngEncoder()); return ms; } } } internal class VerticalPen { private readonly Rgba32 color; public VerticalPen(Rgba32 color) { this.color = color; } public void Draw(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; } } public enum LRGB { LUMINANCE = 0, RED = 1, GREEN = 2, BLUE = 4, REDBLUE = 1 | 4, REDGREEN = 1 | 2, BLUEGREEN = 2 | 4, REDGREENBLUE = 1 | 2 | 4 } } }
示例用法 另请参阅:Web 应用程序示例 namespace ConsoleApp1 { class Program { static void Main(string[] args) { if(args.Length > 0) { using (var openfs = System.IO.File.OpenRead(args[0])) { // NOTE: GET IMAGE SIZE var size = new ImageUtil.GetSize(openfs);
System.Console.WriteLine("IMAGE SIZE: " + size.Width + " x " + size.Height);
if (args.Length > 1) { if (System.IO.File.Exists(args[1])) System.IO.File.Delete(args[1]); using (var savefs = System.IO.File.OpenWrite(args[1])) { System.Console.WriteLine("RESIZING IMAGE TO 10K PIXEL THUMBNAIL");
// NOTE: RESIZE IMAGE TO 10K PIXELS; THIS WILL ALSO FLIP AND ROTATE IMAGE AS NEEDED ImageUtil.Resize.SaveImage(openfs, 10000, savefs); } } }
System.Console.WriteLine("CREATING LUMINANCE HISTOGRAM: histogram.png");
// NOTE: CREATE HISTOGRAM WHICH IS RETURNED AS A MEMORY STREAM OF A PORTABLE NETWORK GRAPHICS (PNG) IMAGE FILE using (var histogram = ImageUtil.Histogram.CreatePNG(args[0], 300, 150, ImageUtil.Histogram.LRGB.LUMINANCE, 128)) { if (System.IO.File.Exists("histogram.png")) System.IO.File.Delete("histogram.png"); System.IO.File.WriteAllBytes("histogram.png", histogram.ToArray()); } } else System.Console.WriteLine("argument one is path to image, argument two [optional] is path to resized image"); } } }
如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。
.NETSixLabors.ImageSharpv1.0图像实用程序控制台示例由讯客互联互联网栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“.NETSixLabors.ImageSharpv1.0图像实用程序控制台示例”