using Masuit.Tools.Systems; using SixLabors.Fonts; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Drawing.Processing; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Transforms; using System; using System.IO; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace Masuit.Tools.Media { public class ImageWatermarker { /// /// 是否跳过小缩略图 /// public bool SkipWatermarkForSmallImages { get; set; } /// /// 小图像素大小 /// public int SmallImagePixelsThreshold { get; set; } public IImageEncoder ImageEncoder { get; set; } private readonly Stream _stream; /// /// /// /// 图片流 public ImageWatermarker(Stream originStream) { _stream = originStream; } /// /// /// /// 图片流 /// 指定编码器 public ImageWatermarker(Stream originStream, IImageEncoder encoder) : this(originStream) { ImageEncoder = encoder; } /// /// /// /// 图片流 /// 指定编码器 /// 是否跳过小缩略图 /// 小图像素大小 public ImageWatermarker(Stream originStream, IImageEncoder encoder, bool skipWatermarkForSmallImages, int smallImagePixelsThreshold) : this(originStream, encoder) { SkipWatermarkForSmallImages = skipWatermarkForSmallImages; SmallImagePixelsThreshold = smallImagePixelsThreshold; } /// /// 添加水印 /// /// 水印文字 /// ttf字体文件路径 /// 字体大小 /// 字体颜色 /// 水印位置 /// 水印边距 /// public PooledMemoryStream AddWatermark(string watermarkText, string ttfFontPath, int fontSize, Color color, WatermarkPosition watermarkPosition = WatermarkPosition.BottomRight, int textPadding = 10) { var fonts = new FontCollection(); var fontFamily = fonts.Add(ttfFontPath); //字体的路径(电脑自带字体库,去copy出来) var font = new Font(fontFamily, fontSize, FontStyle.Bold); return AddWatermark(watermarkText, font, color, watermarkPosition, textPadding); } /// /// 添加水印 /// /// 水印文字 /// 水印颜色 /// 水印位置 /// 边距 /// 字体 public PooledMemoryStream AddWatermark(string watermarkText, Font font, Color color, WatermarkPosition watermarkPosition = WatermarkPosition.BottomRight, int textPadding = 10) { var format = Image.DetectFormat(_stream); _stream.Seek(0, SeekOrigin.Begin); using var img = Image.Load(_stream); var textMeasure = TextMeasurer.MeasureSize(watermarkText, new TextOptions(font)); if (SkipWatermarkForSmallImages && (img.Height < Math.Sqrt(SmallImagePixelsThreshold) || img.Width < Math.Sqrt(SmallImagePixelsThreshold) || img.Width <= textMeasure.Width)) { return _stream as PooledMemoryStream ?? _stream.SaveAsMemoryStream(); } if (img.Width / font.Size > 50) { font = font.Family.CreateFont(img.Width * 1f / 50); textMeasure = TextMeasurer.MeasureSize(watermarkText, new TextOptions(font)); } float x, y; textPadding += (img.Width - 1000) / 100; switch (watermarkPosition) { case WatermarkPosition.TopRight: x = img.Width - textMeasure.Width - textPadding; y = textPadding; break; case WatermarkPosition.BottomLeft: x = textPadding; y = img.Height - textMeasure.Height - textPadding; break; case WatermarkPosition.BottomRight: x = img.Width - textMeasure.Width - textPadding; y = img.Height - textMeasure.Height - textPadding; break; case WatermarkPosition.Center: x = (img.Width - textMeasure.Width) / 2; y = (img.Height - textMeasure.Height) / 2; break; default: x = textPadding; y = textPadding; break; } img.Mutate(c => c.DrawText(watermarkText, font, color, new PointF(x, y))); var ms = new PooledMemoryStream(); if (ImageEncoder == null) { img.Save(ms, format); } else { img.Save(ms, ImageEncoder); } ms.Position = 0; return ms; } /// /// 添加水印 /// /// 水印图片 /// 透明度 /// 水印位置 /// 水印边距 /// public PooledMemoryStream AddWatermark(Stream watermarkImage, float opacity = 1f, WatermarkPosition watermarkPosition = WatermarkPosition.BottomRight, int padding = 20) { var format = Image.DetectFormat(_stream); _stream.Seek(0, SeekOrigin.Begin); using var img = Image.Load(_stream); var height = img.Height; var width = img.Width; if (SkipWatermarkForSmallImages && (height < Math.Sqrt(SmallImagePixelsThreshold) || width < Math.Sqrt(SmallImagePixelsThreshold))) { return _stream as PooledMemoryStream ?? _stream.SaveAsMemoryStream(); } var watermark = Image.Load(watermarkImage); watermark.Mutate(c => c.Resize(new ResizeOptions() { Size = new Size { Width = Math.Max(width / 10, 40), Height = Math.Max(height / 10, 40), }, Mode = ResizeMode.Min, Sampler = new BicubicResampler() })); int x, y; padding += (width - 1000) / 100; switch (watermarkPosition) { case WatermarkPosition.TopRight: x = width - watermark.Width - padding; y = padding; break; case WatermarkPosition.BottomLeft: x = padding; y = height - watermark.Height - padding; break; case WatermarkPosition.BottomRight: x = width - watermark.Width - padding; y = height - watermark.Height - padding; break; case WatermarkPosition.Center: x = (img.Width - watermark.Width) / 2; y = (img.Height - watermark.Height) / 2; break; default: x = padding; y = padding; break; } img.Mutate(c => { c.DrawImage(watermark, new Point(x, y), opacity); watermark.Dispose(); }); var ms = new PooledMemoryStream(); if (ImageEncoder == null) { img.Save(ms, format); } else { img.Save(ms, ImageEncoder); } ms.Position = 0; return ms; } public static ImageWatermarker FromStream(Stream stream) { return new ImageWatermarker(stream); } } }