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