C# 使用 GDI+ 给图片添加文字,并使文字自适应矩形区域
这篇文章是 GDI+ 总结系列的第二篇,如果对 GDI+ 的基础使用不熟悉的朋友可以先看第一篇文章《C# 使用 GDI+ 画图》。
需求
需求是要做一个编辑文字的页面。用户在网页端写文字,文字区域是个矩形框,用户可以通过下方的拖动条调节文字大小。
如下图:

提交数据的时候前端传文字区域的左上角和右下角定位给后台。因为前端的字体大小单位与后端没什么关系,所以不能直接传字体大小,也就是后端要根据矩形区域以及文字内容来自己推算用什么样的字体大小合适。
简单说就是知道文字的矩形区域,以及文字内容,要让文字内容根据矩形区域大小调整到适合的字体大小能比较合适地填满这个区域。
分析&思路
Graphics 类有个 MeasureString 方法,可以用来计算以当前字体写出来的文字会占据多少像素。
如下:
//
// 摘要:
// 测量用指定的 System.Drawing.Font 绘制的指定字符串。
//
// 参数:
// text:
// 要测量的字符串。
//
// font:
// System.Drawing.Font,它定义字符串的文本格式。
//
// 返回结果:
// 此方法返回 System.Drawing.SizeF 结构,该结构表示 text 参数指定的、使用 font 参数绘制的字符串的大小,单位由 System.Drawing.Graphics.PageUnit
// 属性指定。
//
// 异常:
// T:System.ArgumentException:
// font 为 null。
public SizeF MeasureString(string text, Font font);
这个方法返回的 SizeF 包含 Width 和 Height 属性,读取这两个属性可以获取到文字内容所占的宽高(以像素为单位)。
//
// 摘要:
// 获取或设置此 System.Drawing.SizeF 结构的水平分量。
//
// 返回结果:
// 此 System.Drawing.SizeF 结构的水平分量,通常以像素为单位进行度量。
public float Width { get; set; }
// 摘要:
// 获取或设置此 System.Drawing.SizeF 结构的垂直分量。
//
// 返回结果:
// 此 System.Drawing.SizeF 结构的垂直分量,通常以像素为单位进行度量。
public float Height { get; set; }
于是我们可以先根据前端传过来的文字左上角与右下角定位,算出文字的矩形区域,然后估计一个字体大小,再用 MeasureString 方法计算出估算的文字所占区域,比较和实际的文字区域大小,大了则缩小字体,小了则增大字体。这样即可大约找出合适的文字大小。
具体实现
- 添加文字方法
/// <summary>
/// 图片添加文字,文字大小自适应
/// </summary>
/// <param name="imgPath">图片路径</param>
/// <param name="locationLeftTop">左上角定位(x1,y1)</param>
/// <param name="locationRightBottom">右下角定位(x2,y2)</param>
/// <param name="text">文字内容</param>
/// <param name="fontName">字体名称</param>
/// <returns>添加文字后的Bitmap对象</returns>
public static Bitmap AddText(string imgPath, string locationLeftTop, string locationRightBottom, string text, string fontName = "华文行楷")
{
Image img = Image.FromFile(imgPath);
int width = img.Width;
int height = img.Height;
Bitmap bmp = new Bitmap(width, height);
Graphics graph = Graphics.FromImage(bmp);
// 计算文字区域
// 左上角
string[] location = locationLeftTop.Split(',');
float x1 = float.Parse(location[0]);
float y1 = float.Parse(location[1]);
// 右下角
location = locationRightBottom.Split(',');
float x2 = float.Parse(location[0]);
float y2 = float.Parse(location[1]);
// 区域宽高
float fontWidth = x2 - x1;
float fontHeight = y2 - y1;
float fontSize = fontHeight; // 初次估计先用文字区域高度作为文字字体大小,后面再做调整,单位为px
Font font = new Font(fontName, fontSize, GraphicsUnit.Pixel);
SizeF sf = graph.MeasureString(text, font);
int times = 0;
// 调整字体大小以适应文字区域
if (sf.Width > fontWidth)
{
while (sf.Width > fontWidth)
{
fontSize -= 0.1f;
font = new Font(fontName, fontSize, GraphicsUnit.Pixel);
sf = graph.MeasureString(text, font);
times++;
}
Console.WriteLine("一开始估计大了,最终字体大小为{0},循环了{1}次", font.ToString(), times);
}
else if (sf.Width < fontWidth)
{
while (sf.Width < fontWidth)
{
fontSize += 0.1f;
font = new Font(fontName, fontSize, GraphicsUnit.Pixel);
sf = graph.MeasureString(text, font);
times++;
}
Console.WriteLine("一开始估计小了,最终字体大小为{0},循环了{1}次", font.ToString(), times);
}
// 最终的得出的字体所占区域一般不会刚好等于实际区域
// 所以根据两个区域的相差之处再把文字开始位置(左上角定位)稍微调整一下
x1 += (fontWidth - sf.Width) / 2;
y1 += (fontHeight - sf.Height) / 2;
graph.DrawImage(img, 0, 0, width, height);
graph.DrawString(text, font, new SolidBrush(Color.Black), x1, y1);
graph.Dispose();
img.Dispose();
return bmp;
}
- 测试调用
private static void Main(string[] args)
{
try
{
DrawingEntity drawing = new DrawingEntity();
Console.WriteLine("Start drawing ...");
System.Drawing.Bitmap bmp = drawing.AddText(@"D:\test\39585148.png", "177.75,63.84", "674.73, 141.6", "大海啊,全是浪");
bmp.Save(@"D:\test\output.png");
bmp.Dispose();
Console.WriteLine("Done!");
}
catch (System.Exception ex)
{
Console.WriteLine("出错了!!\n" + ex.ToString());
}
finally
{
System.Console.WriteLine("\nPress any key to continue ...");
System.Console.ReadKey();
}
}
最终效果:

