cosky 发表于 2026-1-7 14:22:25

使用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]
查看完整版本: 使用DevExpressWinform实现图片水印功能(支持预设)