
在设计、出版、电商等行业中经常需要为批量图片添加个性化水印版权保护为摄影作品、设计素材添加作者信息营销推广为产品图片添加品牌名或二维码文档管理为工程图纸、合同文档添加编号或版本信息数据标注为训练数据集添加样本 ID 或类别标签界面设计咕嘎批量图片添加文件名水印地址百度网盘 : 下载地址A腾讯网盘 下载地址B设计一个功能完备、视觉清晰的界面文件管理区包含文件选择、预览和列表展示水印设置区可配置水印内容、字体、大小、颜色、透明度位置调整区提供九宫格定位或自由拖动调整水印位置效果预览区实时显示当前设置的水印效果处理控制区开始处理、取消和保存设置按钮进度反馈区显示处理进度和操作日志详细代码步骤以下是基于 WPF 实现批量图片添加文件名水印的完整代码using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; using Microsoft.Win32; using Brushes System.Windows.Media.Brushes; using FontFamily System.Windows.Media.FontFamily; using Point System.Windows.Point; namespace WatermarkApp { public partial class MainWindow : Window { private ObservableCollectionImageItem _imageItems new ObservableCollectionImageItem(); private WatermarkSettings _watermarkSettings new WatermarkSettings(); private CancellationTokenSource _cancellationTokenSource; private bool _isDragging false; private Point _dragStartPoint; public MainWindow() { InitializeComponent(); // 初始化字体列表 _watermarkSettings.FontFamilies new ObservableCollectionFontFamily( Fonts.SystemFontFamilies.OrderBy(f f.Source)); // 设置默认值 _watermarkSettings.SelectedFontFamily _watermarkSettings.FontFamilies .FirstOrDefault(f f.Source.Equals(Arial)) ?? _watermarkSettings.FontFamilies[0]; _watermarkSettings.FontSize 24; _watermarkSettings.WatermarkBrush Brushes.White; _watermarkSettings.Opacity 0.7; _watermarkSettings.RotationAngle 0; _watermarkSettings.Position WatermarkPosition.BottomRight; // 设置数据上下文 LstImages.ItemsSource _imageItems; this.DataContext _watermarkSettings; // 初始化样式 InitializeStyles(); LogMessage(欢迎使用批量图片水印工具); } private void InitializeStyles() { // 创建位置按钮样式 Style positionButtonStyle new Style(typeof(Button)); positionButtonStyle.Setters.Add(new Setter(Button.PaddingProperty, new Thickness(5))); positionButtonStyle.Setters.Add(new Setter(Button.BackgroundProperty, Brushes.LightGray)); positionButtonStyle.Setters.Add(new Setter(Button.ForegroundProperty, Brushes.Black)); positionButtonStyle.Setters.Add(new Setter(Button.BorderBrushProperty, Brushes.Gray)); positionButtonStyle.Setters.Add(new Setter(Button.BorderThicknessProperty, new Thickness(1))); positionButtonStyle.Setters.Add(new Setter(Button.MarginProperty, new Thickness(2))); Trigger selectedTrigger new Trigger(); selectedTrigger.Property Button.TagProperty; selectedTrigger.Value _watermarkSettings.Position.ToString(); selectedTrigger.Setters.Add(new Setter(Button.BackgroundProperty, Brushes.LightBlue)); positionButtonStyle.Triggers.Add(selectedTrigger); Resources.Add(PositionButtonStyle, positionButtonStyle); } private void BtnSelectImages_Click(object sender, RoutedEventArgs e) { OpenFileDialog openFileDialog new OpenFileDialog { Multiselect true, Filter 图片文件|*.jpg;*.jpeg;*.png;*.bmp;*.gif|所有文件|*.* }; if (openFileDialog.ShowDialog() true) { AddImages(openFileDialog.FileNames); } } private void AddImages(string[] filePaths) { foreach (string filePath in filePaths) { try { if (!_imageItems.Any(i i.FilePath.Equals(filePath, StringComparison.OrdinalIgnoreCase))) { ImageItem imageItem new ImageItem(filePath); _imageItems.Add(imageItem); LogMessage($已添加图片: {Path.GetFileName(filePath)}); } else { LogMessage($已跳过重复图片: {Path.GetFileName(filePath)}); } } catch (Exception ex) { LogMessage($添加图片 {Path.GetFileName(filePath)} 时出错: {ex.Message}); } } if (_imageItems.Count 0 LstImages.SelectedIndex -1) { LstImages.SelectedIndex 0; } } private void BtnClearImages_Click(object sender, RoutedEventArgs e) { _imageItems.Clear(); ImgPreview.Source null; LogMessage(已清除所有图片); } private void LstImages_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (LstImages.SelectedItem is ImageItem selectedItem) { try { BitmapImage bitmap new BitmapImage(); bitmap.BeginInit(); bitmap.CacheOption BitmapCacheOption.OnLoad; bitmap.UriSource new Uri(selectedItem.FilePath); bitmap.EndInit(); ImgPreview.Source bitmap; // 更新水印预览 UpdateWatermarkPreview(bitmap.PixelWidth, bitmap.PixelHeight); LogMessage($已加载图片预览: {selectedItem.FileName}); } catch (Exception ex) { LogMessage($加载图片预览时出错: {ex.Message}); } } } private void UpdateWatermarkPreview(int imageWidth, int imageHeight) { if (string.IsNullOrEmpty(_watermarkSettings.WatermarkText)) return; // 计算水印文本的大小 FormattedText formattedText new FormattedText( _watermarkSettings.WatermarkText, System.Globalization.CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, new Typeface(_watermarkSettings.SelectedFontFamily, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal), _watermarkSettings.FontSize, _watermarkSettings.WatermarkBrush, VisualTreeHelper.GetDpi(this).PixelsPerDip); // 根据位置计算水印位置 double x 0, y 0; switch (_watermarkSettings.Position) { case WatermarkPosition.TopLeft: x 10; y 10; break; case WatermarkPosition.TopCenter: x (imageWidth - formattedText.Width) / 2; y 10; break; case WatermarkPosition.TopRight: x imageWidth - formattedText.Width - 10; y 10; break; case WatermarkPosition.MiddleLeft: x 10; y (imageHeight - formattedText.Height) / 2; break; case WatermarkPosition.MiddleCenter: x (imageWidth - formattedText.Width) / 2; y (imageHeight - formattedText.Height) / 2; break; case WatermarkPosition.MiddleRight: x imageWidth - formattedText.Width - 10; y (imageHeight - formattedText.Height) / 2; break; case WatermarkPosition.BottomLeft: x 10; y imageHeight - formattedText.Height - 10; break; case WatermarkPosition.BottomCenter: x (imageWidth - formattedText.Width) / 2; y imageHeight - formattedText.Height - 10; break; case WatermarkPosition.BottomRight: x imageWidth - formattedText.Width - 10; y imageHeight - formattedText.Height - 10; break; } // 设置水印位置 Canvas.SetLeft(TxtPreviewWatermark, x); Canvas.SetTop(TxtPreviewWatermark, y); } private void PositionButton_Click(object sender, RoutedEventArgs e) { if (sender is Button button Enum.TryParse(button.Tag.ToString(), out WatermarkPosition position)) { _watermarkSettings.Position position; // 更新按钮样式 Style positionButtonStyle Resources[PositionButtonStyle] as Style; foreach (var item in UniformGrid.Children) { if (item is Button btn) { btn.Style positionButtonStyle; } } // 更新预览 if (ImgPreview.Source is BitmapSource bitmapSource) { UpdateWatermarkPreview(bitmapSource.PixelWidth, bitmapSource.PixelHeight); } } } private void PreviewCanvas_MouseDown(object sender, MouseButtonEventArgs e) { if (e.OriginalSource TxtPreviewWatermark e.LeftButton MouseButtonState.Pressed) { _isDragging true; _dragStartPoint e.GetPosition(PreviewCanvas); PreviewCanvas.CaptureMouse(); } } private void PreviewCanvas_MouseMove(object sender, MouseEventArgs e) { if (_isDragging) { Point currentPoint e.GetPosition(PreviewCanvas); double offsetX currentPoint.X - _dragStartPoint.X; double offsetY currentPoint.Y - _dragStartPoint.Y; double newLeft Canvas.GetLeft(TxtPreviewWatermark) offsetX; double newTop Canvas.GetTop(TxtPreviewWatermark) offsetY; // 确保水印在画布内 if (newLeft 0 newLeft TxtPreviewWatermark.ActualWidth PreviewCanvas.ActualWidth) Canvas.SetLeft(TxtPreviewWatermark, newLeft); if (newTop 0 newTop TxtPreviewWatermark.ActualHeight PreviewCanvas.ActualHeight) Canvas.SetTop(TxtPreviewWatermark, newTop); _dragStartPoint currentPoint; // 更新为自定义位置 _watermarkSettings.Position WatermarkPosition.Custom; } } private void PreviewCanvas_MouseUp(object sender, MouseButtonEventArgs e) { _isDragging false; PreviewCanvas.ReleaseMouseCapture(); } private void RectColor_MouseDown(object sender, MouseButtonEventArgs e) { if (e.LeftButton MouseButtonState.Pressed) { // 简单的颜色选择对话框 ColorDialog colorDialog new ColorDialog(); if (colorDialog.ShowDialog() true) { _watermarkSettings.WatermarkBrush new SolidColorBrush(colorDialog.SelectedColor); } } } private async void BtnProcess_Click(object sender, RoutedEventArgs e) { if (_imageItems.Count 0) { MessageBox.Show(请先选择要处理的图片, 提示, MessageBoxButton.OK, MessageBoxImage.Information); return; } SaveFileDialog saveFileDialog new SaveFileDialog { Filter 图片文件|*.jpg;*.jpeg;*.png;*.bmp;*.gif|所有文件|*.*, Title 选择保存位置和文件名模式, FileName watermarked_{0} }; if (saveFileDialog.ShowDialog() ! true) return; string outputPath Path.GetDirectoryName(saveFileDialog.FileName); string fileNamePattern Path.GetFileNameWithoutExtension(saveFileDialog.FileName); string fileExtension Path.GetExtension(saveFileDialog.FileName); BtnProcess.IsEnabled false; BtnCancel.IsEnabled true; _cancellationTokenSource new CancellationTokenSource(); LogMessage($开始处理 {_imageItems.Count} 张图片...); try { await ProcessImagesAsync(outputPath, fileNamePattern, fileExtension, _cancellationTokenSource.Token); LogMessage(所有图片处理完成!); } catch (OperationCanceledException) { LogMessage(处理已取消); } catch (Exception ex) { LogMessage($处理过程中出错: {ex.Message}); } finally { BtnProcess.IsEnabled true; BtnCancel.IsEnabled false; _cancellationTokenSource null; } } private async Task ProcessImagesAsync(string outputPath, string fileNamePattern, string fileExtension, CancellationToken cancellationToken) { await Task.Run(() { int processedCount 0; foreach (var imageItem in _imageItems) { if (cancellationToken.IsCancellationRequested) throw new OperationCanceledException(); try { // 从文件名获取水印内容不包含扩展名 string watermarkText Path.GetFileNameWithoutExtension(imageItem.FileName); // 处理图片并添加水印 string outputFilePath Path.Combine(outputPath, string.Format(fileNamePattern, watermarkText) fileExtension); AddWatermarkToImage(imageItem.FilePath, outputFilePath, watermarkText); processedCount; Application.Current.Dispatcher.Invoke(() { LogMessage($已处理 ({processedCount}/{_imageItems.Count}): {imageItem.FileName} - {Path.GetFileName(outputFilePath)}); }); } catch (Exception ex) { string errorMessage $处理图片 {imageItem.FileName} 时出错: {ex.Message}; Application.Current.Dispatcher.Invoke(() { LogMessage(errorMessage); }); } } }, cancellationToken); } private void AddWatermarkToImage(string inputPath, string outputPath, string watermarkText) { using (Bitmap originalImage new Bitmap(inputPath)) { using (Graphics graphics Graphics.FromImage(originalImage)) { // 设置字体 System.Drawing.Font font new System.Drawing.Font( _watermarkSettings.SelectedFontFamily.Source, (float)_watermarkSettings.FontSize, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Pixel); // 计算文本大小 SizeF textSize graphics.MeasureString(watermarkText, font); // 计算位置 float x 0, y 0; switch (_watermarkSettings.Position) { case WatermarkPosition.TopLeft: x 10; y 10; break; case WatermarkPosition.TopCenter: x (originalImage.Width - textSize.Width) / 2; y 10; break; case WatermarkPosition.TopRight: x originalImage.Width - textSize.Width - 10; y 10; break; case WatermarkPosition.MiddleLeft: x 10; y (originalImage.Height - textSize.Height) / 2; break; case WatermarkPosition.MiddleCenter: x (originalImage.Width - textSize.Width) / 2; y (originalImage.Height - textSize.Height) / 2; break; case WatermarkPosition.MiddleRight: x originalImage.Width - textSize.Width - 10; y (originalImage.Height - textSize.Height) / 2; break; case WatermarkPosition.BottomLeft: x 10; y originalImage.Height - textSize.Height - 10; break; case WatermarkPosition.BottomCenter: x (originalImage.Width - textSize.Width) / 2; y originalImage.Height - textSize.Height - 10; break; case WatermarkPosition.BottomRight: x originalImage.Width - textSize.Width - 10; y originalImage.Height - textSize.Height - 10; break; case WatermarkPosition.Custom: // 使用预览中的自定义位置 x (float)Canvas.GetLeft(TxtPreviewWatermark); y (float)Canvas.GetTop(TxtPreviewWatermark); break; } // 创建透明画笔 SolidColorBrush brush new SolidColorBrush(System.Drawing.Color.FromArgb( (int)(_watermarkSettings.Opacity * 255), ((SolidColorBrush)_watermarkSettings.WatermarkBrush).Color.R, ((SolidColorBrush)_watermarkSettings.WatermarkBrush).Color.G, ((SolidColorBrush)_watermarkSettings.WatermarkBrush).Color.B)); // 如果需要旋转创建旋转矩阵 if (_watermarkSettings.RotationAngle ! 0) { graphics.TranslateTransform(x textSize.Width / 2, y textSize.Height / 2); graphics.RotateTransform((float)_watermarkSettings.RotationAngle); graphics.TranslateTransform(-(x textSize.Width / 2), -(y textSize.Height / 2)); // 旋转后重新计算绘制位置 x (originalImage.Width - textSize.Width) / 2; y (originalImage.Height - textSize.Height) / 2; } // 绘制水印 graphics.DrawString(watermarkText, font, brush, x, y); } // 保存图片 ImageFormat format GetImageFormat(outputPath); originalImage.Save(outputPath, format); } } private ImageFormat GetImageFormat(string filePath) { string extension Path.GetExtension(filePath).ToLower(); switch (extension) { case .jpg: case .jpeg: return ImageFormat.Jpeg; case .png: return ImageFormat.Png; case .bmp: return ImageFormat.Bmp; case .gif: return ImageFormat.Gif; case .tif: case .tiff: return ImageFormat.Tiff; default: return ImageFormat.Jpeg; } } private void BtnCancel_Click(object sender, RoutedEventArgs e) { _cancellationTokenSource?.Cancel(); } private void LogMessage(string message) { TxtLog.AppendText($[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}{Environment.NewLine}); TxtLog.ScrollToEnd(); } private void MenuItemSelectImages_Click(object sender, RoutedEventArgs e) { BtnSelectImages_Click(sender, e); } private void MenuItemClearImages_Click(object sender, RoutedEventArgs e) { BtnClearImages_Click(sender, e); } private void MenuItemExit_Click(object sender, RoutedEventArgs e) { Close(); } private void MenuItemWatermarkSettings_Click(object sender, RoutedEventArgs e) { // 显示水印设置对话框 WatermarkSettingsDialog settingsDialog new WatermarkSettingsDialog(_watermarkSettings); settingsDialog.Owner this; if (settingsDialog.ShowDialog() true) { // 更新预览 if (ImgPreview.Source is BitmapSource bitmapSource) { UpdateWatermarkPreview(bitmapSource.PixelWidth, bitmapSource.PixelHeight); } LogMessage(水印设置已更新); } } private void MenuItemSaveSettings_Click(object sender, RoutedEventArgs e) { SaveFileDialog saveFileDialog new SaveFileDialog { Filter 配置文件|*.xml|所有文件|*.*, Title 保存水印配置, FileName watermark_settings.xml }; if (saveFileDialog.ShowDialog() true) { try { _watermarkSettings.SaveToFile(saveFileDialog.FileName); LogMessage($配置已保存到: {saveFileDialog.FileName}); } catch (Exception ex) { LogMessage($保存配置时出错: {ex.Message}); } } } private void MenuItemLoadSettings_Click(object sender, RoutedEventArgs e) { OpenFileDialog openFileDialog new OpenFileDialog { Filter 配置文件|*.xml|所有文件|*.*, Title 加载水印配置 }; if (openFileDialog.ShowDialog() true) { try { _watermarkSettings.LoadFromFile(openFileDialog.FileName); // 更新UI绑定 BindingOperations.GetBindingExpression(TxtWatermarkText, TextBox.TextProperty)?.UpdateTarget(); BindingOperations.GetBindingExpression(CboFontFamily, ComboBox.SelectedItemProperty)?.UpdateTarget(); BindingOperations.GetBindingExpression(SldFontSize, Slider.ValueProperty)?.UpdateTarget(); BindingOperations.GetBindingExpression(RectColor, Rectangle.FillProperty)?.UpdateTarget(); BindingOperations.GetBindingExpression(SldOpacity, Slider.ValueProperty)?.UpdateTarget(); BindingOperations.GetBindingExpression(SldRotation, Slider.ValueProperty)?.UpdateTarget(); // 更新预览 if (ImgPreview.Source is BitmapSource bitmapSource) { UpdateWatermarkPreview(bitmapSource.PixelWidth, bitmapSource.PixelHeight); } LogMessage($已加载配置: {openFileDialog.FileName}); } catch (Exception ex) { LogMessage($加载配置时出错: {ex.Message}); } } } private void MenuItemAbout_Click(object sender, RoutedEventArgs e) { MessageBox.Show(批量图片水印工具 v1.0\n\n 用于批量为图片添加水印的工具支持将文件名作为水印内容。\n\n 功能特点\n - 批量处理多张图片\n - 自定义水印内容、字体、大小、颜色和透明度\n - 支持多种水印位置和旋转角度\n - 实时预览水印效果\n - 保存和加载水印配置, 关于, MessageBoxButton.OK, MessageBoxImage.Information); } } public class ImageItem { public string FilePath { get; set; } public string FileName { get; set; } public BitmapSource Thumbnail { get; set; } public ImageItem(string filePath) { FilePath filePath; FileName Path.GetFileName(filePath); // 创建缩略图 try { BitmapImage bitmap new BitmapImage(); bitmap.BeginInit(); bitmap.CacheOption BitmapCacheOption.OnLoad; bitmap.CreateOptions BitmapCreateOptions.IgnoreImageCache; bitmap.UriSource new Uri(filePath); bitmap.DecodePixelWidth 100; bitmap.EndInit(); Thumbnail bitmap; } catch { // 如果加载图片失败使用默认图标 Thumbnail new BitmapImage(new Uri(pack://application:,,,/Resources/DefaultImage.png)); } } } public class WatermarkSettings : System.ComponentModel.INotifyPropertyChanged { private string _watermarkText; private ObservableCollectionFontFamily _fontFamilies; private FontFamily _selectedFontFamily; private double _fontSize; private Brush _watermarkBrush; private double _opacity; private double _rotationAngle; private WatermarkPosition _position; public string WatermarkText { get _watermarkText; set { if (_watermarkText ! value) { _watermarkText value; OnPropertyChanged(nameof(WatermarkText)); } } } public ObservableCollectionFontFamily FontFamilies { get _fontFamilies; set { if (_fontFamilies ! value) { _fontFamilies value; OnPropertyChanged(nameof(FontFamilies)); } } } public FontFamily SelectedFontFamily { get _selectedFontFamily; set { if (_selectedFontFamily ! value) { _selectedFontFamily value; OnPropertyChanged(nameof(SelectedFontFamily)); } } } public double FontSize { get _fontSize; set { if (_fontSize ! value) { _fontSize value; OnPropertyChanged(nameof(FontSize)); } } } public Brush WatermarkBrush { get _watermarkBrush; set { if (_watermarkBrush ! value) { _watermarkBrush value; OnPropertyChanged(nameof(WatermarkBrush)); } } } public double Opacity { get _opacity; set { if (_opacity ! value) { _opacity value; OnPropertyChanged(nameof(Opacity)); } } } public double RotationAngle { get _rotationAngle; set { if (_rotationAngle ! value) { _rotationAngle value; OnPropertyChanged(nameof(RotationAngle)); } } } public WatermarkPosition Position { get _position; set { if (_position ! value) { _position value; OnPropertyChanged(nameof(Position)); } } } public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); } public void SaveToFile(string filePath) { using (System.Xml.XmlWriter writer System.Xml.XmlWriter.Create(filePath)) { writer.WriteStartDocument(); writer.WriteStartElement(WatermarkSettings); writer.WriteElementString(WatermarkText, WatermarkText); writer.WriteElementString(SelectedFontFamily, SelectedFontFamily.Source); writer.WriteElementString(FontSize, FontSize.ToString()); if (WatermarkBrush is SolidColorBrush solidColorBrush) { writer.WriteStartElement(WatermarkColor); writer.WriteAttributeString(R, solidColorBrush.Color.R.ToString()); writer.WriteAttributeString(G, solidColorBrush.Color.G.ToString()); writer.WriteAttributeString(B, solidColorBrush.Color.B.ToString()); writer.WriteEndElement(); } writer.WriteElementString(Opacity, Opacity.ToString()); writer.WriteElementString(RotationAngle, RotationAngle.ToString()); writer.WriteElementString(Position, Position.ToString()); writer.WriteEndElement(); writer.WriteEndDocument(); } } public void LoadFromFile(string filePath) { using (System.Xml.XmlReader reader System.Xml.XmlReader.Create(filePath)) { while (reader.Read()) { if (reader.IsStartElement()) { switch (reader.Name) { case WatermarkText: WatermarkText reader.ReadString(); break; case SelectedFontFamily: string fontFamilyName reader.ReadString(); SelectedFontFamily FontFamilies.FirstOrDefault(f f.Source fontFamilyName) ?? FontFamilies[0]; break; case FontSize: if (double.TryParse(reader.ReadString(), out double fontSize)) FontSize fontSize; break; case WatermarkColor: byte r 255, g 255, b 255; if (reader.HasAttributes) { while (reader.MoveToNextAttribute()) { switch (reader.Name) { case R: byte.TryParse(reader.Value, out r); break; case G: byte.TryParse(reader.Value, out g); break; case B: byte.TryParse(reader.Value, out b); break; } } reader.MoveToElement(); } WatermarkBrush new SolidColorBrush(System.Windows.Media.Color.FromRgb(r, g, b)); reader.Skip(); break; case Opacity: if (double.TryParse(reader.ReadString(), out double opacity)) Opacity opacity; break; case RotationAngle: if (double.TryParse(reader.ReadString(), out double rotationAngle)) RotationAngle rotationAngle; break; case Position: if (Enum.TryParse(reader.ReadString(), out WatermarkPosition position)) Position position; break; } } } } } } public enum WatermarkPosition { TopLeft, TopCenter, TopRight, MiddleLeft, MiddleCenter, MiddleRight, BottomLeft, BottomCenter, BottomRight, Custom } }总结与优化这个基于 WPF 的批量图片水印工具提供了用户友好的界面和完整的功能实现用户体验直观的界面设计支持文件拖放和实时预览降低了使用门槛功能完整支持自定义水印内容、字体、大小、颜色、透明度、位置和旋转角度性能考虑使用异步处理避免 UI 卡顿支持取消操作可扩展性配置文件支持保存和加载方便重复使用相同设置以下是进一步优化的建议多线程处理对于大量图片可以考虑使用并行处理提高效率水印模板添加预设水印模板功能快速应用常用设置高级图像处理添加图像预处理功能如自动调整对比度、亮度等批量重命名增加批量重命名功能不局限于添加水印进度保存支持保存处理进度中断后可以继续处理国际化支持添加多语言界面支持图像处理 API集成更多图像处理 API提供更丰富的水印效果使用此工具时只需选择要处理的图片设置好水印参数然后选择输出位置即可。程序会自动将每张图片的文件名作为水印内容添加到图片上并保存为新文件。