文章目录
- 检验所支持语言的字体
- 使用字体绘制文本并显示
PdfSharp 语言和字体的支持有限,有时候再本地电脑上能正常显示文本,但在其它电脑上就显示乱码或一个正方体,或??。不同操作系统可能自带的字体本身就不一样,可能中文系统有的,英文系统没有,这就导致文本显示有问题。
检验所支持语言的字体
根据 PdfSharp对中文字体支持及排版格式的调整这篇文章,修改源码,做的一个小工具。
首先是源码的修改:
PdfSharp 1.5版本 在github上的源码:https://github.com/empira/PDFsharp-1.5
PdfSharp 1.5版本 在sourceforge上的源码 https://sourceforge.net/projects/pdfsharp/files/pdfsharp/
通过阅读源码,最终在PdfSharp.Fonts.CMapInfo的AddChars方法里找到了解决方案,AddChars方法内部在添加字符的时候会调用OpenTypeDescriptor.CharCodeToGlyphIndex方法将unicode字符映射到相应glyph的索引上,如果映射的索引为0,则说明该字符使用的字体在pdfSharp是不支持的,那么我们就可以通过遍历映射结果字典CharacterToGlyphIndex,只要字典值里有任何一个0值就说明提供的文本在该字体上有不被支持的字符,一旦被打印就会有乱码出现,这时就需要换一种字体来显示了。 (PS, 该段文字来自其他博文的引用)
PdfSharp.Fonts.CMapInfo类中的AddChars方法,源码如下:
/// <summary>
/// Adds the characters of the specified string to the hashtable.
/// </summary>
public void AddChars(string text)
{
if (text != null)
{
bool symbol = _descriptor.FontFace.cmap.symbol;
int length = text.Length;
for (int idx = 0; idx < length; idx++)
{
char ch = text[idx];
if (!CharacterToGlyphIndex.ContainsKey(ch))
{
char ch2 = ch;
if (symbol)
{
// Remap ch for symbol fonts.
ch2 = (char)(ch | (_descriptor.FontFace.os2.usFirstCharIndex & 0xFF00)); // @@@ refactor
}
//glyphIndex = 0 时说明该字符不被PdfSharp支持
int glyphIndex = _descriptor.CharCodeToGlyphIndex(ch2);
CharacterToGlyphIndex.Add(ch, glyphIndex);
GlyphIndices[glyphIndex] = null;
MinChar = (char)Math.Min(MinChar, ch);
MaxChar = (char)Math.Max(MaxChar, ch);
}
}
}
}
现在我们在PdfSharp.Drawing XFont 类增加一个IsSupport的方法,判断该字体是否支持字符串的绘制。
/// <summary>
/// 该字体是否支持字符串的绘制
/// </summary>
/// <param name="font"></param>
/// <param name="text"></param>
/// <returns></returns>
public bool IsSupport( XFont font, string text)
{
OpenTypeDescriptor descriptor = FontDescriptorCache.GetOrCreateDescriptorFor(font) as
OpenTypeDescriptor;
int count = 1;
if (descriptor != null)
{
var mapInfo = new CMapInfo(descriptor);
mapInfo.AddChars(text);
//CharacterToGlyphIndex是AddChars方法映射结果字典
var maps = mapInfo.CharacterToGlyphIndex;
foreach (int x in maps.Values)
{
if (x == 0)
{
count++;
break;
}
}
// return !maps.Values.Any(x => x == 0);
}
if (count == 1)
{
return true;
}
return false;
}
使用字体绘制文本并显示
在确保字体可以使用时,使用该字体绘制文本并显示出来看看效果。可使用的字体会显示Ok, 不支持该语言文本的字体则显示NG。
先附上效果图:
使用的是修改源码编译后的Pdfsharp.dll, 工程源码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using PdfSharp;
using PdfSharp.Fonts;
using PdfSharp.Drawing;
using PdfSharp.Pdf;
namespace CheckPdfSharpTextFont
{
public partial class Form1 : Form
{
PdfiumViewer.PdfViewer pdfViewer1;
public Form1()
{
InitializeComponent();
pdfViewer1 = new PdfiumViewer.PdfViewer();
this.panel1.Controls.Add(pdfViewer1);
pdfViewer1.Dock = DockStyle.Fill;
this.btnCheck.Click += btnCheck_Click;
}
/// <summary>
/// 检测
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnCheck_Click(object sender, EventArgs e)
{
string text = tbText.Text.Trim();
if(text.Length < 1)
{
text = "ABC789def";
}
XFont font = BuildFont(text, 20);
if (font != null && ckbDrawText.Checked)
{
// MessageBox.Show(font.Name);
BuildPdf(font, text);
}
}
/// <summary>
/// 创建检测字体
/// </summary>
/// <param name="text"></param>
/// <param name="size"></param>
/// <returns></returns>
public XFont BuildFont(string text, double size)
{
XFont font = null;
string str = tbFont.Text;
var fontFamilies = str.Split(',');
foreach (var name in fontFamilies)
{
try
{
font = new XFont(name, size, XFontStyle.Regular);
if (font.IsSupport(font, text))
{
tbResult.Text = ("Ok: " + name);
}
else
{
tbResult.Text = ("NG: " + name);
}
}
catch { tbResult.Text = ("NG: " + name); }
}
return font;
}
//创建PDF文档
private void BuildPdf(XFont font, string text)
{
//创建PDF文档
PdfDocument doc = new PdfDocument();
//创建空白页
PdfPage page = doc.AddPage();
//设置纸张大小
page.Size = PageSize.A4;
//设置一个画布
XGraphics gfx = XGraphics.FromPdfPage(page);
//绘制文本
for(int i=0; i<5; i++)
{
gfx.DrawString(font.Name + ": " + text, font, XBrushes.DarkSlateGray, 0, 30 + i * 40);
}
MemoryStream stream = new MemoryStream();
//将Pdf保存为数据流
doc.Save(stream);
//加载PDF文件
pdfViewer1.Document = PdfiumViewer.PdfDocument.Load(stream);
}
}
}