在.Net Core下,没有可以支持跨平台的Drawing类库,官网提供的Common.Drawing只能在Windows下使用,那么在.Net Core下该如何处理图片呢?其实有很多第三方提供了解决方案,而我比较喜欢用的是Mono团队提供的SkiaSharp,原因是稳定而且支持的也很好,性能上也还好。
Skia是Google旗下的2D图形处理库,下面是援引百科中的词条:
skia是个2D向量图形处理函数库,包含字型、坐标转换,以及点阵图都有高效能且简洁的表现。不仅用于Google Chrome浏览器,新兴的Android开放手机平台也采用skia作为绘图处理,搭配OpenGL/ES与特定的硬件特征,强化显示的效果。
Skia官网中是这样介绍的:
Skia is an open source 2D graphics library which provides common APIs that work across a variety of hardware and software platforms. It serves as the graphics engine for Google Chrome and Chrome OS, Android, Mozilla Firefox and Firefox OS, and many other products.
SkiaSharp故名思义,就是在.net下使用Skia API的库,是SkiaSharp是由mono团队开发并进行持续维护,至今已经多年了。目前的最新版本是1.60.3,当前支持.net下的:
SkiaSharp项目:https://github.com/mono/SkiaSharp
可以通过nuget命令进行安装:
nuget install skiasharp
或者在要使用的项目下,打开nuget管理器,搜索skiasharp进行安装。
这里假设已经安装好SkiaSharp 1.60.3版本。 我们先把要缩略的原图加载到内存中:
using (var input = File.OpenRead($"{PlatformServices.Default.Application.ApplicationBasePath}wwwroot/{pic}"))
这里的变量pic
是图片的相对路径。
之后实例化一个SKManagedStream
using (var inputStream = new SKManagedStream(input))
最后,把inputStream
加载到SKBitmap
画布中
using (var original = SKBitmap.Decode(inputStream))
之后重新设置图片的尺寸,也就是完成缩略处理:
using (var resized = original
.Resize(new SKImageInfo(width, height), SKBitmapResizeMethod.Lanczos3))
{
if (resized == null) return "";
using (var image = SKImage.FromBitmap(resized))
{
using (var output =
File.OpenWrite($"{PlatformServices.Default.Application.ApplicationBasePath}wwwroot/{thumb_name}"))
{
image.Encode(SKEncodedImageFormat.Png,quality)
.SaveTo(output);
}
}
}
其中,变量width
和height
分别为缩略图的宽度和高度,thumb_name
为缩略图要保存的文件名,quality
是质量,一般设置为75,或者是其他的自己觉得合适的值。
完整的例子:
using System.IO;
using Microsoft.Extensions.PlatformAbstractions;
using SkiaSharp;
public static string MakeThumb(string pic,string thumb_dir, int width, int height)
{
const int quality = 75; //质量为75%
using (var input = File.OpenRead($"{PlatformServices.Default.Application.ApplicationBasePath}wwwroot/{pic}"))
using (var inputStream = new SKManagedStream(input))
using (var original = SKBitmap.Decode(inputStream))
{
string[] arr_pic = pic.Split('/');
string filename = arr_pic[arr_pic.Length - 1]; //完整文件名
string[] arr_filename = filename.Split('.');
string ext = "";
if (arr_filename.Length >= 2)
{
ext = arr_filename[arr_filename.Length - 1]; //最后一个为扩展名
}
string thumb_name = $"{filename.Remove(filename.Length - ext.Length - 1)}-{width}x{height}.png"; //文件名,缩略图保存为png
string save_dir = $"/attach/{thumb_dir}/thumb/{DateTime.Now.ToString("yyyy-MM-dd")}";
string savepath = $"{PlatformServices.Default.Application.ApplicationBasePath}wwwroot{save_dir}";
if (!Directory.Exists(savepath))
{
Directory.CreateDirectory(savepath);
}
string thumb_file = $"{save_dir}/{thumb_name}";
using (var resized = original
.Resize(new SKImageInfo(width, height), SKBitmapResizeMethod.Lanczos3))
{
if (resized == null) return "";
using (var image = SKImage.FromBitmap(resized))
{
using (var output =
File.OpenWrite($"{savepath}/{thumb_name}"))
{
image.Encode(SKEncodedImageFormat.Png,quality)
.SaveTo(output);
}
}
}
return thumb_file;
}
}
其实图片的文字水印、图片验证码都可以从这个例子上扩充出来。
首先还是要安装SkiaSharp,之后,实例化SKImageInfo
:
var info = new SKImageInfo(width, height);
创建一个新的SKSurface
:
using (var surface = SKSurface.Create(info))
设置画布背景透明:
var canvas = surface.Canvas;
canvas.Clear(SKColors.White);
设置SKPaint
的参数
var paint = new SKPaint
{
Color = SKColors.Black,//颜色
IsAntialias = true,//抗锯齿
Style = SKPaintStyle.Fill,
TextAlign = SKTextAlign.Center,//居中
TextSize = 40F,//字号
Typeface= SkiaSharp.SKTypeface.FromFile(fontpath, 0)//加载字体
};
这里除了指定字体的路径之外,还可以使用SkiaSharp.SKTypeface.FromFamilyName("微软雅黑",SKTypefaceStyle.Bold)
来通过字体名来设置要使用的字体;参数fontpath
是字体的物理路径。
参数设置好之后,进行绘图:
var coord = new SKPoint(info.Width / 2, (info.Height + paint.TextSize / 2);
canvas.DrawText(text, coord, paint);
最后,生成图片:
using (var image = surface.Snapshot())
using (var data = image.Encode(SKEncodedImageFormat.Png, 100))
一个简单的例子:
using SkiaSharp;
using System.Linq;
public static byte[] CreateImage(string fontpath, string text,float font_size=100)
{
var info = new SKImageInfo(1100, 480);
using (var surface = SKSurface.Create(info))
{
var canvas = surface.Canvas;
canvas.Clear(SKColors.White);
var paint = new SKPaint
{
Color = SKColors.Black,
IsAntialias = true,
Style = SKPaintStyle.Fill,
TextAlign = SKTextAlign.Center,
TextSize = font_size,
Typeface= SkiaSharp.SKTypeface.FromFile(fontpath, 0)
};
var coord = new SKPoint(info.Width / 2, (info.Height + paint.TextSize) / 2);
canvas.DrawText(text, coord, paint);
using (var image = surface.Snapshot())
using (var data = image.Encode(SKEncodedImageFormat.Png, 100))
{
return data.ToArray();
}
}
}
这个是指定的文字内容使用指定的字体直接显示到空白图片上,但是不支持文字换行。我们下面的例子是对上面的进行改进,支持文字换行:
public static byte[] CreateImage(string fontpath, string text,float font_size=100)
{
//支持文字多行
List<string> list = text.Split('\n').ToList();
list.RemoveAll(x => { return string.IsNullOrEmpty(x.Trim()); }); //删除空行
list.Reverse(); //顺序反转
float line_height = 1.5F; //行距
float height = 480;
if (list.Count * line_height*font_size >= height)
{
height = list.Count * line_height * font_size;
}
var info = new SKImageInfo(1100, (int)height);
using (var surface = SKSurface.Create(info))
{
var canvas = surface.Canvas;
canvas.Clear(SKColors.White);
var paint = new SKPaint
{
Color = SKColors.Black,
IsAntialias = true,
Style = SKPaintStyle.Fill,
TextAlign = SKTextAlign.Center,
TextSize = font_size,
Typeface= SkiaSharp.SKTypeface.FromFile(fontpath, 0)
};
int i = 0;
list.ForEach(x =>
{
var coord = new SKPoint(info.Width / 2, (info.Height + paint.TextSize * (list.Count - i) - paint.TextSize * i * 1.5F) / 2);
canvas.DrawText(x.Trim(), coord, paint);
i++;
});
using (var image = surface.Snapshot())
using (var data = image.Encode(SKEncodedImageFormat.Png, 100))
{
return data.ToArray();
}
}
}
测试地址:http://tool.dwz.nz/fonts 源码:https://github.com/hongbai/FontsPrint
如果要在Linux上使用,还需要同时上传libSkiaSharp.so文件,放到与SkiaSharp.dll同一文件夹下。libSkiaSharp.so文件可以在SkiaSharp的github上下载最新的发行版本,下载地址:https://github.com/mono/SkiaSharp/releases
通过以上两个例子,我们可以发现,SkiaSharp的使用方法非常简单方便,而且各方面支持的都很不错,支持跨平台。功能上我暂时只在以上两个例子中使用,如果以后在其他方面用到的话,我会继续更新。代码写的丑,多包涵。
以上。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。