在网页中嵌入任意字体的解决方案 (insert any font)

本文介绍如何使用@font-face属性及sIFR、Typeface.js和cufon等技术实现在网页中嵌入任意字体。详细讲解了字体文件格式转换、浏览器兼容性问题及各种技术的优缺点。

字体使用是网页设计中不可或缺的一部分。经常地,我们希望在网页中使用某一特定字体,但是该字体并非主流操作系统的内置字体,这样用户在浏览页面的 时候就有可能看不到真实的设计。美工设计师最常做的办法是把想要的文字做成图片,

 

这样做有几个明显缺陷:

1. 不可能大范围的使用该字体;

2. 图片内容相对使用文字不易修改;

3. 不利于网站SEO(主流搜索引擎不会将图片alt内容作为判断网页内容相关性的有效因素)。

 

网络上有一些使用sIFR技术、或 javascript/flash hack的方法,但实现起来或繁琐,或有缺陷。下面要讲的是如何只通过CSS的@font-face属性来实现在网页中嵌入任意字体。

 

【第一步】

获取要使用字体的三种文件格式,确保能在主流浏览器中都能正常显示该字体。

 

1. @font-face

CSS3的@font-face属性(事实上CSS2中就已引入),为我们带来了一些希望,而 Firefox 3.5新增的对@font-face的支持,让我们离这个希望更进了一些。

 

到现在为止,已经有Safari、 Chrome、Opera 10和Firefox 3.5支持@font-face了,比较意外的是,IE系列浏览器也部分支持该属性。Mozilla旗下的其它产品,SeaMonkey 2 和Thunderbird 3 也支持该属性。

 

浏览器兼容性
浏览器最 低版本支持字体
Internet Explorer 4.0 只 支持OpenType字体(eof格式)
Firefox (Gecko) 3.5 (1.9.1)TrueType(ttf格式)和OpenType 字体
Opera 10.0 TrueType 和OpenType 字体
Safari (WebKit) 3.1 (525)TrueType和OpenType 字体

 

从表中可以看 出,IE系浏览器不支持TTF格式的字体,只支持eof格式,不过,微软官方发布了一个WEFT工具,可以将TTF转化为EOF,需要的朋友可以去下载使用

 

可以使用的样式如下:

  • .TTF或.OTF,适用于Firefox 3.5、Safari、Opera
  • .EOT,适用于Internet Explorer 4.0+
  • .SVG,适用于Chrome、IPhone

下面要解决的是如何获取到某种字体的这三种格式文件。一般地,我们在手头上(或在设计资源站点已经找到)有该字体的某种格式文件,最常见的 是.TTF文件,我们需要通过这种文件格式转换为其余两种文件格式。

 

字体文件格式的转换可以通过网站FontsQuirrelonlinefontconverter 提 供的在线字体转换服务获取。这里推荐第一个站点,它允许我们选择需要的字符生成字体文件(在服务的最后一个选项),这样就大大缩减了字体文件的大小,使得 本方案更具实用性。

 

【第二步】

获取到三种格式的字体文件后,下一步要在样式表中声明该字体,并在需要的地方使用该字体。

字体声明如下:

 

@font-face {
	font-family: 'fontNameRegular';
	src: url('fontName.eot');
	src: local('fontName Regular'), 
              local('fontName'), 
              url('fontName.woff') format('woff'), 
              url('fontName.ttf') format('truetype'), 
              url('fontName.svg#fontName') format('svg');
}  
/*其中fontName替换为你的字体名称*/
 

 

在页面中需要的地方使用该字体:

 

    p { font: 13px fontNameRegular, Arial, sans-serif; }
    h1{font-family: fontNameRegular}
 

或者

 

    <p style="font-family: fontNameRegular">掬水月在手,落花香满衣</p>
 


其他方法:

sIFR

sIFR并非一种新技术,而是已经存在并被使用很多年了。sIFR是一种很有用也很好用的文本替换技术,通过 Flash+JS+CSS将网络字体嵌入到页面中。

考虑到网上已经有很多资源,本文就不再赘述,想要了解的朋友可以参考一下文章:

  1. 如何以及何时使用sIFR
  2. sIFR-文本替换技术
  3. sIFR——百度百 科

Typeface.js

Typeface 被认为是替代 SIFR的最佳方案,相对于sIFR,Typeface少了Flash的应用,使用纯JS来嵌入相关字体,而且用法也很简单:在页面中引入相应的js文件 就OK了。

 

<html>
  <head>
<!-- 加载所有的样式先 -->
    <link rel="stylesheet" type="text/css" ref="/style.css">