系列其他文章:
C# 使用 GDI+ 画图
C# 使用 GDI+ 实现添加中心旋转(任意角度)的文字
C# 使用 GDI+ 给图片添加文字,并使文字自适应矩形区域的更多相关文章
- VS2010 MFC 使用GDI+给图片添加汉字
1.配置GDI+ VS2010自带GDI+,直接使用. (1)首先要添加头文件和库 #pragma comment( lib, "gdiplus.lib" ) #include & ...
- ios图片添加文字或者水印
在项目中,我们会对图片做一些处理,但是我们要记住,一般在客户端做图片处理的数量不宜太多,因为受设备性能的限制,如果批量的处理图片,将会带来交互体验性上的一些问题.首先让我们来看看在图片上添加文字的方法 ...
- php 图片添加文字水印 以及 图片合成(微信快码传播)
1.图片添加文字水印: $bigImgPath = 'backgroud.png'; $img = imagecreatefromstring(file_get_contents($bigImgPat ...
- R语言 如何为图片添加文字说明(转载)
转载:(中文翻译者)[http://blog.csdn.net/chen790646223/article/details/49766659] (原文链接)[http://datascienceplu ...
- 利用php给图片添加文字水印--面向对象与面向过程俩种方法的实现
1: 面向过程的编写方法 //指定图片路径 $src = '001.png'; //获取图片信息 $info = getimagesize($src); //获取图片扩展名 $type = image ...
- 一种基于重载的高效c#上图片添加文字图形图片的方法
在做图片监控显示的时候,需要在图片上添加文字,如果用graphics类绘制图片上的字体,实现图像上添加自定义标记,这种方法经验证是可行的,并且在visual c#2005 编程技巧大全上有提到,但是, ...
- Swift - 给图片添加文字水印(图片上写文字,并可设置位置和样式)
想要给图片添加文字水印或者注释,我们需要实现在UIImage上写字的功能. 1,效果图如下: (在图片左上角和右下角都添加了文字.) 2,为方便使用,我们通过扩展UIImage类来实现添加水印功能 ( ...
- C#图片添加文字水印
/// <summary> /// 给图片添加文字水印 /// </summary> /// <param name="img">图片</ ...
- php 图片添加文字,水印
因为工作需求,用到这个,网上找了很多,也没有找到好的方式,最后找到这种感觉比较简单的方式,记录下来,以备后用. $im = imagecreatefrompng("img/yyk_bg. ...
随机推荐
- angular路由详解四(子路由)
子路由是相对路由 路由配置部分: 主要是children const routes: Routes = [ {path:'home', component: HomeComponent, childr ...
- C# Redis实战(四)
四.写入数据 在C# Redis实战(三)中我们已经配置好了web.config程序,并且能通过C#代码来读取和管理以上配置信息. 接下来,就可以进行Redis的数据写入了.Redis中可以用Stor ...
- java的枚举2
首先先理解一下java中枚举的本质. java的世界中一切皆是类,下面通过一个例子解释一下enum的本质: package cn.xnchall.enumeration; public class G ...
- Appserv(Apache) 配置ssl证书
一:打开httpd.conf文件,移除注释的行: Include conf/extra/httpd-ahssl.conf LoadModule ssl_module modules/mod_ssl.s ...
- springMVC的异常处理
1. 异常 什么是异常: 在程序中预期会出现,但是却无法处理的问题,叫做异常 异常处理原则: 延迟处理 先记着...,后续补充
- OpenCascade Law Function
OpenCascade Law Function eryar@163.com 1.Introduction 在OpenCASCADE的TKGeomAlgo Toolkit中提供了一个Law Packa ...
- 笔记:Maven 创建 Nexus 私服
首先从 http://nexus.sonatype.org/downloads/ 下载最新版本的Nexus,下载 bundle 包,不需要Web容器. windows 系统安装 目录结构说明 目录 说 ...
- Java 泛型进阶
擦除 在泛型代码内部,无法获得任何有关泛型参数类型的信息. 例子1: //这个例子表明编译过程中并没有根据参数生成新的类型 public class Main2 { public static voi ...
- 如何通过TortoiseGit(小乌龟)把本地项目上传到github上
1.第一步: 安装git for windows(链接:https://gitforwindows.org/)一路next就好了, 如果遇到什么问题可以参考我另外一篇文章~^ - ^ 2.第二步:安装 ...
- lvs(dr)+keepalived
系统:centos6.5mini 环境: 机器名 Ip地址 角色 Vip-web: 192.168.20.50 Vip-mysql: 192.168.20.60 lvs01 192.168.20.10 ...