【图片添加不同水印】批量图片添加不同的水印,将文件名批量作为图片水印添加上去的步骤和方法
2026/6/24 2:45:49 网站建设 项目流程

在设计、出版、电商等行业中,经常需要为批量图片添加个性化水印:

  1. 版权保护:为摄影作品、设计素材添加作者信息
  2. 营销推广:为产品图片添加品牌名或二维码
  3. 文档管理:为工程图纸、合同文档添加编号或版本信息
  4. 数据标注:为训练数据集添加样本 ID 或类别标签

界面设计

咕嘎批量图片添加文件名水印地址
百度网盘 : 下载地址A
腾讯网盘: 下载地址B

设计一个功能完备、视觉清晰的界面:

  1. 文件管理区:包含文件选择、预览和列表展示
  2. 水印设置区:可配置水印内容、字体、大小、颜色、透明度
  3. 位置调整区:提供九宫格定位或自由拖动调整水印位置
  4. 效果预览区:实时显示当前设置的水印效果
  5. 处理控制区:开始处理、取消和保存设置按钮
  6. 进度反馈区:显示处理进度和操作日志

详细代码步骤

以下是基于 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 ObservableCollection<ImageItem> _imageItems = new ObservableCollection<ImageItem>(); private WatermarkSettings _watermarkSettings = new WatermarkSettings(); private CancellationTokenSource _cancellationTokenSource; private bool _isDragging = false; private Point _dragStartPoint; public MainWindow() { InitializeComponent(); // 初始化字体列表 _watermarkSettings.FontFamilies = new ObservableCollection<FontFamily>( 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 ObservableCollection<FontFamily> _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 ObservableCollection<FontFamily> 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 的批量图片水印工具提供了用户友好的界面和完整的功能实现:

  1. 用户体验:直观的界面设计,支持文件拖放和实时预览,降低了使用门槛
  2. 功能完整:支持自定义水印内容、字体、大小、颜色、透明度、位置和旋转角度
  3. 性能考虑:使用异步处理避免 UI 卡顿,支持取消操作
  4. 可扩展性:配置文件支持保存和加载,方便重复使用相同设置

以下是进一步优化的建议:

  1. 多线程处理:对于大量图片,可以考虑使用并行处理提高效率
  2. 水印模板:添加预设水印模板功能,快速应用常用设置
  3. 高级图像处理:添加图像预处理功能,如自动调整对比度、亮度等
  4. 批量重命名:增加批量重命名功能,不局限于添加水印
  5. 进度保存:支持保存处理进度,中断后可以继续处理
  6. 国际化支持:添加多语言界面支持
  7. 图像处理 API:集成更多图像处理 API,提供更丰富的水印效果

使用此工具时,只需选择要处理的图片,设置好水印参数,然后选择输出位置即可。程序会自动将每张图片的文件名作为水印内容添加到图片上,并保存为新文件。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询