编辑
2023-07-21
Csharp/dotNet
0
请注意,本文编写于 546 天前,最后修改于 490 天前,其中某些信息可能已经过时。

目录

主要几点
代码实例
活动海报
产品海报图

主要几点

  • Font 字体对象
csharp
using FileStream fs = File.OpenRead(字体所在目录); SKTypeface Font = SKTypeface.FromStream(fs);
  • 常用的 SKPaint 对象
csharp
SKPaint text_paint = new SKPaint { TextSize = 24F, Color = sKColors, Typeface = Font, TextScaleX = scale, FakeBoldText = bold, IsAntialias = true,//抗锯齿 IsDither = true };
  • 圆角矩形
csharp
SKRoundRect roundRect = new SKRoundRect(new SKRect(0, 0, childSurface1Width, childSurface1Height), 11, 11); SKCanvas对象实例.ClipRoundRect(roundRect);
  • 绘制多行文本,并且使用省略号
csharp
/// </summary> /// <param name="canvas">画布</param> /// <param name="text">多行文字</param> /// <param name="x">x坐标</param> /// <param name="y">y坐标</param> /// <param name="paint">画笔</param> /// <param name="maxWidth">单行文字最大宽度</param> /// <param name="maxLines">最大行数,如果超出,则使用...</param> public static void DrawMuiltLineText(SKCanvas canvas, string text, float x, float y, SKPaint paint, float maxWidth, int maxLines) { //已写出行数 int lines = 0; //省略号宽度 var ellipseWidth = paint.MeasureText("..."); //如果文字没写完且已写行数小于最大行数,则继续写出 while (!string.IsNullOrEmpty(text) && lines < maxLines) { //单行文字 string lineStr; //单行文字长度 long strLength; //非最后一行 if (lines != maxLines - 1) { //调用BreakText方法,可计算指定宽度能写出多少文字 strLength = paint.BreakText(text, maxWidth, out float ww, out lineStr); } //最后一行 else { //调用BreakText方法计算单行文字长度,这里需减去省略号宽度 strLength = paint.BreakText(text, maxWidth - ellipseWidth, out float ww, out lineStr); //假如字还没写完,需加省略号 if (strLength < text.Length) { lineStr += "..."; } } //文字矩形 var tRect = new SKRect(); //计算文字矩形 paint.MeasureText(lineStr, ref tRect); //计算坐标 var tPoint = new SKPoint { X = x - tRect.Left, //这里注意Y坐标需要加上行高 Y = y + lines * paint.FontSpacing - tRect.Top }; //写出一行文字 canvas.DrawText(lineStr, tPoint, paint); //已写出行数加1 lines++; //取剩余文字 text = text.Substring((int)strLength); } }

代码实例

活动海报

c#
public class 海报生成 { /// <summary> /// 自定义字体 /// </summary> static SKTypeface? Font; /// <summary> /// 生成员工活码图片 /// </summary> /// <param name="bgPath">背景地址</param> /// <param name="qrPath">二维码地址</param> /// <param name="title">标题</param> /// <param name="text">子标题</param> public static Stream CreateActivityDiyQrCode(string bgPath, string qrPath, string coverPath, string title) { if (!File.Exists(bgPath)) throw new Exception($"不存在文件:{bgPath}"); if (Font == null) { var fontPath = $"AlibabaPuHuiTi-2-45-Light.ttf"; using (FileStream fs = File.OpenRead(fontPath)) { Font = SKTypeface.FromStream(fs); } } //字体设置 var text_paint = new SKPaint { TextSize = 24F, Typeface = Font, FakeBoldText = true, IsAntialias = true, IsDither = true }; // 创建一个主画布 using var bgMap = SKBitmap.Decode(bgPath); var mapInfo = new SKImageInfo(495, 880); var map = SKBitmap.FromImage(SKImage.Create(mapInfo)); // 创建一个主画布的画布上下文 using var mainCanvas = new SKCanvas(map); var bsSize = new SKSizeI(495, 880); var bgImage = bgMap.Resize(bsSize, SKFilterQuality.High); mainCanvas.DrawColor(SKColors.White); mainCanvas.DrawBitmap(bgImage, 0, 0); //顶部 var coverBitmap = SKBitmap.Decode(coverPath); mainCanvas.DrawBitmap(coverBitmap, 16, y: 24); mainCanvas.DrawText(title, 72, 53, text_paint); //二维码画布 var childSurface1Height = mapInfo.Height - (630 + 20); var childSurface1Width = mapInfo.Width - (283 + 20); using var childSurface1 = new SKBitmap(childSurface1Width, childSurface1Height); using var childCanvas1 = new SKCanvas(childSurface1); childCanvas1.Clear(SKColors.Transparent); SKRoundRect roundRect = new SKRoundRect(new SKRect(0, 0, childSurface1Width, childSurface1Height), 11, 11); childCanvas1.ClipRoundRect(roundRect); var qrHeight = 160; var qrWidth = 160; var qrMap = SKBitmap.Decode(qrPath); var qrSize = new SKSizeI(qrWidth, height: qrHeight); var qrImage = qrMap.Resize(qrSize, SKFilterQuality.High); childCanvas1.DrawColor(SKColors.White); childCanvas1.DrawBitmap(qrImage, 16, 12); var qrTextY = 200; var qrTextX = 35; childCanvas1.DrawText("扫码加好友", qrTextX, qrTextY, text_paint); // 把二维码画布画到主画布上 mainCanvas.DrawBitmap(childSurface1, 283, 630); var stream = SKImage.FromBitmap(map).Encode(SKEncodedImageFormat.Png, 100).AsStream(); return stream; } }

产品海报图

  • 下载在线图片到本地示例 (使用flurl库)
string localPath = await "imgUrl".DownloadFileAsync(filePath, $"temp_prodImg_{nowTimeFileName}");
  • 把byte[]图片数据保存到本地示例
csharp
private async Task<string> SaveIgmToTemp(string fileName, byte[] byteArray) { using MemoryStream imgStream = new MemoryStream(byteArray); string tempPath = "temp/image/"; string filePath = Path.Combine(tempPath, fileName).Replace("\\", "/"); if (!Directory.Exists(tempPath)) Directory.CreateDirectory(tempPath); using var fileStream = File.Create(filePath); imgStream.CopyTo(fileStream); return filePath; }
  • 核心代码
csharp
public class ImageHelper { /// <summary> /// 生成产品二维码海报图 /// </summary> /// <param name="prodPath">产品图地址(本地地址)</param> /// <param name="qrCodePath">二维码地址(本地地址)</param> /// <param name="regularPriceF">产品原价</param> /// <param name="salePriceF">产品售价</param> /// <param name="prodTitle">产品标题</param> /// <param name="marginX">整体的X边距</param> /// <param name="marginY">整体的Y边距</param> /// <param name="additionalH">额外增高</param> /// <param name="fontPath">字体路径(本地地址)</param> /// <returns></returns> public static Stream CreateProductQrImage(string prodPath, string qrCodePath, float regularPriceF, float salePriceF, string prodTitle, int marginX = 35, int marginY = 35, int additionalH = 200, string fontPath = "font.ttf") { int prodRadius = 11; //分别获取原价和售价的整数和小数 string salePriceZero = "." + salePriceF.ToString("0.00").Split('.')[1]; string salePriceInt = ((int)salePriceF).ToString(); string regularPriceZero = "." + regularPriceF.ToString("0.00").Split('.')[1]; string regularPriceInt = ((int)regularPriceF).ToString(); SKBitmap prodBitmapSource = SKBitmap.Decode(prodPath); var bsSize = new SKSizeI(500, 550); SKBitmap prodBitmap = prodBitmapSource.Resize(bsSize, SKFilterQuality.High); //根据产品图片大小生成画布大小 using SKBitmap mainBitmap = new SKBitmap(prodBitmap.Width + marginX * 2, prodBitmap.Height + additionalH + marginY * 2); using SKCanvas mainCanvas = new SKCanvas(mainBitmap); mainCanvas.Clear(); mainCanvas.DrawColor(SKColors.White); var prodReBitmap = new SKBitmap(bsSize.Width, bsSize.Height); using SKCanvas prodCanvas = new SKCanvas(prodReBitmap); prodCanvas.Clear(); SKRoundRect roundRect = new SKRoundRect(new SKRect(0, 0, bsSize.Width, bsSize.Height), prodRadius, prodRadius); prodCanvas.ClipRoundRect(roundRect); prodCanvas.DrawColor(SKColors.White); prodCanvas.DrawBitmap(prodBitmap, new SKPoint() { X = 0, Y = 0 }); //画产品图 mainCanvas.DrawBitmap(prodReBitmap, marginX, marginY); //画文字 MeasureText var line_1Paint = GetSKPaint(fontPath, SKColor.Parse("#af243d")); string row1_col1Text = "¥"; SKRect row1_col1GapSkRect = new SKRect(); SKRect row1_col2GapSkRect = new SKRect(); SKRect row2_GapSkRect = new SKRect(); SKRect row2_col1GapSkRect = new SKRect(); line_1Paint.MeasureText(text: row1_col1Text, bounds: ref row1_col1GapSkRect); float row1Y = prodBitmap.Height + prodBitmap.Height / 7; mainCanvas.DrawText(row1_col1Text, marginX, row1Y, line_1Paint); float row1X = marginX + row1_col1GapSkRect.Width + row1_col1GapSkRect.Width / 2; line_1Paint.TextSize = 45F; mainCanvas.DrawText(salePriceInt, row1X, y: row1Y, line_1Paint); line_1Paint.MeasureText($"{salePriceInt}", ref row1_col2GapSkRect); line_1Paint.TextSize = 25F; row1X = marginX + row1_col2GapSkRect.Width + (row1_col2GapSkRect.Width / 2) + (row1_col2GapSkRect.Width / 7); mainCanvas.DrawText(salePriceZero, row1X, y: row1Y, line_1Paint); row1Y = row1Y + row1_col1GapSkRect.Height * 2 + 10; string line_2Col1Text = $"价格"; SKPaint line_2Patin = GetSKPaint(fontPath, SKColors.Gray, 15F, false); //画第二行第一段文字 mainCanvas.DrawText(line_2Col1Text, marginX, row1Y, line_2Patin); //第二行第一段文字(价格)的大小方位 line_2Patin.MeasureText($"{line_2Col1Text}", ref row2_col1GapSkRect); //画第二行第二段文字 string row2Col2Text = $"¥{regularPriceInt}{regularPriceZero}"; float row2Col2TextStartPoint = marginX + row2_col1GapSkRect.Width + 5; mainCanvas.DrawText(row2Col2Text, row2Col2TextStartPoint, row1Y, line_2Patin); line_2Patin.MeasureText(row2Col2Text, ref row2_GapSkRect); //画线 SKPaint linePaint = new SKPaint { Style = SKPaintStyle.Stroke, Color = SKColors.Gray, StrokeWidth = 2 }; float lineY = row1Y - row2_GapSkRect.Height * .4f; mainCanvas.DrawLine(row2Col2TextStartPoint, lineY, row2Col2TextStartPoint + row2_GapSkRect.Width+10, lineY, linePaint); DrawMuiltLineText( mainCanvas, prodTitle, marginX, row1Y + row2_GapSkRect.Height + 10, GetSKPaint(fontPath, SKColor.Parse("#292929"), 25F, bold: false, 1), prodBitmap.Width / 2 + 10, 2); using SKBitmap qrCodeBimap = SKBitmap.Decode(qrCodePath); int wh = 150; int x = mainBitmap.Width - wh - wh / 5; int y = mainBitmap.Height - wh - wh / 4; //画二维码 //using SKImage qrCodeSKImage = SKImage.FromEncodedData(SKData.Create(qrCodePath)); //int x = mainBitmap.Width - 100; //- qrCodeSKImage.Width; //int y = mainBitmap.Height - 100;// - qrCodeSKImage.Height; SKRect qrCodeRect = SKRect.Create(x, y, wh, wh); mainCanvas.DrawBitmap(qrCodeBimap, qrCodeRect); Stream stream = SKImage.FromBitmap(mainBitmap).Encode(SKEncodedImageFormat.Png, 100).AsStream(); return stream; } /// <summary> /// 获取画笔 /// </summary> /// <param name="fontPath"></param> /// <param name="sKColors"></param> /// <param name="size"></param> /// <param name="bold"></param> /// <param name="scale"></param> /// <returns></returns> static SKPaint GetSKPaint(string fontPath, SKColor sKColors, float size = 24F, bool bold = true, float scale = 1f) { using FileStream fs = File.OpenRead(fontPath); SKTypeface Font = SKTypeface.FromStream(fs); //字体设置 SKPaint text_paint = new SKPaint { TextSize = 24F, Color = sKColors, Typeface = Font, TextScaleX = scale, FakeBoldText = bold, IsAntialias = true, IsDither = true }; return text_paint; } ///<summary> /// 画多行文本并省略 /// </summary> /// <param name="canvas">画布</param> /// <param name="text">多行文字</param> /// <param name="x">x坐标</param> /// <param name="y">y坐标</param> /// <param name="paint">画笔</param> /// <param name="maxWidth">单行文字最大宽度</param> /// <param name="maxLines">最大行数,如果超出,则使用...</param> public static void DrawMuiltLineText(SKCanvas canvas, string text, float x, float y, SKPaint paint, float maxWidth, int maxLines) { //已写出行数 int lines = 0; //省略号宽度 var ellipseWidth = paint.MeasureText("..."); //如果文字没写完且已写行数小于最大行数,则继续写出 while (!string.IsNullOrEmpty(text) && lines < maxLines) { //单行文字 string lineStr; //单行文字长度 long strLength; //非最后一行 if (lines != maxLines - 1) { //调用BreakText方法,可计算指定宽度能写出多少文字 strLength = paint.BreakText(text, maxWidth, out float ww, out lineStr); } //最后一行 else { //调用BreakText方法计算单行文字长度,这里需减去省略号宽度 strLength = paint.BreakText(text, maxWidth - ellipseWidth, out float ww, out lineStr); //假如字还没写完,需加省略号 if (strLength < text.Length) { lineStr += "..."; } } //文字矩形 var tRect = new SKRect(); //计算文字矩形 paint.MeasureText(lineStr, ref tRect); //计算坐标 var tPoint = new SKPoint { X = x - tRect.Left, //这里注意Y坐标需要加上行高 Y = y + lines * paint.FontSpacing - tRect.Top }; //写出一行文字 canvas.DrawText(lineStr, tPoint, paint); //已写出行数加1 lines++; //取剩余文字 text = text.Substring((int)strLength); } } }

本文作者:宁骑

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!