前言

之前写过一篇 Linux/Docker 中使用 System.Drawing.Common 踩坑小计, 当时主要是有一块图像处理的需要从 .net framework 迁移到 .net core上,使用这个方案,基本可以说是无缝迁移。但是最近发现了两个问题:

  • 构建 Docker 时需安装 libgdiplus
  • 多行文本输出,在 WindowsLinux 下表现不一致

针对以上问题,想着尝试一下其他解决方案试试,后来遇见它:SixLabors.ImageSharp。下面通过实战来了解一下它的具体使用。

合并图片

合并图片即将一张小图片放到一张大图片上,准备素材如下:

模板图 (basic.bmp) :

电子签名图 (test.png):

合并操作代码:

        /// <summary>
/// 合并图片
/// </summary>
/// <param name="templateImage"></param>
/// <param name="mergeImagePath">合并图片</param>
/// <param name="x">X坐标</param>
/// <param name="y">y坐标</param> /// <returns></returns>
public static Image MergeImage(Image templateImage, string mergeImagePath, int x, int y)
{
// 加载需要合并的图片
var mergeImage = Image.Load(mergeImagePath); templateImage.Mutate(o =>
{
o.DrawImage(mergeImage, new Point(x, y), 1);
}); return templateImage;
}

使用:

        static void Main(string[] args)
{
var templatePath = "./basic.bmp";
var mergeImagePath = "./test.png";
var outputImage = Image.Load(templatePath);
outputImage = MergeImage(outputImage, mergeImagePath, 700, 1825); outputImage.Save("result.png");
}

效果图 (result.png):

图片缩放

经过上一步图片合并,我们可以发现电子签名的图片有些大了,我们需要缩放一下。

改进 MergeImage 代码:

        /// <summary>
/// 合并图片
/// </summary>
/// <param name="templateImage"></param>
/// <param name="mergeImagePath">合并图片</param>
/// <param name="x">X坐标</param>
/// <param name="y">y坐标</param>
/// <param name="width">宽度</param>
/// <param name="height">高度</param>
/// <returns></returns>
public static Image MergeImage(Image templateImage, string mergeImagePath, int x, int y, int width, int height)
{
var mergeImage = Image.Load(mergeImagePath);
mergeImage.Mutate(m =>
{
m.Resize(new Size(width, height));
}); templateImage.Mutate(o =>
{
o.DrawImage(mergeImage, new Point(x, y), 1);
}); return templateImage;
}

调用和之前一样,但是需要提供你希望缩放图片宽高即可。

效果图 (result.png):

输出多行文本

        /// <summary>
/// 多行文本输出
/// </summary>
/// <param name="templateImage"></param>
/// <param name="text"></param>
/// <param name="fontSize"></param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="wrapTextWidth">文本框长度</param>
/// <returns></returns>
public static Image AddMultilineText(Image templateImage, string text, int fontSize, int x, int y, int wrapTextWidth)
{
var fonts = new FontCollection();
var fontFamily = fonts.Install("./simhei.ttf");
var font = new Font(fontFamily, fontSize, FontStyle.Bold); var textOptions = new TextOptions()
{
ApplyKerning = true,
VerticalAlignment = VerticalAlignment.Top,
HorizontalAlignment = HorizontalAlignment.Left,
WrapTextWidth = wrapTextWidth
}; var graphicsOptions = new GraphicsOptions()
{
Antialias = true
}; var options = new TextGraphicsOptions(graphicsOptions, textOptions); templateImage.Mutate(o =>
{ o.DrawText(options, text, font, Color.Black, new PointF(x, y));
}); return templateImage;
}

