C# 绘制印章
最近有个.net core的项目要绘制印章功能,一个公司印章,一个个人印章,于是抽了点时间自己写了一个,现在分享出来
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; using System.Text; namespace DemoConsole { public class SealHelper { public static MechanismSealHelper Mechanism() { return new MechanismSealHelper(); } public static PersonalSealHelper Personal() { return new PersonalSealHelper(); } public class MechanismSealHelper : IDisposable { string star = "★"; int size = 160; Image map; Graphics g; int defaultWidth; float defaultStarSize; float defaultTitleSize; float defaultHorizontalSize; float defaultChordSize; public Color Color { get; set; } = Color.Red; public string DefaultFontName { get; set; } = "SimSun"; public MechanismSealHelper() { map = new Bitmap(size, size); g = Graphics.FromImage(map);//实例化Graphics类 g.SmoothingMode = SmoothingMode.AntiAlias; //System.Drawing.Drawing2D; g.Clear(Color.Transparent); defaultWidth = size / 40; defaultStarSize = size / 5; defaultTitleSize = (float)Math.Sqrt(size); defaultHorizontalSize = (float)Math.Sqrt(size); defaultChordSize = size / 20; } /// <summary> /// 绘制圆 /// </summary> public void DrawCircle() { DrawCircle(defaultWidth); } /// <summary> /// 绘制圆 /// </summary> /// <param name="width">画笔粗细</param> public void DrawCircle(int width) { Rectangle rect = new Rectangle(width, width, size - width * 2, size - width * 2);//设置圆的绘制区域 Pen pen = new Pen(Color, width); //设置画笔(颜色和粗细) g.DrawEllipse(pen, rect); //绘制圆 } /// <summary> /// 绘制星星 /// </summary> public void DrawStar() { DrawStar(defaultStarSize, defaultWidth); } /// <summary> /// 绘制星星 /// </summary> /// <param name="emSize"></param> public void DrawStar(float emSize) { DrawStar(emSize, defaultWidth); } /// <summary> /// 绘制星星 /// </summary> /// <param name="emSize">字体大小</param> /// <param name="width">画笔粗细</param> public void DrawStar(float emSize, int width) { Font starFont = new Font(DefaultFontName, emSize, FontStyle.Bold);//设置星号的字体样式 var starSize = g.MeasureString(star, starFont);//对指定字符串进行测量 //要指定的位置绘制星号 PointF starXy = new PointF(size / 2 - starSize.Width / 2, size / 2 - starSize.Height / 2); g.DrawString(star, starFont, new SolidBrush(Color), starXy); } /// <summary> /// 绘制主题 /// </summary> /// <param name="title">主题(公司名称)</param> /// <param name="startAngle">开始角度</param> public void DrawTitle(string title, float startAngle = 160) { DrawTitle(title, startAngle, defaultTitleSize); } /// <summary> /// 绘制主题 /// </summary> /// <param name="title">主题(公司名称)</param> /// <param name="startAngle">开始角度,必须是左半边,推荐(135-270)</param> /// <param name="emSize">字体大小</param> public void DrawTitle(string title, float startAngle, float emSize) { DrawTitle(title, startAngle, emSize, defaultWidth); } /// <summary> /// 绘制主题 /// </summary> /// <param name="title">主题(公司名称)</param> /// <param name="startAngle">开始角度,必须是左半边,推荐(135-270)</param> /// <param name="emSize">字体大小</param> /// <param name="width">画笔粗细</param> public void DrawTitle(string title, float startAngle, float emSize, int width) { Font font = new Font(DefaultFontName, emSize, FontStyle.Bold); DrawTitle(title, startAngle, font, width); } /// <summary> /// 绘制主题 /// </summary> /// <param name="title">主题(公司名称)</param> /// <param name="startAngle">开始角度,必须是左半边,推荐(135-270)</param> /// <param name="font">字体</param> /// <param name="width">画笔粗细</param> public void DrawTitle(string title, float startAngle, Font font, int width) { if (string.IsNullOrEmpty(title)) { return; } if (Math.Cos(startAngle / 180 * Math.PI) > 0) { throw new ArgumentException($"初始角度错误:{startAngle}(建议135-270)", nameof(startAngle)); } startAngle = startAngle % 360;//起始角度 var length = title.Length; float changeAngle = (270 - startAngle) * 2 / length;//每个字所占的角度,也就是旋转角度 var circleWidth = size / 2 - width * 3;//字体圆形的长度 var fontSize = g.MeasureString(title, font);//测量一下字体 var per = fontSize.Width / length;//每个字体的长度 //在指定的角度绘制字符 void action(string t, float a) { var angleXy = a / 180 * Math.PI; var x = size / 2 + Math.Cos(angleXy) * circleWidth; var y = size / 2 + Math.Sin(angleXy) * circleWidth; DrawChar(t, (float)x, (float)y, a + 90, font, width); } //起始绘制角度=起始角度+旋转角度/2-字体所占角度的一半 var angle = startAngle + changeAngle / 2 - (float)(Math.Asin(per / 2 / circleWidth) / Math.PI * 180);//起始绘制角度 for (var i = 0; i < length; i++) { action(title[i].ToString(), angle); angle += changeAngle; } } /// <summary> /// 绘制横向文 /// </summary> /// <param name="text">横向文</param> public void DrawHorizontal(string text) { DrawHorizontal(text, defaultHorizontalSize); } /// <summary> /// 绘制横向文 /// </summary> /// <param name="text">横向文</param> /// <param name="emSize">字体大小</param> public void DrawHorizontal(string text, float emSize) { Font font = new Font(DefaultFontName, emSize, FontStyle.Bold);//定义字体的字体样式 DrawHorizontal(text, font); } /// <summary> /// 绘制横向文 /// </summary> /// <param name="text">横向文</param> /// <param name="font">字体</param> public void DrawHorizontal(string text, Font font) { int length = text.Length; SizeF textSize = g.MeasureString(text, font);//对指定字符串进行测量 while (textSize.Width > size * 2 / 3) { DrawHorizontal(text, new Font(font.Name, font.Size - 1, font.Style)); return; } //要指定的位置绘制中间文字 PointF point = new PointF(size / 2 - textSize.Width / 2, size * 2 / 3); g.ResetTransform(); g.DrawString(text, font, new SolidBrush(Color), point); } /// <summary> /// 绘制下弦文 /// </summary> /// <param name="text">下弦文</param> /// <param name="startAngle">开始角度,必须是左下半边,推荐(90-180)</param> public void DrawChord(string text, float startAngle = 135) { DrawChord(text, startAngle, defaultChordSize); } /// <summary> /// 绘制下弦文 /// </summary> /// <param name="text">下弦文</param> /// <param name="startAngle">开始角度,必须是左下半边,推荐(90-180)</param> /// <param name="emSize">字体大小</param> public void DrawChord(string text, float startAngle, float emSize) { DrawChord(text, startAngle, emSize, defaultWidth); } /// <summary> /// 绘制下弦文 /// </summary> /// <param name="text">下弦文</param> /// <param name="startAngle">开始角度,必须是左下半边,推荐(90-180)</param> /// <param name="emSize">字体大小</param> /// <param name="width">画笔粗细</param> public void DrawChord(string text, float startAngle, float emSize, int width) { Font font = new Font(DefaultFontName, emSize, FontStyle.Bold);//定义字体的字体样式 DrawChord(text, startAngle, font, width); } /// <summary> /// 绘制下弦文 /// </summary> /// <param name="text">下弦文</param> /// <param name="startAngle">开始角度,必须是左下半边,推荐(90-180)</param> /// <param name="font">字体</param> /// <param name="width">画笔粗细</param> public void DrawChord(string text, float startAngle, Font font, int width) { if (string.IsNullOrEmpty(text)) { return; } if (Math.Cos(startAngle / 180 * Math.PI) > 0) { throw new ArgumentException($"初始角度错误:{startAngle}(建议90-135)", nameof(startAngle)); } startAngle = startAngle % 360;//起始角度 var length = text.Length; float changeAngle = (startAngle - 90) * 2 / length;//每个字所占的角度,也就是旋转角度 var fontSize = g.MeasureString(text, font);//测量一下字体 var per = fontSize.Width / length;//每个字体的长度 var circleWidth = size / 2 - width * 2 - fontSize.Height;//字体圆形的长度 //在指定的角度绘制字符 void action(string t, float a) { var angleXy = a / 180 * Math.PI; var x = size / 2 + Math.Cos(angleXy) * circleWidth; var y = size / 2 + Math.Sin(angleXy) * circleWidth; DrawChar(t, (float)x, (float)y, a - 90, font, width); } //起始绘制角度=起始角度-旋转角度/2+字体所占角度的一半 var angle = startAngle - changeAngle / 2 + (float)(Math.Asin(per / 2 / circleWidth) / Math.PI * 180);//起始绘制角度 for (var i = 0; i < length; i++) { action(text[i].ToString(), angle); angle -= changeAngle; } } /// <summary> /// 绘制单个字符 /// </summary> /// <param name="char">字符</param> /// <param name="x">距离画布左边的距离</param> /// <param name="y">距离画布上边的距离</param> /// <param name="emSize">字体大小</param> /// <param name="width">画笔粗细</param> public void DrawChar(string @char, float x, float y, float emSize) { DrawChar(@char, x, y, 0, emSize); } /// <summary> /// 绘制单个字符 /// </summary> /// <param name="char">字符</param> /// <param name="x">距离画布左边的距离</param> /// <param name="y">距离画布上边的距离</param> /// <param name="angle">选中角度,0度为右方,顺时针增加</param> /// <param name="emSize">字体大小</param> /// <param name="width">画笔粗细</param> public void DrawChar(string @char, float x, float y, float angle, float emSize) { DrawChar(@char, x, y, angle, emSize, defaultWidth); } /// <summary> /// 绘制单个字符 /// </summary> /// <param name="char">字符</param> /// <param name="x">距离画布左边的距离</param> /// <param name="y">距离画布上边的距离</param> /// <param name="angle">选中角度,0度为右方,顺时针增加</param> /// <param name="emSize">字体大小</param> /// <param name="width">画笔粗细</param> public void DrawChar(string @char, float x, float y, float angle, float emSize, int width) { Font font = new Font(DefaultFontName, emSize, FontStyle.Bold); DrawChar(@char, x, y, angle, font, width); } /// <summary> /// 绘制单个字符 /// </summary> /// <param name="char">字符</param> /// <param name="x">距离画布左边的距离</param> /// <param name="y">距离画布上边的距离</param> /// <param name="angle">选中角度,0度为右方,顺时针增加</param> /// <param name="fontName">字体</param> /// <param name="width">画笔粗细</param> public void DrawChar(string @char, float x, float y, float angle, Font font, int width) { if (string.IsNullOrEmpty(@char) || @char.Length != 1) { throw new ArgumentException("only one char is supported", nameof(@char)); } g.ResetTransform();//重置 g.TranslateTransform(x, y);//调整偏移 g.RotateTransform(angle);//旋转角度 g.DrawString(@char, font, new SolidBrush(Color), 0, 0);//绘制,因为使用了偏移,所以这里的坐标是相对偏移的,所以是0 } /// <summary> /// 保存图片 /// </summary> /// <param name="fileName"></param> public void Save(string fileName) { map.Save(fileName); } /// <summary> /// 保存图片 /// </summary> /// <param name="stream"></param> /// <param name="format"></param> public void Save(Stream stream, ImageFormat format) { map.Save(stream, format); } public void Dispose() { try { if (map != null) { map.Dispose(); } if (g != null) { g.Dispose(); } } catch { } } } public class PersonalSealHelper : IDisposable { int size = 160; Image map; Graphics g; int defaultWidth; float defaultSquareSize; float defaultNameSize; bool isSquare = false; public Color Color { get; set; } = Color.Red; public string DefaultFontName { get; set; } = "SimSun"; public PersonalSealHelper() { map = new Bitmap(size, size); g = Graphics.FromImage(map);//实例化Graphics类 g.SmoothingMode = SmoothingMode.AntiAlias; //System.Drawing.Drawing2D; g.Clear(Color.Transparent); defaultWidth = size / 40; defaultSquareSize = size / 4; defaultNameSize = size / 4; } /// <summary> /// 绘制方形之印 /// </summary> public void DrawSquare() { DrawSquare(defaultSquareSize); } /// <summary> /// 绘制方形之印 /// </summary> /// <param name="emSize">字体大小</param> public void DrawSquare(float emSize) { DrawSquare(emSize, defaultWidth); } /// <summary> /// 绘制方形之印 /// </summary> /// <param name="font">字体</param> public void DrawSquare(Font font) { DrawSquare(font, defaultWidth); } /// <summary> /// 绘制方形之印 /// </summary> /// <param name="emSize">字体大小</param> /// <param name="width">画笔粗细</param> public void DrawSquare(float emSize, int width) { Font font = new Font(DefaultFontName, emSize, FontStyle.Bold);//设置之印的字体样式 DrawSquare(font, width); } /// <summary> /// 绘制方形之印 /// </summary> /// <param name="font">字体</param> /// <param name="width">画笔粗细</param> public void DrawSquare(Font font, int width) { isSquare = true; var pen = new Pen(Color, width);//设置画笔的颜色 Rectangle rect = new Rectangle(width, width, size - width * 2, size - width * 2);//设置绘制区域 g.DrawRectangle(pen, rect); var textSize = g.MeasureString("之印", font);//对指定字符串进行测量 var left = (size / 2 - width * 2 - textSize.Width / 2) / 2; var perHeght = (size - width * 4 - textSize.Height * 2) / 3; PointF point1 = new PointF(left + width * 2, perHeght + width * 2); g.DrawString("之", font, pen.Brush, point1); PointF point2 = new PointF(left + width * 2, perHeght * 2 + width * 2 + textSize.Height); g.DrawString("印", font, pen.Brush, point2); } /// <summary> /// 绘制带边框的姓名 /// </summary> /// <param name="name">姓名</param> public void DrawNameWithBorder(string name) { DrawNameWithBorder(name, defaultNameSize, defaultWidth); } /// <summary> /// 绘制带边框的姓名 /// </summary> /// <param name="name">姓名</param> /// <param name="font">字体</param> public void DrawNameWithBorder(string name, Font font) { DrawNameWithBorder(name, font, defaultWidth); } /// <summary> /// 绘制带边框的姓名 /// </summary> /// <param name="name">姓名</param> /// <param name="emSize">字体大小</param> public void DrawNameWithBorder(string name, float emSize) { DrawNameWithBorder(name, emSize, defaultWidth); } /// <summary> /// 绘制带边框的姓名 /// </summary> /// <param name="name">姓名</param> /// <param name="emSize">字体大小</param> /// <param name="width">画笔粗细</param> public void DrawNameWithBorder(string name, float emSize, int width) { Font font = new Font(DefaultFontName, emSize, FontStyle.Bold);//设置字体样式 DrawNameWithBorder(name, font, width); } /// <summary> /// 绘制带边框的姓名 /// </summary> /// <param name="name">姓名</param> /// <param name="font">字体</param> /// <param name="width">画笔粗细</param> public void DrawNameWithBorder(string name, Font font, int width) { var nameSize = g.MeasureString(name, font);//对指定字符串进行测量 while (nameSize.Width > size - width * 6) { DrawNameWithBorder(name, new Font(font.Name, font.Size - 1, font.Style), width); return; } var left = (int)(size - nameSize.Width - width * 4) / 2; var height = (int)(size - nameSize.Height - width * 4) / 2; var pen = new Pen(Color, width);//设置画笔的颜色 Rectangle rect = new Rectangle(width, height, size - width * 2, size - height * 2);//设置绘制区域 g.DrawRectangle(pen, rect); PointF point = new PointF(width + width * 2, height + width * 2); g.DrawString(name, font, pen.Brush, point); } /// <summary> /// 绘制带边框的姓名 /// </summary> /// <param name="name">姓名</param> public void DrawName(string name) { DrawName(name, defaultNameSize, defaultWidth); } /// <summary> /// 绘制带边框的姓名 /// </summary> /// <param name="name">姓名</param> /// <param name="font">字体</param> public void DrawName(string name, Font font) { DrawName(name, font, defaultWidth); } /// <summary> /// 绘制带边框的姓名 /// </summary> /// <param name="name">姓名</param> /// <param name="emSize">字体大小</param> public void DrawName(string name, float emSize) { DrawName(name, emSize, defaultWidth); } /// <summary> /// 绘制带边框的姓名 /// </summary> /// <param name="name">姓名</param> /// <param name="emSize">字体大小</param> /// <param name="width">画笔粗细</param> public void DrawName(string name, float emSize, int width) { Font font = new Font(DefaultFontName, emSize, FontStyle.Bold);//设置字体样式 DrawName(name, font, width); } /// <summary> /// 绘制姓名 /// </summary> /// <param name="name">姓名</param> /// <param name="font">字体</param> /// <param name="width">画笔粗细</param> public void DrawName(string name, Font font, int width) { var nameSize = g.MeasureString(name, font);//对指定字符串进行测量 while (nameSize.Width > size - width * 6) { DrawName(name, new Font(font.Name, font.Size - 1, font.Style), width); return; } if (isSquare) { int length = name.Length;//获取字符串的长度 var left = (size / 2 - width - nameSize.Width / length) / 2; var height = (size - width * 4 - nameSize.Height * length) / (length + 1); if (left <= 0 || height <= 0) { return; } for (var i = 0; i < length; i++) { PointF point = new PointF(width + size / 2, height * (i + 1) + width * 2 + nameSize.Height * i); g.DrawString(name[i].ToString(), font, new SolidBrush(Color), point); } } else { var left = (size - nameSize.Width) / 2; var height = (size - nameSize.Height) / 2; PointF point = new PointF(width, height); g.DrawString(name, font, new SolidBrush(Color), point); } } /// <summary> /// 保存图片 /// </summary> /// <param name="fileName"></param> public void Save(string fileName) { map.Save(fileName); } /// <summary> /// 保存图片 /// </summary> /// <param name="stream"></param> /// <param name="format"></param> public void Save(Stream stream, ImageFormat format) { map.Save(stream, format); } public void Dispose() { try { if (map != null) { map.Dispose(); } if (g != null) { g.Dispose(); } } catch { } } } } }
注意了,.net core没有System.Drawing,替代方案是使用第三方的依赖,这里推荐使用Nuget的System.Drawing.Common。
另外,代码使用的是最新版本的C#,如果使用旧版本的可能会报错,相对于的调整一下就好了
这个辅助类还能生成不同颜色和字体的印章,可随需求而变
如果在Linux下发现中文乱码,那应该是没有安装相应的字体,可以将windows下的C:\Windows\Fonts的字体拷贝到linux对应目录下(Ubuntu是/usr/share/fonts),在安装,清空缓存,重启后就可以了
生成公司印章:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.IO; using System.Text; namespace DemoConsole { class Program { static void Main(string[] args) { using (var helper = SealHelper.Mechanism()) { helper.DrawCircle();//绘制圆 helper.DrawStar();//绘制星星 helper.DrawTitle("某某科技股份有限公司");//绘制公司名称 helper.DrawHorizontal("练习专用");//绘制横向文 helper.DrawChord("20191016094709");//绘制下弦文 helper.Save(Path.Combine(Directory.GetCurrentDirectory(), "公司印章.png")); } } } }
生成的印章:
生成个人印章:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.IO; using System.Text; namespace DemoConsole { class Program { static void Main(string[] args) { //绘制方形印章 using (var helper = SealHelper.Personal()) { helper.DrawSquare(); helper.DrawName("张三"); helper.Save(Path.Combine(Directory.GetCurrentDirectory(), "张三.png")); } //绘制姓名带边框 using (var helper = SealHelper.Personal()) { helper.DrawNameWithBorder("李四"); helper.Save(Path.Combine(Directory.GetCurrentDirectory(), "李四.png")); } //绘制姓名 using (var helper = SealHelper.Personal()) { helper.DrawName("王五"); helper.Save(Path.Combine(Directory.GetCurrentDirectory(), "王五.png")); } } } }
生成的印章:
一个专注于.NetCore的技术小白