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