调用方式:

        static void Main(string[] args)
{
var templatePath = "./basic.bmp";
var mergeImagePath = "./test.png";
var text =
"两侧胸廓对称;两侧肺野透光度正常,未见异常密度增高影;两肺纹理略增粗。两肺门无增大、增浓;心影大小、形态如常;纵隔居中,两膈面光整,肋膈角清晰锐利。 两肺门无增大、增浓;心影大小、形态如常;纵隔居中,两膈面光整,肋膈角清晰锐利。";
var outputImage = Image.Load(templatePath);
outputImage = MergeImage(outputImage, mergeImagePath, 700, 1825, 195, 53); outputImage = AddMultilineText(outputImage, text, 35, 143, 1050, 1100);
outputImage.Save("20201123-result-3.png");
}

效果图:

以上可以看到,文本并没有达到我想要的换行效果,尝试过调整 wrapTextWidth 的值,结果都是失败。后来发现可以自己手动给文本添加\r\n 换行符,来让文本输出的时候自动换行。所以自己整了一个给文本添加的换行符的方法。

CutText:

        /// <summary>
/// 自动换行字符串
/// </summary>
/// <param name="str">文本字符串</param>
/// <param name="len">每行的长度,多于这个长度自动换行</param>
/// <returns></returns>
public static string CutText(string str, int len)
{ var result = string.Empty;
var strLen = Encoding.Default.GetByteCount(str);
for (var i = 0; i < strLen; i++)
{
var r = i % len;
var last = (str.Length / len) * len;
if (i != 0 && i <= last)
{
if (r == 0)
{
result += str.Substring(i - len, len) + "\r\n";
}
}
else if (i > last)
{
result += str.Substring(i - 1);
break;
}
}
return result;
}

改进一下 AddMultilineText 方法:

        /// <summary>
/// 多行文本输出
/// </summary>
/// <param name="templateImage"></param>
/// <param name="text"></param>
/// <param name="fontSize"></param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="wrapTextWidth">文本框长度</param>
/// <returns></returns>
public static Image AddMultilineText(Image templateImage, string text, int fontSize, int x, int y, int wrapTextWidth)
{
var fonts = new FontCollection();
var fontFamily = fonts.Install("./simhei.ttf");
var font = new Font(fontFamily, fontSize, FontStyle.Bold); var textOptions = new TextOptions()
{
ApplyKerning = true,
VerticalAlignment = VerticalAlignment.Top,
HorizontalAlignment = HorizontalAlignment.Left,
WrapTextWidth = wrapTextWidth
}; var graphicsOptions = new GraphicsOptions()
{
Antialias = true
}; var options = new TextGraphicsOptions(graphicsOptions, textOptions); templateImage.Mutate(o =>
{
var result = CutText(text, wrapTextWidth / fontSize);
o.DrawText(options, result, font, Color.Black, new PointF(x, y));
}); return templateImage;
}

执行查看效果图:

小结

目前使用 SixLabors.ImageSharp 重写 System.Drawing.Common 实现的代码,效果还不错,API 接口也挺简洁的,也不需要在发布到 Docker 的时候安装额外的组件依赖,总的来说还是不错。

