c#给图片添加边框
发表博文的过程中,很多博客平台背景是纯白色的,而需要发表的截图也是纯白色,导致看不到边界,体验感不好。
此时可以借助工具将图片处理后再发表到博客,增强体验感。
原始图片:

处理后:

程序截图:

程序下载地址:https://pan.quark.cn/s/5208302ebc74
程序源码Form1.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ImageShadowTool
{
public partial class MainForm : Form
{
private Panel topPanel;
private Panel centerPanel;
private Panel bottomPanel;
private Button btnSelectFiles;
private Button btnSelectFolder;
private Button btnProcess;
private Button btnClear;
private ListBox listBoxFiles;
private ProgressBar progressBar;
private Label lblProgress;
private NumericUpDown numShadowSize;
private NumericUpDown numShadowOpacity;
private Label lblShadowSize;
private Label lblShadowOpacity;
private Label lblStatus;
private Label lblTitle;
private Label lblFileCount;
private List selectedFiles = new List();
public MainForm()
{
InitializeComponent();
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);
}
private void InitializeComponent()
{
this.SuspendLayout();
// 设置窗体属性
this.Text = "图片阴影效果工具";
this.Size = new Size(700, 600);
this.StartPosition = FormStartPosition.CenterScreen;
this.FormBorderStyle = FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.BackColor = Color.FromArgb(245, 245, 245);
this.Icon = CreateIcon();
// 顶部面板
topPanel = new Panel();
topPanel.Dock = DockStyle.Top;
topPanel.Height = 120;
topPanel.BackColor = Color.FromArgb(52, 152, 219);
topPanel.Paint += TopPanel_Paint;
this.Controls.Add(topPanel);
// 标题
lblTitle = new Label();
lblTitle.Text = "图片阴影效果工具";
lblTitle.Font = new Font("微软雅黑", 16, FontStyle.Bold);
lblTitle.ForeColor = Color.White;
lblTitle.Location = new Point(30, 25);
lblTitle.Size = new Size(200, 30);
topPanel.Controls.Add(lblTitle);
// 文件计数标签
lblFileCount = new Label();
lblFileCount.Text = "未选择文件";
lblFileCount.Font = new Font("微软雅黑", 10);
lblFileCount.ForeColor = Color.White;
lblFileCount.Location = new Point(30, 65);
lblFileCount.Size = new Size(200, 20);
topPanel.Controls.Add(lblFileCount);
// 阴影大小设置
lblShadowSize = new Label();
lblShadowSize.Text = "阴影大小(像素):";
lblShadowSize.Font = new Font("微软雅黑", 9);
lblShadowSize.ForeColor = Color.White;
lblShadowSize.Location = new Point(400, 25);
lblShadowSize.Size = new Size(100, 20);
topPanel.Controls.Add(lblShadowSize);
numShadowSize = new NumericUpDown();
numShadowSize.Location = new Point(400, 50);
numShadowSize.Size = new Size(80, 25);
numShadowSize.Minimum = 5;
numShadowSize.Maximum = 50;
numShadowSize.Value = 5;
numShadowSize.Font = new Font("微软雅黑", 9);
topPanel.Controls.Add(numShadowSize);
// 阴影透明度设置
lblShadowOpacity = new Label();
lblShadowOpacity.Text = "阴影透明度(%):";
lblShadowOpacity.Font = new Font("微软雅黑", 9);
lblShadowOpacity.ForeColor = Color.White;
lblShadowOpacity.Location = new Point(520, 25);
lblShadowOpacity.Size = new Size(100, 20);
topPanel.Controls.Add(lblShadowOpacity);
NumericUpDown numShadowOpacity = new NumericUpDown();
numShadowOpacity.Location = new Point(520, 50);
numShadowOpacity.Size = new Size(80, 25);
numShadowOpacity.Minimum = 10;
numShadowOpacity.Maximum = 100;
numShadowOpacity.Value = 50;
numShadowOpacity.Font = new Font("微软雅黑", 9);
this.numShadowOpacity = numShadowOpacity;
topPanel.Controls.Add(numShadowOpacity);
// 中间区域 - 直接在主窗体上添加控件
// 选择文件按钮
btnSelectFiles = CreateStyledButton("选择图片文件", Color.FromArgb(46, 204, 113));
btnSelectFiles.Location = new Point(20, 140);
btnSelectFiles.Click += BtnSelectFiles_Click;
this.Controls.Add(btnSelectFiles);
// 选择文件夹按钮
btnSelectFolder = CreateStyledButton("选择文件夹", Color.FromArgb(155, 89, 182));
btnSelectFolder.Location = new Point(160, 140);
btnSelectFolder.Click += BtnSelectFolder_Click;
this.Controls.Add(btnSelectFolder);
// 清空按钮
btnClear = CreateStyledButton("清空列表", Color.FromArgb(231, 76, 60));
btnClear.Location = new Point(300, 140);
btnClear.Click += BtnClear_Click;
this.Controls.Add(btnClear);
// 处理按钮
btnProcess = CreateStyledButton("开始处理", Color.FromArgb(230, 126, 34));
btnProcess.Location = new Point(440, 140);
btnProcess.Size = new Size(120, 35);
btnProcess.Enabled = false;
btnProcess.Click += BtnProcess_Click;
this.Controls.Add(btnProcess);
// 文件列表 - 增大字体
listBoxFiles = new ListBox();
listBoxFiles.Location = new Point(20, 190);
listBoxFiles.Size = new Size(640, 300);
listBoxFiles.Font = new Font("微软雅黑", 12); // 从10增大到12
listBoxFiles.BorderStyle = BorderStyle.FixedSingle;
listBoxFiles.BackColor = Color.FromArgb(250, 250, 250);
listBoxFiles.SelectionMode = SelectionMode.One;
listBoxFiles.ItemHeight = 30; // 从25增大到30
listBoxFiles.DrawMode = DrawMode.OwnerDrawFixed;
listBoxFiles.DrawItem += ListBoxFiles_DrawItem;
this.Controls.Add(listBoxFiles);
// 底部面板
bottomPanel = new Panel();
bottomPanel.Dock = DockStyle.Bottom;
bottomPanel.Height = 80;
bottomPanel.BackColor = Color.FromArgb(236, 240, 241);
bottomPanel.Paint += BottomPanel_Paint;
this.Controls.Add(bottomPanel);
// 进度条
progressBar = new ProgressBar();
progressBar.Location = new Point(20, 15);
progressBar.Size = new Size(640, 20);
progressBar.Style = ProgressBarStyle.Continuous;
progressBar.ForeColor = Color.FromArgb(52, 152, 219);
bottomPanel.Controls.Add(progressBar);
// 进度标签
lblProgress = new Label();
lblProgress.Text = "准备就绪";
lblProgress.Font = new Font("微软雅黑", 9);
lblProgress.Location = new Point(20, 45);
lblProgress.Size = new Size(300, 20);
lblProgress.ForeColor = Color.FromArgb(52, 73, 94);
bottomPanel.Controls.Add(lblProgress);
// 状态标签
lblStatus = new Label();
lblStatus.Text = "请选择要处理的图片文件或文件夹";
lblStatus.Font = new Font("微软雅黑", 9);
lblStatus.Location = new Point(350, 45);
lblStatus.Size = new Size(310, 20);
lblStatus.ForeColor = Color.FromArgb(52, 152, 219);
lblStatus.TextAlign = ContentAlignment.MiddleRight;
bottomPanel.Controls.Add(lblStatus);
this.ResumeLayout(false);
}
private Button CreateStyledButton(string text, Color backColor)
{
Button btn = new Button();
btn.Text = text;
btn.Size = new Size(120, 35);
btn.BackColor = backColor;
btn.ForeColor = Color.White;
btn.FlatStyle = FlatStyle.Flat;
btn.FlatAppearance.BorderSize = 0;
btn.Font = new Font("微软雅黑", 9, FontStyle.Bold);
btn.Cursor = Cursors.Hand;
// 鼠标悬停效果
btn.MouseEnter += (s, e) => {
btn.BackColor = ControlPaint.Light(backColor, 0.2f);
};
btn.MouseLeave += (s, e) => {
btn.BackColor = backColor;
};
return btn;
}
private Icon CreateIcon()
{
// 创建一个简单的图标
Bitmap bmp = new Bitmap(16, 16);
using (Graphics g = Graphics.FromImage(bmp))
{
g.FillRectangle(new SolidBrush(Color.FromArgb(52, 152, 219)), 0, 0, 16, 16);
g.FillRectangle(new SolidBrush(Color.White), 2, 2, 12, 12);
}
return Icon.FromHandle(bmp.GetHicon());
}
private void ListBoxFiles_DrawItem(object sender, DrawItemEventArgs e)
{
if (e.Index < 0) return;
e.DrawBackground();
using (Brush brush = new SolidBrush(e.ForeColor))
{
string text = listBoxFiles.Items[e.Index].ToString();
e.Graphics.DrawString(text, e.Font, brush, e.Bounds.Left + 5, e.Bounds.Top + 7); // 调整垂直位置
}
e.DrawFocusRectangle();
}
private void TopPanel_Paint(object sender, PaintEventArgs e)
{
// 添加渐变背景
using (LinearGradientBrush brush = new LinearGradientBrush(
topPanel.ClientRectangle,
Color.FromArgb(52, 152, 219),
Color.FromArgb(41, 128, 185),
LinearGradientMode.Vertical))
{
e.Graphics.FillRectangle(brush, topPanel.ClientRectangle);
}
}
private void BottomPanel_Paint(object sender, PaintEventArgs e)
{
// 添加顶部分隔线
using (Pen pen = new Pen(Color.FromArgb(189, 195, 199), 1))
{
e.Graphics.DrawLine(pen, 0, 0, bottomPanel.Width, 0);
}
}
private void BtnSelectFiles_Click(object sender, EventArgs e)
{
using (OpenFileDialog openFileDialog = new OpenFileDialog())
{
openFileDialog.Filter = "图片文件|*.jpg;*.jpeg;*.png;*.bmp;*.gif;*.tiff|所有文件|*.*";
openFileDialog.Multiselect = true;
openFileDialog.Title = "选择图片文件";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
selectedFiles.AddRange(openFileDialog.FileNames.Where(f => !selectedFiles.Contains(f)));
UpdateFileList();
}
}
}
private void BtnSelectFolder_Click(object sender, EventArgs e)
{
using (FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog())
{
folderBrowserDialog.Description = "选择包含图片的文件夹";
if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
{
// 获取文件夹中的所有图片文件
string[] extensions = { "*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.tiff" };
foreach (string extension in extensions)
{
var files = Directory.GetFiles(folderBrowserDialog.SelectedPath, extension, SearchOption.AllDirectories);
selectedFiles.AddRange(files.Where(f => !selectedFiles.Contains(f)));
}
UpdateFileList();
}
}
}
private void BtnClear_Click(object sender, EventArgs e)
{
selectedFiles.Clear();
UpdateFileList();
}
private void UpdateFileList()
{
listBoxFiles.Items.Clear();
foreach (string file in selectedFiles)
{
string displayText = $"📷 {Path.GetFileName(file)}";
listBoxFiles.Items.Add(displayText);
}
btnProcess.Enabled = selectedFiles.Count > 0;
lblFileCount.Text = selectedFiles.Count > 0 ? $"已选择 {selectedFiles.Count} 个文件" : "未选择文件";
lblStatus.Text = selectedFiles.Count > 0 ? "准备处理" : "请选择要处理的图片文件或文件夹";
}
private async void BtnProcess_Click(object sender, EventArgs e)
{
if (selectedFiles.Count == 0)
{
MessageBox.Show("请先选择要处理的图片文件!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
// 禁用按钮防止重复点击
SetButtonsEnabled(false);
try
{
await ProcessImagesAsync();
MessageBox.Show("处理完成!", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show($"处理过程中发生错误:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
// 重新启用按钮
SetButtonsEnabled(true);
progressBar.Value = 0;
lblProgress.Text = "处理完成";
}
}
private void SetButtonsEnabled(bool enabled)
{
btnProcess.Enabled = enabled && selectedFiles.Count > 0;
btnSelectFiles.Enabled = enabled;
btnSelectFolder.Enabled = enabled;
btnClear.Enabled = enabled;
}
private async Task ProcessImagesAsync()
{
progressBar.Maximum = selectedFiles.Count;
progressBar.Value = 0;
// 创建输出目录
string outputDir = CreateOutputDirectory();
lblStatus.Text = $"输出: {Path.GetFileName(outputDir)}";
int shadowSize = (int)numShadowSize.Value;
float shadowOpacity = (float)numShadowOpacity.Value / 100f;
for (int i = 0; i < selectedFiles.Count; i++)
{
string inputFile = selectedFiles[i];
try
{
lblProgress.Text = $"正在处理: {Path.GetFileName(inputFile)} ({i + 1}/{selectedFiles.Count})";
Application.DoEvents();
await Task.Run(() => AddShadowToImage(inputFile, outputDir, shadowSize, shadowOpacity));
progressBar.Value = i + 1;
}
catch (Exception ex)
{
// 记录错误但继续处理其他文件
lblProgress.Text = $"处理 {Path.GetFileName(inputFile)} 时出错: {ex.Message}";
await Task.Delay(1000); // 显示错误信息1秒
}
}
}
private string CreateOutputDirectory()
{
// 获取第一个文件的目录作为基准
string baseDir = Path.GetDirectoryName(selectedFiles[0]);
// 创建时间戳
long timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
// 创建输出目录名
string outputDirName = $"output_{timestamp}";
string outputDir = Path.Combine(baseDir, outputDirName);
// 创建目录
Directory.CreateDirectory(outputDir);
return outputDir;
}
private void AddShadowToImage(string inputPath, string outputDir, int shadowSize, float shadowOpacity)
{
using (Image originalImage = Image.FromFile(inputPath))
{
// 计算新图片尺寸(为四周阴影留出空间)
int margin = shadowSize + 8; // 增加更多边距,为四周阴影留出空间
int newWidth = originalImage.Width + (margin * 2);
int newHeight = originalImage.Height + (margin * 2);
// 创建新图片 - 使用透明背景
using (Bitmap newImage = new Bitmap(newWidth, newHeight))
{
using (Graphics graphics = Graphics.FromImage(newImage))
{
// 设置高质量渲染
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
// 使用透明背景
graphics.Clear(Color.Transparent);
// 创建四周阴影效果
CreateShadowEffect(graphics, margin, margin, originalImage.Width, originalImage.Height, shadowSize, shadowOpacity);
// 在中心绘制原始图片
graphics.DrawImage(originalImage, margin, margin, originalImage.Width, originalImage.Height);
}
// 保存到输出目录
string fileName = Path.GetFileNameWithoutExtension(inputPath) + "_shadow" + Path.GetExtension(inputPath);
string outputPath = Path.Combine(outputDir, fileName);
// 保存为PNG以支持透明度
newImage.Save(outputPath, ImageFormat.Png);
}
}
}
private void CreateShadowEffect(Graphics graphics, int x, int y, int width, int height, int shadowSize, float opacity)
{
// 创建四周阴影效果
int shadowOffset = shadowSize / 3; // 减小偏移量,让阴影更均匀
// 创建阴影的矩形,四周都有阴影
Rectangle shadowRect = new Rectangle(x - shadowOffset, y - shadowOffset,
width + shadowOffset * 2, height + shadowOffset * 2);
// 绘制多层渐变阴影,从外到内逐渐变浅
for (int i = shadowSize; i > 0; i--)
{
// 计算当前层的透明度
float layerOpacity = opacity * (1.0f - (float)i / shadowSize) * 0.6f;
int alpha = (int)(255 * layerOpacity);
// 使用深灰色阴影
Color shadowColor = Color.FromArgb(alpha, 80, 80, 80);
using (Brush shadowBrush = new SolidBrush(shadowColor))
{
// 计算当前层的位置
int currentOffset = i;
Rectangle currentShadowRect = new Rectangle(
x - currentOffset,
y - currentOffset,
width + currentOffset * 2,
height + currentOffset * 2
);
// 绘制阴影层 - 使用路径来创建圆角效果
using (GraphicsPath shadowPath = CreateRoundedRectanglePath(currentShadowRect, 2))
{
graphics.FillPath(shadowBrush, shadowPath);
}
}
}
}
private GraphicsPath CreateRoundedRectanglePath(Rectangle rect, int radius)
{
GraphicsPath path = new GraphicsPath();
if (radius <= 0)
{
path.AddRectangle(rect);
return path;
}
// 确保圆角不超过矩形的一半
radius = Math.Min(radius, Math.Min(rect.Width, rect.Height) / 2);
// 创建圆角矩形路径
path.AddArc(rect.X, rect.Y, radius * 2, radius * 2, 180, 90); // 左上角
path.AddArc(rect.Right - radius * 2, rect.Y, radius * 2, radius * 2, 270, 90); // 右上角
path.AddArc(rect.Right - radius * 2, rect.Bottom - radius * 2, radius * 2, radius * 2, 0, 90); // 右下角
path.AddArc(rect.X, rect.Bottom - radius * 2, radius * 2, radius * 2, 90, 90); // 左下角
path.CloseAllFigures();
return path;
}
}
// Program.cs
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
}
浙公网安备 33010602011771号