<!-- 再加载typeface.js 库文件和typeface.js字体文件-->
    <script type="text/javascript" src="typeface-0.10.js"></script>
    <script type="text/javascript" src="helvetiker_regular.typeface.js"></script>
  </head>
  <body>
<!-- 继续并使用CSS指定typeface.js 字体 -->
    <div class="myclass typeface-js" style="font-family: Helvetiker">
      文本文本...
    </div>
  </body>
</html>
 

 

从 中我们可以看出来,使用Typeface只需要着简单的几步就可以在页面中使用嵌入字体了。

typeface资源:

cufon

cufon是一个比较新的技术,被定位为有价值的sIFR替代方案,它有很多优 势:

  1. 无需浏览器插件——被浏览器原生支持;
  2. 兼容性——兼容各个主流浏览器
  3. 易用—— 无需配置
  4. 速度—— 快速渲染大量字体
cufon的原理:

cufon通过生成器将字体文件 转化为SVG字体,再将其转换为VML文件,这对IE很重要,因为IE原生支持VML文件。最后,使用复杂的JavaScript函数将VML文件编码为 JSON文件(typeface的原理与此类似)。如下图所示:

 

 

这 样做有很多好处:

  1. 与加载一个字体文件,你只需要加载一些js文件就可以;
  2. 客户端无需再次手工编码;
  3. 外 部js文件直到加载完成才会被执行,这可以让我们实现无闪烁的干净的替换。
  4. 压缩率高。相对于字体文件,可压缩掉60-80% 。
cufon 的用法:

cufon的用法与typeface类似,需要加载一个库文件和字体文件。而与typeface不同的是,你需要使用js初始化 cufon:

 

<script type="text/javascript">
Cufón.replace('h2', { fontFamily: 'Qlassik Medium' }); 
</script>
 

 

这 与typeface的在样式中定义字体很不一样。

cufon资源:
cufon和typeface.js对比:

CufónTypeface.js
File size14.0kb (压缩后)16.3kb (未压缩)
支持的浏览器Firefox 1.5+, Safari 3+, Opera 9.5+, Google Chrome 和 Internet Explorer6+Firefox 1.5+, Safari 2+, and Internet Explorer 6+, 最新版已经支持IE8
支 持的字体类型.ttf, .otf, PFB, postscript.ttf
支 持的字体样式font-size, font-style, font-weight, line-height, text-shadow, colorfont-size, font-style, font-weight, font-stretch, letter-spacing, line-height
可选文字?尚 不支持尚不支持

 

从这个对比中可以看出来,两者并没有太大的不 同,cufon支持更多的浏览器和字体类型,而typeface支持更多的字体样式。实际应用中貌似typeface方便一些,可以直接在样式中定义字 体,而cufon则有总体文件大小方面的优势。具体用哪一个,看你自己的喜好吧。

总结

事实上,sIFR、 typeface.js和cufon都是目前常说的文本替换技术,这些技术都可以用来替换@font-face,并且实现更好的浏览器兼容性。但是每种技 术都不是完美的:

  1. @font-face最简单,虽然大部分浏览器也都支持了,但是其浏览器兼容性并不是很完美,对IE还需要 eof字体的特殊支持,而且对于中文字体来说,一般都很大,这会占用很大的页面加载时间和服务器流量。
  2. sIFR是兼容性和可用性最好、 对SEO友好的一种方案,但也是实现起来最复杂的,而且需要浏览器支持Flash插件。
  3. typeface和cufon都是利用在IE中 渲染VML,而在非IE浏览器中使用canvas的方式实现“伪”字体的,他们使用起来相对简单,但是可用性和用户体验以及SEO都不是很理想。
  4. 版 权问题是一个很重要的问题,无论你使用哪种技术,都需要考虑文字的授权。

所以,使用哪种方案,要看你的需求和喜好,或许你宁愿 切更多的图片也不愿使用这些技术?

 

 

 

