@@ -694,7 +694,13 @@ def __init__(self, filename, metadata=None):
694694
695695 self .paths = []
696696
697- self .pageAnnotations = [] # A list of annotations for the current page
697+ # A list of annotations for each page. Each entry is a tuple of the
698+ # overall Annots object reference that's inserted into the page object,
699+ # followed by a list of the actual annotations.
700+ self ._annotations = []
701+ # For annotations added before a page is created; mostly for the
702+ # purpose of newTextnote.
703+ self .pageAnnotations = []
698704
699705 # The PDF spec recommends to include every procset
700706 procsets = [Name (x ) for x in "PDF Text ImageB ImageC ImageI" .split ()]
@@ -720,6 +726,7 @@ def newPage(self, width, height):
720726
721727 self .width , self .height = width , height
722728 contentObject = self .reserveObject ('page contents' )
729+ annotsObject = self .reserveObject ('annotations' )
723730 thePage = {'Type' : Name ('Page' ),
724731 'Parent' : self .pagesObject ,
725732 'Resources' : self .resourceObject ,
@@ -728,11 +735,12 @@ def newPage(self, width, height):
728735 'Group' : {'Type' : Name ('Group' ),
729736 'S' : Name ('Transparency' ),
730737 'CS' : Name ('DeviceRGB' )},
731- 'Annots' : self . pageAnnotations ,
738+ 'Annots' : annotsObject ,
732739 }
733740 pageObject = self .reserveObject ('page' )
734741 self .writeObject (pageObject , thePage )
735742 self .pageList .append (pageObject )
743+ self ._annotations .append ((annotsObject , self .pageAnnotations ))
736744
737745 self .beginStream (contentObject .id ,
738746 self .reserveObject ('length of content stream' ))
@@ -750,14 +758,13 @@ def newTextnote(self, text, positionRect=[-100, -100, 0, 0]):
750758 'Contents' : text ,
751759 'Rect' : positionRect ,
752760 }
753- annotObject = self .reserveObject ('annotation' )
754- self .writeObject (annotObject , theNote )
755- self .pageAnnotations .append (annotObject )
761+ self .pageAnnotations .append (theNote )
756762
757763 def finalize (self ):
758764 """Write out the various deferred objects and the pdf end matter."""
759765
760766 self .endStream ()
767+ self ._write_annotations ()
761768 self .writeFonts ()
762769 self .writeExtGSTates ()
763770 self ._write_soft_mask_groups ()
@@ -816,6 +823,10 @@ def endStream(self):
816823 self .currentstream .end ()
817824 self .currentstream = None
818825
826+ def _write_annotations (self ):
827+ for annotsObject , annotations in self ._annotations :
828+ self .writeObject (annotsObject , annotations )
829+
819830 def fontName (self , fontprop ):
820831 """
821832 Select a font based on fontprop and return a name suitable for
@@ -2095,6 +2106,19 @@ def draw_mathtext(self, gc, x, y, s, prop, angle):
20952106 width , height , descent , glyphs , rects = \
20962107 self ._text2path .mathtext_parser .parse (s , 72 , prop )
20972108
2109+ if gc .get_url () is not None :
2110+ link_annotation = {
2111+ 'Type' : Name ('Annot' ),
2112+ 'Subtype' : Name ('Link' ),
2113+ 'Rect' : (x , y , x + width , y + height ),
2114+ 'Border' : [0 , 0 , 0 ],
2115+ 'A' : {
2116+ 'S' : Name ('URI' ),
2117+ 'URI' : gc .get_url (),
2118+ },
2119+ }
2120+ self .file ._annotations [- 1 ][1 ].append (link_annotation )
2121+
20982122 global_fonttype = mpl .rcParams ['pdf.fonttype' ]
20992123
21002124 # Set up a global transformation matrix for the whole math expression
@@ -2151,6 +2175,19 @@ def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!', mtext=None):
21512175 with dviread .Dvi (dvifile , 72 ) as dvi :
21522176 page , = dvi
21532177
2178+ if gc .get_url () is not None :
2179+ link_annotation = {
2180+ 'Type' : Name ('Annot' ),
2181+ 'Subtype' : Name ('Link' ),
2182+ 'Rect' : (x , y , x + page .width , y + page .height ),
2183+ 'Border' : [0 , 0 , 0 ],
2184+ 'A' : {
2185+ 'S' : Name ('URI' ),
2186+ 'URI' : gc .get_url (),
2187+ },
2188+ }
2189+ self .file ._annotations [- 1 ][1 ].append (link_annotation )
2190+
21542191 # Gather font information and do some setup for combining
21552192 # characters into strings. The variable seq will contain a
21562193 # sequence of font and text entries. A font entry is a list
@@ -2250,6 +2287,21 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
22502287 if is_opentype_cff_font (font .fname ):
22512288 fonttype = 42
22522289
2290+ if gc .get_url () is not None :
2291+ font .set_text (s )
2292+ width , height = font .get_width_height ()
2293+ link_annotation = {
2294+ 'Type' : Name ('Annot' ),
2295+ 'Subtype' : Name ('Link' ),
2296+ 'Rect' : (x , y , x + width / 64 , y + height / 64 ),
2297+ 'Border' : [0 , 0 , 0 ],
2298+ 'A' : {
2299+ 'S' : Name ('URI' ),
2300+ 'URI' : gc .get_url (),
2301+ },
2302+ }
2303+ self .file ._annotations [- 1 ][1 ].append (link_annotation )
2304+
22532305 # If fonttype != 3 or there are no multibyte characters, emit the whole
22542306 # string at once.
22552307 if fonttype != 3 or all (ord (char ) <= 255 for char in s ):
0 commit comments