SixLabors.ImageSharp 实践小结的更多相关文章

  1. .net core 图片合并,图片水印,等比例缩小,SixLabors.ImageSharp

    需要引用 SixLabors.ImageSharp 和SixLabors.ImageSharp.Drawing 引用方法 NuGet包管理 添加程序包来源 https://www.myget.org/ ...

  2. 在 .NET Core 下使用 SixLabors.ImageSharp 操作图片文件(放大、缩小、裁剪、加水印等等)的几个小示例

    1. 基础 1.1  将图片的宽度和高度缩小一半 直接贴代码了: <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup ...

  3. TCP编程实践小结1

    说起TCP/IP协议,大家估计都能说出个一二,但是估计很少有人能够深入的理解这个协议,原因有这么几个: 协议本身确实复杂 入门教材没选对,太抽象了,导致大家浅尝辄止 学习过程中如果没有配合实践理解,过 ...

  4. 使用puppeteer爬取网页数据实践小结

    简单介绍Puppeteer Puppeteer是一个Node库,它通过DevTools协议提供高级API来控制Chrome或Chromium.Puppeteer默认以无头方式运行,但可以配置为有头方式 ...

  5. Python原生调试工具pdb实践小结

    使用python -m pdb xxx.py进入单步调试模式,默认会在脚本的第一行可执行命令处停止.此时,通过 b function设置之后的函数断点会提示出错,从出错异常栈中可以看出,pdb是将fu ...

  6. TCP KeepAlive机制理解与实践小结

    0 前言 本文将主要通过抓包并查看报文的方式学习TCP KeepAlive机制,以此加深理解. 1 TCP KeepAlive机制简介 TCP长连接下,客户端和服务器若长时间无数据交互情况下,若一方出 ...

  7. Android MVP+Retrofit+RxJava实践小结

    关于MVP.Retrofit.RxJava,之前已经分别做了分享,如果您还没有阅读过,可以猛戳: 1.Android MVP 实例 2.Android Retrofit 2.0使用 3.RxJava ...

  8. 82.Android之MVP+Retrofit+RxJava实践小结

    转载:http://wuxiaolong.me/2016/06/12/mvpRetrofitRxjava/ 关于MVP.Retrofit.RxJava,之前已经分别做了分享,如果您还没有阅读过,可以猛 ...

  9. 使用U盘安装Ubuntu系统的实践小结

    参考教程:http://diybbs.zol.com.cn/1/33925_1942.html   遇到的问题:安装ubuntu 12.04 64位,提示缺少“/casper/vmlinuz.efi ...

随机推荐

  1. 五分钟详解MySQL并发控制及事务原理

    在如今互联网业务中使用范围最广的数据库无疑还是关系型数据库MySQL,之所以用"还是"这个词,是因为最近几年国内数据库领域也取得了一些长足进步,例如以TIDB.OceanBase等 ...

  2. jmeter环境变量配置

    参考博客:超全 https://blog.csdn.net/qq_39720249/article/details/80721777

  3. Django (学习第一部 基础操作)

    django 1 django 文件相关信息 2 Python创建django 3 命令行创建django 4 Django 必会三板斧 5 静态文件配置 6 request对象方法 7 pychar ...

  4. openresty 的小白记录

    openresty提供了一个快速访问数据库,快速响应的功能.基于lua + redis,我们可以做到快速响应,达到10k级连接的处理能力. openresty 的小白记录 好的学习资料,从lua到op ...

  5. spring与缓存注解,以及encache缓存使用

    随着时间的积累,应用的使用用户不断增加,数据规模也越来越大,往往数据库查询操作会成为影响用户使用体验的瓶颈,此时使用缓存往往是解决这一问题非常好的手段之一.Spring 3开始提供了强大的基于注解的缓 ...

  6. 卸载联软UniAccess,删除UniAccess Agent记录

    UniAccess 卸载 事情起因: 公司假以安全上网为由,让公司员工安装所谓的"XX上网助手",实则是内嵌了联软的UniAccess监控系统. 有关这个软件的用途就不用多介绍了, ...

  7. 4G DTU的使用方法和应用领域

    4G DTU是一种数据传输单元,通俗理解就是,用来传输数据的一种硬件.既然是用来传输数据的,那就能将它视为一个管道,也就是说,指令同过它传给设备,而管道是不对这些指令做出响应的. 4G DTU如何使用 ...

  8. 【USACO】New Years Party

    题意描述 New Years Party \(N(3\leq N\leq 200)\) 头奶牛举办新年聚会.每头奶牛会做几种不同的佳肴(以"碟"记数). 一共有 \(D(5\leq ...

  9. 关于H5页面在微信浏览器中音视频播放的问题

    Android 上,因为各个软件使用的浏览器渲染引擎不一样,所以视频播放的效果差异也很大,这里主要以微信为主.微信使用的是腾讯浏览器自带的X5内核. 而iOS是不允许使用第三方浏览器内核的,就是Goo ...

  10. mysql触发

    create procedure agex(in addage1 int,in addage2 int)begindeclare curl_stu_id int; declare curl_stu_s ...