from openpyxl import load_workbook from docx import Document from docx.shared import Inches from docx.shared import Pt, Cm from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_LINE_SPACING # 添加WD_LINE_SPACING from docx.enum.style import WD_STYLE_TYPE from docx.enum.table import WD_ALIGN_VERTICAL, WD_ROW_HEIGHT_RULE from docx.oxml.ns import qn from docx.oxml import OxmlElement from docxcompose.composer import Composer import re import pandas as pd import tempfile, shutil, sys, os def insert_entire_document(main_doc_path, insert_doc_path, output_path): """ 将整个插入文档内容添加到主文档末尾 参数: main_doc_path: 主文档路径 insert_doc_path: 要插入的文档路径 output_path: 输出文档路径 """ # 读取主文档 main_doc = Document(main_doc_path) # 读取要插入的文档 insert_doc = Document(insert_doc_path) # 创建Composer对象进行文档合并 composer = Composer(main_doc) # 将插入文档追加到主文档 composer.append(insert_doc) # 保存合并后的文档 composer.save(output_path) print(f"文档已成功合并保存至: {output_path}") def set_cell_margins(cell, left=0.05, right=0.05, top=None, bottom=None): """ 设置Word表格单元格边距(单位:厘米) 参数: cell: 要设置的单元格对象 left: 左边距(厘米),默认为0.05 right: 右边距(厘米),默认为0.05 top: 上边距(厘米),可选 bottom: 下边距(厘米),可选 """ # 确保单位为厘米 left = float(left) if left is not None else None right = float(right) if right is not None else None top = float(top) if top is not None else None bottom = float(bottom) if bottom is not None else None # 获取单元格属性 tc = cell._tc tcPr = tc.get_or_add_tcPr() # 创建或获取单元格边距元素 tcMar = tcPr.first_child_found_in('w:tcMar') if tcMar is None: tcMar = OxmlElement('w:tcMar') tcPr.append(tcMar) # 创建边距元素并设置值 directions = { 'left': left, 'right': right, 'top': top, 'bottom': bottom } for direction, value in directions.items(): if value is None: continue # 转换厘米为缇(twips): 1厘米 = 567缇 twips = str(int(value * 567)) # 查找或创建方向元素 dir_element = tcMar.find(qn(f'w:{direction}')) if dir_element is None: dir_element = OxmlElement(f'w:{direction}') dir_element.set(qn('w:w'), twips) dir_element.set(qn('w:type'), 'dxa') # dxa表示单位为缇 tcMar.append(dir_element) else: dir_element.set(qn('w:w'), twips) def set_table_cell_margins(table, left=0.05, right=0.05, top=None, bottom=None): """ 设置整个表格所有单元格的边距 参数: table: 表格对象 left: 左边距(厘米),默认为0.05 right: 右边距(厘米),默认为0.05 top: 上边距(厘米),可选 bottom: 下边距(厘米),可选 """ for row in table.rows: for cell in row.cells: set_cell_margins(cell, left, right, top, bottom) def add_formatted_text(paragraph, text): """ 添加带格式的文本到段落中,自动处理斜体、上标、下标和中文双引号 格式规则: - U 和 k 设置为斜体 - rel 设置为下标 - 科学计数法中的指数部分设置为上标 - 中文双引号单独处理并设置中文字体 """ # 定义格式标记的正则表达式 patterns = [ (r'U(rel)?', 'u'), # 匹配U或Urel (r'k=', 'k'), # 匹配k= (r'rel', 'subscript'), # 单独匹配rel (r'%', 'normal'), # 百分号 (r'dB', 'normal'), # dB单位 (r'[“”]', 'quote') # 匹配中文双引号 ] # 位置标记数组 (0=普通, 1=斜体, 3=下标, 4=中文引号) flags = [0] * len(text) # 应用格式标记 for pattern, flag_type in patterns: for match in re.finditer(pattern, text): start, end = match.span() flag_value = { 'u': 1, 'k': 1, 'subscript': 3, 'normal': 0, 'quote': 4 }[flag_type] # 特殊处理Urel组合 if flag_type == 'u' and match.group(1): flags[start] = 1 # U斜体 for i in range(start + 1, end): flags[i] = 3 # rel下标 else: for i in range(start, end): flags[i] = flag_value # 新增:手动处理科学计数法格式(避免使用后视断言) for match in re.finditer(r'×10(-\d+)', text): start, end = match.span() # 找到×10后面的指数开始位置 exp_start = match.start(1) # 设置指数部分为上标 for i in range(exp_start, end): flags[i] = 2 # 上标 # 分割并添加格式化的文本片段 start_idx = 0 for i in range(1, len(flags)): if flags[i] != flags[i - 1]: segment = text[start_idx:i] add_segment(paragraph, segment, flags[i - 1]) start_idx = i # 添加最后一段 add_segment(paragraph, text[start_idx:], flags[-1]) def add_segment(paragraph, text, flag): """添加指定格式的文本片段""" if not text: return run = paragraph.add_run(text) run.font.size = Pt(12) # 根据标志设置字体 if flag == 4: # 中文双引号 run.font.name = '宋体' # 设置为中文字体 run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体') else: # 其他文本 run.font.name = 'Times New Roman' run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体') # 应用其他格式 if flag == 1: # 斜体 (U/k) run.italic = True elif flag == 2: # 上标 (科学计数法指数) run.font.superscript = True elif flag == 3: # 下标 (rel) run.font.subscript = True def excel_sheets_to_word(excel_path, word_path, lieshu,buquedingdu_excel_path): # 加载Excel工作簿 wb = None bqdd = None try: # 使用with确保资源释放 with pd.ExcelFile(buquedingdu_excel_path) as xls: bqdd = pd.read_excel(xls) # 加载工作簿 wb = load_workbook(excel_path, data_only=True) try: doc = Document(word_path) except: doc = Document() # 文件存在时创建新文档 # 遍历所有sheet sheetn = 0 xuhaon = 0 xuhao = ["二、", "三、", "四、", "五、", "六、", "七、"] # 创建标题样式对象(设置全局行距) try: title_style = doc.styles['TitleStyle'] except KeyError: # 如果存在则创建 title_style = doc.styles.add_style('TitleStyle', WD_STYLE_TYPE.PARAGRAPH) title_style.paragraph_format.line_spacing_rule = WD_LINE_SPACING.MULTIPLE title_style.paragraph_format.line_spacing = 1.5 # 设置为1.5倍行距 panju = 0 measurements = [] for sheet_name in wb.sheetnames: sheet = wb[sheet_name] max_row = sheet.max_row max_col = sheet.max_column # 检测有效数据范围(跳过开头和结尾的空行) start_row = 1 end_row = max_row # 查找第一个非空行(从顶部) for row_idx in range(1, max_row + 1): if any(sheet.cell(row=row_idx, column=col).value for col in range(1, max_col + 1)): start_row = row_idx break # 查找最后一个非空行(从底部) for row_idx in range(max_row, 0, -1): if any(sheet.cell(row=row_idx, column=col).value for col in range(1, max_col + 1)): end_row = row_idx break # print(end_row) if sheet_name == "频率": suoyin = "A" + str(end_row) pinlv = sheet[suoyin].value if pinlv<2000: pinlv=2000 else: pass measurements.append(bqdd[pinlv][0]) measurements.append(bqdd[pinlv][1]) zd = lieshu[sheetn] if sheet_name == "相对电平": xuhaon = xuhaon - 1 else: # 创建标题段落并指定样式 title = doc.add_paragraph(style='TitleStyle') title_xu = xuhao[xuhaon] + sheet_name title_run = title.add_run(title_xu) title_run.bold = True # 设置加粗 title_run.font.size = Pt(14) if sheet_name == "调幅深度": measurements.append(bqdd[pinlv][2]) title_zhu = title.add_run("(功率0dBm,调制速率1kHz,检波器+/-PEAK/2,低通3kHz,高通300Hz)") elif sheet_name == "调频频偏": measurements.append(bqdd[pinlv][3]) title_zhu = title.add_run("(功率0dBm,调制速率1kHz,检波器+/-PEAK/2,低通3kHz,高通300Hz)") elif sheet_name == "调相相偏": measurements.append(bqdd[pinlv][4]) title_zhu = title.add_run("(功率0dBm,调制速率1kHz,检波器+/-PEAK/2,低通3kHz,高通300Hz)") elif sheet_name == "频谱纯度": measurements.append(bqdd[pinlv][5]) else: title_zhu = title.add_run("") title_zhu.font.size = Pt(10.5) title_zhu.bold = False title.alignment = WD_ALIGN_PARAGRAPH.LEFT # 确保行距设置应用到段落(双重保证) title.paragraph_format.line_spacing_rule = WD_LINE_SPACING.MULTIPLE title.paragraph_format.line_spacing = 1.5 table = doc.add_table(rows=1, cols=zd) # 固定4列 table.style = 'Table Grid' # 添加表头(第一行数据作为标题) header_cells = table.rows[0].cells for col in range(1, zd + 1): # 只取前4列 header_cells[col - 1].text = str(sheet.cell(row=1, column=col).value or "") # 添加数据行(从第二行开始) for row in range(2, end_row + 1): row_cells = table.add_row().cells for col in range(1, zd + 1): # 只取前4列 cell_value = sheet.cell(row=row, column=col).value data_cell = str(cell_value) if cell_value is not None else "" # print(data_cell) if "*" in "9.9999934*": panju = "合格" # print(panju) else: pass data_cell = data_cell.replace("–", "-") data_cell = data_cell.replace("HZ", "Hz") row_cells[col - 1].text = data_cell set_table_cell_margins(table, 0.05, 0.05) # if zd >= 4: # 确保表格至少有4列 # table.columns[3].width = Cm(7) # 索引3对应第4列 # table.autofit = True # print(f"已设置表格 '{sheet_name}' 第4列宽度为7cm(列数={zd})") # else: # print(f"警告:表格 '{sheet_name}' 仅 {zd} 列,无法设置第4列宽度") # 设置单元格居中 for row in table.rows: if zd >= 4: row.cells[3].width = Cm(7) row.height_rule = WD_ROW_HEIGHT_RULE.AUTO # 自动调整行高 for cell in row.cells: cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER for paragraph in cell.paragraphs: paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER # 设置表格字体 for row in table.rows: for cell in row.cells: for paragraph in cell.paragraphs: for run in paragraph.runs: run.font.name = 'Times New Roman' run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体') run.font.size = Pt(12) sheetn = sheetn + 1 xuhaon = xuhaon + 1 # print(measurements) if panju == "合格": measurements.append("注:本次校准结果中标“*”号项目符合技术指标要求。") else: measurements.append("注:本次校准结果符合技术指标要求。") # 添加带格式的测量数据 for item in measurements: p = doc.add_paragraph(style='TitleStyle') add_formatted_text(p, item) t1 = doc.add_paragraph(style='TitleStyle') run_t1 = t1.add_run("以下无内容") run_t1.font.size = Pt(12) run_t1.font.name = 'Times New Roman' # run_t1.font.name = u'黑体' # 中文字体 run_t1._element.rPr.rFonts.set(qn('w:eastAsia'), u'黑体') run_t1.font.bold = True doc.save(word_path) # ... 原函数处理逻辑变 ... except Exception as e: print(f"处理过程中出错: {e}") finally: # 确保资源释放 if wb: wb.close() # 清理大型对象 del bqdd # 显式触发垃圾回收 import gc gc.collect() # 使用示例 import tkinter as tk from tkinter import filedialog # def select_file(file_type, title, extensions): # """通过文件对话框选择文件""" # root = tk.Tk() # root.withdraw() # 隐藏主窗口 # file_path = filedialog.askopenfilename( # title=title, # filetypes=[(f"{file_type}文件", extensions), ("所有文件", "*.*")] # ) # return file_path def select_file(file_type, title, extensions): """通过文件对话框选择文件并确保资源释放""" root = tk.Tk() root.withdraw() file_path = filedialog.askopenfilename( title=title, filetypes=[(f"{file_type}文件", extensions), ("所有文件", "*.*")] ) # 确保销毁Tk窗口 root.destroy() return file_path # 选择Excel文件 if __name__ == "__main__": # 创建临时目录处理 # temp_dir = tempfile.TemporaryDirectory() # 优化文件选择 excel_path = select_file("Excel", "选择信号源数据", "*.xlsx") if not excel_path: print("未选择Excel文件,退出") sys.exit() word_path = select_file("Word", "选择信号源原始记录模板", "*.docx") if not word_path: print("未选择Word文件,退出") sys.exit() # 处理文件 lieshulist = None try: # 使用临时文件副本 # word_path = "信号源原始记录.docx" # temp_word_path = os.path.join(temp_dir.name, "temp_output.docx") lieshulist = list(pd.read_excel("信号源数据列数.xlsx")["列数"]) excel_sheets_to_word(excel_path, word_path, lieshulist, "确定度.xlsx") # shutil.copy(temp_word_path, "最终输出.docx") finally: # 清理资源 del lieshulist # temp_dir.cleanup() import gc gc.collect() print("处理完成") input('按回车退出程序...') # excel_path = select_file("Excel", "选择信号源数据", "*.xlsx") # if not excel_path: # 用户取消了选择 # print("未选择Excel文件,程序退出") # exit() # # # 选择Word文件 # word_path = select_file("Word", "选择信号源原始记录模板", "*.docx") # if not word_path: # 用户取消了选择 # print("未选择Word文件,程序退出") # exit() # # excel_path = "信号源数据模板.xlsx" # Excel文件路径 # # word_path = "信号源原始记录.docx" # 输出Word路径 # buquedingdu="确定度.xlsx" # lieshulist=list(pd.read_excel("信号源数据列数.xlsx")["列数"]) # # excel_sheets_to_word(excel_path, word_path, lieshulist,buquedingdu) # # print("原始记录或证书出具完毕") # input('输入任意字符退出程序……')打包以上程序为exe文件,方便在其他电脑上使用
最新发布
09-05
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值