PowerPoint文件字体提取工具

 

很多人工作学习中经常需要做演示报告,如果自己没有笔记本,那么准备好的PPT文件就得手动转移了。这个过程中如果不能将文件中使用的特殊字体一起带走,到演示机器上的效果可能会让你的精心准备大打折扣。正是因为自己碰到过这个问题,所以希望做个简单的小工具将PPT文件中使用到的字体都提取出来,方便携带到其他机器上安装。

简单介绍一下这个小工具制作的过程~

工作原理设想

很简单,分三步:

1. 解析PPT文件,收集其中的所有文字使用到的字体名称;

2. 通过这些字体名称,去系统的字体文件存放目录将相应的字体文件导出;

3. 生成一个字体安装脚本,以便在目标机器安装这些字体。

具体实现

有了这个简单设计,就用c#去着手实现了,可即使设计这么简单了,还是碰到一些问题:)

1. PPT文件解析

由于.net对office应用已经做了良好封装,这步做起来没有什么困难,基本只要查一查需要的查询接口就可以。只有一点需要注意一下,因为PPT文字格式的任意性,每一个文字都可以设置字体,所以我们需要让字体提取的粒度保持在单个的字符上,这样才不会有所遗漏。

首先在后台模式打开PPT文件:

PowerPoint.Application pptApplication = new PowerPoint.ApplicationClass();
PowerPoint.Presentation presentation = pptApplication.Presentations.Open2007(
    _fileName,
    Office.MsoTriState.msoTrue,
    Office.MsoTriState.msoTrue,
    Office.MsoTriState.msoFalse,
    Office.MsoTriState.msoFalse);

然后遍历文字取得字体名,层次顺序是 slide –> shape –> text –> character:

foreach (PowerPoint.Slide slide in presentation.Slides)
{
    foreach (PowerPoint.Shape shape in slide.Shapes)
    {
        if (shape.HasTextFrame == Office.MsoTriState.msoTrue &&
            shape.TextFrame.HasText == Office.MsoTriState.msoTrue) 
        {
            PowerPoint.TextRange textRange = shape.TextFrame.TextRange;
            for (int i = 0; i < textRange.Length; ++i)
            {
                PowerPoint.Font font = textRange.Characters(i, 1).Font;
                if (!_fontNames.Contains(font.Name))
                    _fontNames.Add(font.Name);
            }
        }
    }
}

这样就可以获得各种PPT文件中各种形式文本使用的每一个字体名(smartart形式的除外,因为微软没有开放相应的模型数据)。

别忘了关闭文件和PPT程序:

presentation.Close();
pptApplication.Quit();

2. 导出字体文件

在上一步中所有字体名称都已得到(存放于_fontNames中),那么现在就可以用这些名称导出相应的字体文件了。根据原先的设想,字体名称应该就是字体文件名称,然而事实上却没有想象的这么简单。打开系统字体文件目录(如c:\windows\fonts),可以看到很多字体文件的真实文件名并不是其中字体的名称,比如:

       微软雅黑 –> MSYH.TTF

因此,这里还需要一步额外的步骤,建立(字体名称,字体文件名)的映射表。我的解决方案是从系统注册表中读取字体键值来建立这个映射,"HKLM\Software\Microsoft\Windows NT\CurrentVersion\Fonts" 这个键下的值记录了系统中每一个字体对应的字体文件名,因此将键下所有值的name和value取出建立关联即可:

RegistryKey fonts = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\Windows NT\CurrentVersion\Fonts");
string[] valueNames = fonts.GetValueNames();

List<KeyValuePair<string, string>> fontMappingTable = valueNames
    .Select(s => new KeyValuePair<string, string>(s, (string)fonts.GetValue(s)))
    .ToList();

建立了这个映射表之后,就可以用之前得到的_fontNames(PPT文件中使用字体名称表)在此映射表中取出使用字体名称对应的那些字体文件名:

foreach (string fontName in _fontNames)
{
    _fontFileNames.AddRange(fontMappingTable
        .FindAll(p => p.Key.Contains(fontName))
        .Select(p => p.Value)
        .ToList());
}

接着就可以将_fontFileNames中字体文件名称对应的字体文件从系统字体目录中导出:

string fontDir = Environment.GetEnvironmentVariable("systemroot") + @"\fonts";
_fontFileNames.ForEach(s => File.Copy(fontDir + '\\' + s, _fontOutputPath + '\\' + s, true));

3. 生成安装脚本

最后在字体导出目录中生成一个安装脚本,方便在目标机器上安装这些字体:

StreamWriter writer = File.CreateText(_fontOutputPath + @"\install.bat");
_fontFileNames.ForEach(s => writer.WriteLine("copy \"" + s + "\"" + @" %systemroot%\fonts\"));
writer.Close();

在目标机器上直接运行这个文件,就大功告成啦,再也不用担心你演示中的酷帅字体了:P

补充

1. 做完了发现一不小心还是发明了轮子,PowerPoint是有save时内嵌字体这个选项的,只不过有点隐蔽,囧。。。,好在发现这个选项只能保存true type字体,总算心里得到一点点安慰。

2. 源码和可执行包下载 猛击我        运行环境:PowerPoint2007,.Net Framework3.5

3. 由于要遍历每个字符,在解析大文件时速度较慢些,但反正是一劳永逸的事,去喝点咖啡回来就好啦:)

posted @ 2009-11-01 16:05  DeathKnight  阅读(2051)  评论(5编辑  收藏  举报