@@ -950,7 +950,7 @@ def writeFonts(self):
950
950
_log .debug ('Writing TrueType font.' )
951
951
charmap = self ._character_tracker .used .get ((filename , subset ))
952
952
if charmap :
953
- fonts [Fx ] = self .embedTTF (filename , charmap )
953
+ fonts [Fx ] = self .embedTTF (filename , subset , charmap )
954
954
self .writeObject (self .fontObject , fonts )
955
955
956
956
def _write_afm_font (self , filename ):
@@ -1117,7 +1117,7 @@ def createType1Descriptor(self, t1font, fontfile=None):
1117
1117
end
1118
1118
end"""
1119
1119
1120
- def embedTTF (self , filename , charmap ):
1120
+ def embedTTF (self , filename , subset_index , charmap ):
1121
1121
"""Embed the TTF font from the named file into the document."""
1122
1122
font = get_font (filename )
1123
1123
fonttype = mpl .rcParams ['pdf.fonttype' ]
@@ -1133,12 +1133,40 @@ def cvt(length, upe=font.units_per_EM, nearest=True):
1133
1133
else :
1134
1134
return math .ceil (value )
1135
1135
1136
- def embedTTFType3 (font , charmap , descriptor ):
1136
+ def generate_unicode_cmap (charmap ):
1137
+ # Make the ToUnicode CMap.
1138
+ last_ccode = - 2
1139
+ unicode_groups = []
1140
+ for ccode in sorted (charmap .keys ()):
1141
+ if ccode != last_ccode + 1 :
1142
+ unicode_groups .append ([ccode , ccode ])
1143
+ else :
1144
+ unicode_groups [- 1 ][1 ] = ccode
1145
+ last_ccode = ccode
1146
+
1147
+ width = 2 if fonttype == 3 else 4
1148
+ unicode_bfrange = []
1149
+ for start , end in unicode_groups :
1150
+ real_start = self ._character_tracker .subset_to_unicode (subset_index ,
1151
+ start )
1152
+ real_end = self ._character_tracker .subset_to_unicode (subset_index , end )
1153
+ real_values = ' ' .join ('<%s>' % chr (x ).encode ('utf-16be' ).hex ()
1154
+ for x in range (real_start , real_end + 1 ))
1155
+ unicode_bfrange .append (
1156
+ f'<{ start :0{width }x} > <{ end :0{width }x} > [{ real_values } ]' )
1157
+ unicode_cmap = (self ._identityToUnicodeCMap %
1158
+ (len (unicode_groups ),
1159
+ '\n ' .join (unicode_bfrange ).encode ('ascii' )))
1160
+
1161
+ return unicode_cmap
1162
+
1163
+ def embedTTFType3 (font , subset_index , charmap , descriptor ):
1137
1164
"""The Type 3-specific part of embedding a Truetype font"""
1138
1165
widthsObject = self .reserveObject ('font widths' )
1139
1166
fontdescObject = self .reserveObject ('font descriptor' )
1140
1167
fontdictObject = self .reserveObject ('font dictionary' )
1141
1168
charprocsObject = self .reserveObject ('character procs' )
1169
+ toUnicodeMapObject = self .reserveObject ('ToUnicode map' )
1142
1170
differencesArray = []
1143
1171
firstchar , lastchar = min (charmap ), max (charmap )
1144
1172
bbox = [cvt (x , nearest = False ) for x in font .bbox ]
@@ -1157,8 +1185,9 @@ def embedTTFType3(font, charmap, descriptor):
1157
1185
'Encoding' : {
1158
1186
'Type' : Name ('Encoding' ),
1159
1187
'Differences' : differencesArray },
1160
- 'Widths' : widthsObject
1161
- }
1188
+ 'Widths' : widthsObject ,
1189
+ 'ToUnicode' : toUnicodeMapObject ,
1190
+ }
1162
1191
1163
1192
# Make the "Widths" array
1164
1193
def get_char_width (charcode ):
@@ -1191,15 +1220,18 @@ def get_char_width(charcode):
1191
1220
self .outputStream (charprocObject , stream )
1192
1221
charprocs [charname ] = charprocObject
1193
1222
1223
+ unicode_cmap = generate_unicode_cmap (charmap )
1224
+
1194
1225
# Write everything out
1195
1226
self .writeObject (fontdictObject , fontdict )
1196
1227
self .writeObject (fontdescObject , descriptor )
1197
1228
self .writeObject (widthsObject , widths )
1198
1229
self .writeObject (charprocsObject , charprocs )
1230
+ self .outputStream (toUnicodeMapObject , unicode_cmap )
1199
1231
1200
1232
return fontdictObject
1201
1233
1202
- def embedTTFType42 (font , charmap , descriptor ):
1234
+ def embedTTFType42 (font , subset_index , charmap , descriptor ):
1203
1235
"""The Type 42-specific part of embedding a Truetype font"""
1204
1236
fontdescObject = self .reserveObject ('font descriptor' )
1205
1237
cidFontDictObject = self .reserveObject ('CID font dictionary' )
@@ -1209,12 +1241,12 @@ def embedTTFType42(font, charmap, descriptor):
1209
1241
wObject = self .reserveObject ('Type 0 widths' )
1210
1242
toUnicodeMapObject = self .reserveObject ('ToUnicode map' )
1211
1243
1212
- _log .debug ("SUBSET %s characters: %s" , filename , charmap )
1244
+ _log .debug ("SUBSET %s:%d characters: %s" , filename , subset_index , charmap )
1213
1245
with _backend_pdf_ps .get_glyphs_subset (filename ,
1214
1246
charmap .values ()) as subset :
1215
1247
fontdata = _backend_pdf_ps .font_as_file (subset )
1216
1248
_log .debug (
1217
- "SUBSET %s %d -> %d" , filename ,
1249
+ "SUBSET %s:%d %d -> %d" , filename , subset_index ,
1218
1250
os .stat (filename ).st_size , fontdata .getbuffer ().nbytes
1219
1251
)
1220
1252
@@ -1251,55 +1283,37 @@ def embedTTFType42(font, charmap, descriptor):
1251
1283
fontfileObject , fontdata .getvalue (),
1252
1284
extra = {'Length1' : fontdata .getbuffer ().nbytes })
1253
1285
1254
- # Make the 'W' (Widths) array, CidToGidMap and ToUnicode CMap
1255
- # at the same time
1286
+ # Make the 'W' (Widths) array and CidToGidMap at the same time.
1256
1287
cid_to_gid_map = ['\0 ' ] * 65536
1257
1288
widths = []
1258
1289
max_ccode = 0
1259
1290
for ccode , gind in charmap .items ():
1260
1291
glyph = font .load_glyph (gind ,
1261
1292
flags = LoadFlags .NO_SCALE | LoadFlags .NO_HINTING )
1262
1293
widths .append ((ccode , cvt (glyph .horiAdvance )))
1263
- if ccode < 65536 :
1264
- cid_to_gid_map [ccode ] = chr (gind )
1294
+ cid_to_gid_map [ccode ] = chr (gind )
1265
1295
max_ccode = max (ccode , max_ccode )
1266
1296
widths .sort ()
1267
1297
cid_to_gid_map = cid_to_gid_map [:max_ccode + 1 ]
1268
1298
1269
1299
last_ccode = - 2
1270
1300
w = []
1271
1301
max_width = 0
1272
- unicode_groups = []
1273
1302
for ccode , width in widths :
1274
1303
if ccode != last_ccode + 1 :
1275
1304
w .append (ccode )
1276
1305
w .append ([width ])
1277
- unicode_groups .append ([ccode , ccode ])
1278
1306
else :
1279
1307
w [- 1 ].append (width )
1280
- unicode_groups [- 1 ][1 ] = ccode
1281
1308
max_width = max (max_width , width )
1282
1309
last_ccode = ccode
1283
1310
1284
- unicode_bfrange = []
1285
- for start , end in unicode_groups :
1286
- # Ensure the CID map contains only chars from BMP
1287
- if start > 65535 :
1288
- continue
1289
- end = min (65535 , end )
1290
-
1291
- unicode_bfrange .append (
1292
- b"<%04x> <%04x> [%s]" %
1293
- (start , end ,
1294
- b" " .join (b"<%04x>" % x for x in range (start , end + 1 ))))
1295
- unicode_cmap = (self ._identityToUnicodeCMap %
1296
- (len (unicode_groups ), b"\n " .join (unicode_bfrange )))
1297
-
1298
1311
# CIDToGIDMap stream
1299
1312
cid_to_gid_map = "" .join (cid_to_gid_map ).encode ("utf-16be" )
1300
1313
self .outputStream (cidToGidMapObject , cid_to_gid_map )
1301
1314
1302
1315
# ToUnicode CMap
1316
+ unicode_cmap = generate_unicode_cmap (charmap )
1303
1317
self .outputStream (toUnicodeMapObject , unicode_cmap )
1304
1318
1305
1319
descriptor ['MaxWidth' ] = max_width
@@ -1355,9 +1369,9 @@ def embedTTFType42(font, charmap, descriptor):
1355
1369
}
1356
1370
1357
1371
if fonttype == 3 :
1358
- return embedTTFType3 (font , charmap , descriptor )
1372
+ return embedTTFType3 (font , subset_index , charmap , descriptor )
1359
1373
elif fonttype == 42 :
1360
- return embedTTFType42 (font , charmap , descriptor )
1374
+ return embedTTFType42 (font , subset_index , charmap , descriptor )
1361
1375
1362
1376
def alphaState (self , alpha ):
1363
1377
"""Return name of an ExtGState that sets alpha to the given value."""
0 commit comments