8
8
from datetime import datetime
9
9
from functools import total_ordering
10
10
from io import BytesIO
11
+ import itertools
11
12
import logging
12
13
import math
13
14
import os
14
- import pathlib
15
15
import re
16
16
import struct
17
17
import time
90
90
# * encoding of fonts, including mathtext fonts and unicode support
91
91
# * TTF support has lots of small TODOs, e.g., how do you know if a font
92
92
# is serif/sans-serif, or symbolic/non-symbolic?
93
- # * draw_markers, draw_line_collection, etc.
93
+ # * draw_quad_mesh
94
94
95
95
96
96
def fill (strings , linelen = 75 ):
@@ -348,11 +348,22 @@ class Stream:
348
348
__slots__ = ('id' , 'len' , 'pdfFile' , 'file' , 'compressobj' , 'extra' , 'pos' )
349
349
350
350
def __init__ (self , id , len , file , extra = None , png = None ):
351
- """id: object id of stream; len: an unused Reference object for the
352
- length of the stream, or None (to use a memory buffer); file:
353
- a PdfFile; extra: a dictionary of extra key-value pairs to
354
- include in the stream header; png: if the data is already
355
- png compressed, the decode parameters"""
351
+ """
352
+ Parameters
353
+ ----------
354
+
355
+ id : int
356
+ Object id of the stream.
357
+ len : Reference or None
358
+ An unused Reference object for the length of the stream;
359
+ None means to use a memory buffer so the length can be inlined.
360
+ file : PdfFile
361
+ The underlying object to write the stream to.
362
+ extra : dict from Name to anything, or None
363
+ Extra key-value pairs to include in the stream header.
364
+ png : dict or None
365
+ If the data is already png encoded, the decode parameters.
366
+ """
356
367
self .id = id # object id
357
368
self .len = len # id of length object
358
369
self .pdfFile = file
@@ -424,7 +435,25 @@ class PdfFile:
424
435
"""PDF file object."""
425
436
426
437
def __init__ (self , filename , metadata = None ):
427
- self .nextObject = 1 # next free object id
438
+ """
439
+ Parameters
440
+ ----------
441
+
442
+ filename : file-like object or string
443
+ Output target; if a string, a file will be opened for writing.
444
+ metadata : dict from strings to strings and dates
445
+ Information dictionary object (see PDF reference section 10.2.1
446
+ 'Document Information Dictionary'), e.g.:
447
+ `{'Creator': 'My software', 'Author': 'Me',
448
+ 'Title': 'Awesome fig'}`.
449
+
<
629A
tr class="diff-line-row">
450
+ The standard keys are `'Title'`, `'Author'`, `'Subject'`,
451
+ `'Keywords'`, `'Creator'`, `'Producer'`, `'CreationDate'`,
452
+ `'ModDate'`, and `'Trapped'`. Values have been predefined
453
+ for `'Creator'`, `'Producer'` and `'CreationDate'`. They
454
+ can be removed by setting them to `None`.
455
+ """
456
+ self ._object_seq = itertools .count (1 ) # consumed by reserveObject
428
457
self .xrefTable = [[0 , 65535 , 'the zero object' ]]
429
458
self .passed_in_file_object = False
430
459
self .original_file_like = None
@@ -482,21 +511,21 @@ def __init__(self, filename, metadata=None):
482
511
if v is not None }
483
512
484
513
self .fontNames = {} # maps filenames to internal font names
485
- self .nextFont = 1 # next free internal font name
514
+ self ._internal_font_seq = ( Name ( f'F { i } ' ) for i in itertools . count ( 1 ))
486
515
self .dviFontInfo = {} # maps dvi font names to embedding information
487
516
# differently encoded Type-1 fonts may share the same descriptor
488
517
self .type1Descriptors = {}
489
518
self .used_characters = {}
490
519
491
520
self .alphaStates = {} # maps alpha values to graphics state objects
492
- self .nextAlphaState = 1
521
+ self ._alpha_state_seq = ( Name ( f'A { i } ' ) for i in itertools . count ( 1 ))
493
522
# reproducible writeHatches needs an ordered dict:
494
523
self .hatchPatterns = collections .OrderedDict ()
495
- self .nextHatch = 1
524
+ self ._hatch_pattern_seq = ( Name ( f'H { i } ' ) for i in itertools . count ( 1 ))
496
525
self .gouraudTriangles = []
497
526
498
527
self ._images = collections .OrderedDict () # reproducible writeImages
499
- self .nextImage = 1
528
+ self ._image_seq = ( Name ( f'I { i } ' ) for i in itertools . count ( 1 ))
500
529
501
530
self .markers = collections .OrderedDict () # reproducible writeMarkers
502
531
self .multi_byte_charprocs = {}
@@ -643,9 +672,8 @@ def fontName(self, fontprop):
643
672
644
673
Fx = self .fontNames .get (filename )
645
674
if Fx is None :
646
- Fx = Name ( 'F%d' % self .nextFont )
675
+ Fx = next ( self ._internal_font_seq )
647
676
self .fontNames [filename ] = Fx
648
- self .nextFont += 1
649
677
_log .debug ('Assigning font %s = %r' , Fx , filename )
650
678
651
679
return Fx
@@ -669,8 +697,7 @@ def dviFontName(self, dvifont):
669
697
"the font may lack a Type-1 version"
670
698
.format (psfont .psname , dvifont .texname ))
671
699
672
- pdfname = Name ('F%d' % self .nextFont )
673
- self .nextFont += 1
700
+ pdfname = next (self ._internal_font_seq )
674
701
_log .debug ('Assigning font %s = %s (dvi)' , pdfname , dvifont .texname )
675
702
self .dviFontInfo [dvifont .texname ] = types .SimpleNamespace (
676
703
dvifont = dvifont ,
@@ -1186,8 +1213,7 @@ def alphaState(self, alpha):
1186
1213
if state is not None :
1187
1214
return state [0 ]
1188
1215
1189
- name = Name ('A%d' % self .nextAlphaState )
1190
- self .nextAlphaState += 1
1216
+ name = next (self ._alpha_state_seq )
1191
1217
self .alphaStates [alpha ] = \
1192
1218
(name , {'Type' : Name ('ExtGState' ),
1193
1219
'CA' : alpha [0 ], 'ca' : alpha [1 ]})
@@ -1207,8 +1233,7 @@ def hatchPattern(self, hatch_style):
1207
1233
if pattern is not None :
1208
1234
return pattern
1209
1235
1210
- name = Name ('H%d' % self .nextHatch )
1211
- self .nextHatch += 1
1236
+ name = next (self ._hatch_pattern_seq )
1212
1237
self .hatchPatterns [hatch_style ] = name
1213
1238
return name
1214
1239
@@ -1300,9 +1325,8 @@ def imageObject(self, image):
1300
1325
if entry is not None :
1301
1326
return entry [1 ]
1302
1327
1303
- name = Name ('I%d' % self .nextImage )
1304
- ob = self .reserveObject ('image %d' % self .nextImage )
1305
- self .nextImage += 1
1328
+ name = next (self ._image_seq )
1329
+ ob = self .reserveObject (f'image { name } ' )
1306
1330
self ._images [id (image )] = (image , name , ob )
1307
1331
return name
1308
1332
@@ -1495,8 +1519,7 @@ def reserveObject(self, name=''):
1495
1519
the object with writeObject.
1496
1520
"""
1497
1521
1498
- id = self .nextObject
1499
- self .nextObject += 1
1522
+ id = next (self ._object_seq )
1500
1523
self .xrefTable .append ([None , 0 , name ])
1501
1524
return Reference (id )
1502
1525
@@ -1510,7 +1533,7 @@ def writeObject(self, object, contents):
1510
1533
def writeXref (self ):
1511
1534
"""Write out the xref table."""
1512
1535
self .startxref = self .fh .tell () - self .tell_base
1513
- self .write (b"xref\n 0 %d\n " % self .nextObject )
1536
+ self .write (b"xref\n 0 %d\n " % len ( self .xrefTable ) )
1514
1537
for i , (offset , generation , name ) in enumerate (self .xrefTable ):
1515
1538
if offset is None :
1516
1539
raise AssertionError (
@@ -1557,7 +1580,7 @@ def writeTrailer(self):
1557
1580
1558
1581
self .write (b"trailer\n " )
1559
1582
self .write (pdfRepr (
1560
- {'Size' : self .nextObject ,
1583
+ {'Size' : len ( self .xrefTable ) ,
1561
1584
'Root' : self .rootObject ,
1562
1585
'Info' : self .infoObject }))
1563
1586
# Could add 'ID'
@@ -2316,13 +2339,6 @@ def finalize(self):
2316
2339
cmds .extend (self .pop ())
2317
2340
return cmds
2318
2341
2319
- ########################################################################
2320
- #
2321
- # The following functions and classes are for pylab and implement
2322
- # window/figure managers, etc...
2323
- #
2324
- ########################################################################
2325
-
2326
2342
2327
2343
class PdfPages :
2328
2344
"""
0 commit comments