使用DevExpressWinform实现图片水印功能(支持预设)
本帖最后由 cosky 于 2026-3-1 18:02 编辑图片演示:
步骤一:
在DevExpress图片编辑器中的工具栏中插入两个自定义按钮,用来打开水印编辑器和预设水印应用(如图)。
代码如下:
pictureEdit1.ImageEditorDialogShowing += (sender, e) =>
{
//添加水印命令(需要准备两张svg图片作为按钮图片)
e.Commands.Insert(0, new WatermarkCommand() { Image = svgImages });
e.Commands.Insert(1, new WatermarkPreset() { Image = svgImages });
//添加裁切比例,这个不重要和水印功能无关,也可以删掉
e.Form.CustomizeCropOptions += CustomizeCropOptions;
};
void CustomizeCropOptions(object sender, CustomizeCropOptionsEventArgs e)
{
var widescreen = new AspectRatioInfo(1.777f, "16:9");
var standard = new AspectRatioInfo(1.333f, "4:3");
//e.AspectRatios.Clear();
e.AspectRatios.Add(widescreen);
e.AspectRatios.Add(standard);
e.DefaultAspectRatio = widescreen;
}
准备就绪后点击按钮显示图片编辑器
void btnShowImageEditor_Click(object sender, EventArgs e)
{
pictureEdit1.ShowImageEditorDialog();
}
打开编辑器后我们可以看到顶部工具栏上添加了两个按钮(如下图)
第一个按钮是打开水印编辑功能,第二个按钮是应用预设的水印功能。
public class WatermarkCommand : IGraphicCommand
{
public virtual SvgImage Image
{
get;
set;
}
public virtual string ToolTip
{
get { return "添加自定义水印"; }
}
public virtual void Execute(ImageEditorControl editorControl)
{
editorControl.SetActiveTool(new WatermarkToolControl()); //设置活动工具栏为自定义的工具栏
}
}
预设水印功能很简单,核心代码如下
public class WatermarkPreset : WatermarkCommand
{
public override string ToolTip
{
get { return "添加预设水印"; } //设置预设按钮的工具提示
}
public override void Execute(ImageEditorControl editorControl)
{
//使用EditController在代码中执行WatermarkGraphicOperation操作。 当图像编辑器处于活动状态时,用户可以使用Ctrl+Z撤消此操作。
//WatermarkGraphicOperation构 造参数为(水印文字,文字颜色,字体大小,垂直方向间隔,水平方向间隔,文字旋转角度,文字位置偏移量)
editorControl.EditController.DoOperation(new WatermarkGraphicOperation("DXPER.NET", Color.LightBlue, 28, 128, 200, -45, 0, Point.Empty));
}
}
接下来我们需要新建一个自定义控件作为设置水印的工具栏,布局如图:
在WatermarkToolControl控件构造函数中 首先我们要注册几个事件,作用是当工具栏中的值发生变动时实时应用水印样式,代码也非常简单。
public WatermarkToolControl()
{
InitializeComponent();
teText.TextChanged += (s, e) => RaiseChanged();
cpeColor.EditValueChanged += (s, e) => RaiseChanged();
seFontSize.EditValueChanged += (s, e) => RaiseChanged();
trackIntervalY.ValueChanged += (s, e) => RaiseChanged();
trackIntervalX.ValueChanged += (s, e) => RaiseChanged();
trackDrawAngle.ValueChanged += (s, e) => RaiseChanged();
txtOffset.Validated += (s, e) => RaiseChanged();
cobPosition.SelectedIndexChanged += (s, e) =>
{
if (cobPosition.SelectedIndex == 0)
{
panelTile.Visible = true;
panelFixed.Visible = false;
}
else if (cobPosition.SelectedIndex == 1)
{
panelTile.Visible = false;
panelFixed.Visible = false;
}
else
{
panelTile.Visible = false;
panelFixed.Visible = true;
}
RaiseChanged();
};
}
// 可以在此自定义初始样式
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
teText.Text = "DXPER.NET";
cpeColor.Color = Color.FromArgb(180, Color.Silver);
seFontSize.SelectedIndex = 5;
cobPosition.SelectedIndex = 0;
}
public BaseGraphicOperation GetOperation()
{
if (!int.TryParse(seFontSize.Text, out int fontSize)) fontSize = 30;
Point offset = Point.Empty;
if (cobPosition.SelectedIndex > 1)
{
TypeConverter converter = TypeDescriptor.GetConverter(typeof(Point));
offset = (Point)converter.ConvertFromString(txtOffset.Text);
}
return new WatermarkGraphicOperation(teText.Text, cpeColor.Color, fontSize, trackIntervalY.Value, trackIntervalX.Value, trackDrawAngle.Value, cobPosition.SelectedIndex, offset);
}
核心水印绘制操作如下:
public class WatermarkGraphicOperation : BaseCachedGraphicOperation
{
public string Text { get; protected set; }
public Color Color { get; protected set; }
public int Position { get; protected set; }
public int FontSize { get; protected set; }
public int IntervalY { get; protected set; }
public int IntervalX { get; protected set; }
public int DrawAngle { get; protected set; }
public Point Offset { get; protected set; }
public WatermarkGraphicOperation(string text, Color color, int fontSize, int intervalY, int intervalX, int drawAngle, int position, Point offset)
{
this.Text = text;
this.FontSize = fontSize;
this.Color = color;
this.Position = position;
this.IntervalY = intervalY;
this.IntervalX = intervalX;
this.DrawAngle = drawAngle;
this.Offset = offset;
}
public override Image Apply(Image input)
{
Image newImg = new Bitmap(input);
if (!string.IsNullOrEmpty(Text))
{
using (Graphics g = Graphics.FromImage(newImg))
{
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
using (Font font = new Font("Microsoft Yahei", FontSize))
{
using (SolidBrush brush = new SolidBrush(this.Color))
{
RectangleF rect;
switch (Position)
{
case 1: //居中
rect = new RectangleF(0, 0, input.Width, input.Height);
using (StringFormat format = new StringFormat())
{
format.Alignment = StringAlignment.Center;
format.LineAlignment = StringAlignment.Center;
g.DrawString(Text, font, brush, rect, format);
}
break;
case 2: //左上角
rect = new RectangleF(Offset.X, Offset.Y, input.Width, input.Height);
using (StringFormat format = new StringFormat())
{
format.Alignment = StringAlignment.Near;
format.LineAlignment = StringAlignment.Near;
g.DrawString(Text, font, brush, rect, format);
}
break;
case 3: //右上角
rect = new RectangleF(0, 20, input.Width - Offset.X, input.Height);
using (StringFormat format = new StringFormat())
{
format.Alignment = StringAlignment.Far;
format.LineAlignment = StringAlignment.Near;
g.DrawString(Text, font, brush, rect, format);
}
break;
case 4: //左下角
rect = new RectangleF(20, 0, input.Width, input.Height - Offset.Y);
using (StringFormat format = new StringFormat())
{
format.Alignment = StringAlignment.Near;
format.LineAlignment = StringAlignment.Far;
g.DrawString(Text, font, brush, rect, format);
}
break;
case 5: //右下角
rect = new RectangleF(0, 0, input.Width - Offset.X, input.Height - Offset.Y);
using (StringFormat format = new StringFormat())
{
format.Alignment = StringAlignment.Far;
format.LineAlignment = StringAlignment.Far;
g.DrawString(Text, font, brush, rect, format);
}
break;
default: //平铺
float centerX = ((float)newImg.Width / 2);
float centerY = ((float)newImg.Height / 2);
g.TranslateTransform(centerX, centerY);
g.RotateTransform(DrawAngle);
g.TranslateTransform(-centerX, -centerY);
Size textSize = g.MeasureString(Text, font).ToSize();
int max = Math.Max(newImg.Width, newImg.Height);
int start = -Math.Abs(newImg.Width - newImg.Height);
for (int y = start; y < max; y += textSize.Height + IntervalY)
{
for (int x = start - (textSize.Width / 2); x < max; x += textSize.Width + IntervalX)
{
g.DrawString(Text, font, brush, new PointF(x, y));
}
}
break;
}
}
}
}
}
return newImg;
}
}
完整项目代码代码:
(环境.NetFramework4.8 + DevExpress24.2)
页:
[1]