From 5c580298444cfff7d9ca0e671c39b8ad813c0863 Mon Sep 17 00:00:00 2001 From: John Whitington Date: Wed, 26 Feb 2025 16:37:27 +0000 Subject: [PATCH] Support PDF/UA annotations --- cpdfcommand.ml | 3 ++- cpdftoc.ml | 6 +++--- cpdftoc.mli | 2 +- cpdftype.ml | 16 ++++++++++------ cpdftype.mli | 2 +- 5 files changed, 17 insertions(+), 12 deletions(-) diff --git a/cpdfcommand.ml b/cpdfcommand.ml index 3a7f34b..2eba76a 100644 --- a/cpdfcommand.ml +++ b/cpdfcommand.ml @@ -4783,7 +4783,8 @@ let go () = let cpdffont = embed_font () in let pdf = Cpdftoc.typeset_table_of_contents - ~font:cpdffont ~fontsize:args.fontsize ~title:args.toc_title ~bookmark:args.toc_bookmark ~dotleader:args.dot_leader pdf + ~font:cpdffont ~fontsize:args.fontsize ~title:args.toc_title + ~bookmark:args.toc_bookmark ~dotleader:args.dot_leader ~process_struct_tree:args.process_struct_trees pdf in write_pdf false pdf | Some (Typeset filename) -> diff --git a/cpdftoc.ml b/cpdftoc.ml index 5d8301c..a498be5 100644 --- a/cpdftoc.ml +++ b/cpdftoc.ml @@ -106,7 +106,7 @@ let make_dots space fontpack fontsize = (and CropBox) copied from first page of existing PDF. Margin of 10% inside CropBox. Font size of title twice body font size. Null page labels added for TOC, others bumped up and so preserved. *) -let typeset_table_of_contents ~font ~fontsize ~title ~bookmark ~dotleader pdf = +let typeset_table_of_contents ~font ~fontsize ~title ~bookmark ~dotleader ~process_struct_tree pdf = Hashtbl.clear width_table_cache; let marks = Pdfmarks.read_bookmarks pdf in if marks = [] then (Pdfe.log "No bookmarks, not making table of contents\n"; pdf) else @@ -158,7 +158,7 @@ let typeset_table_of_contents ~font ~fontsize ~title ~bookmark ~dotleader pdf = then make_dots space fontpack fontsize else [Cpdftype.HGlue space] in - [Cpdftype.BeginDest mark.Pdfmarks.target; Cpdftype.HGlue indent] @ textruns @ leader @ labelruns + [Cpdftype.BeginDest (mark.Pdfmarks.target, Some mark.Pdfmarks.text); Cpdftype.HGlue indent] @ textruns @ leader @ labelruns @ [Cpdftype.EndDest; Cpdftype.NewLine]) (Pdfmarks.read_bookmarks pdf) in @@ -181,7 +181,7 @@ let typeset_table_of_contents ~font ~fontsize ~title ~bookmark ~dotleader pdf = let firstfont = hd (keep (function Cpdftype.Font _ -> true | _ -> false) (title @ flatten lines)) in - Cpdftype.typeset ~process_struct_tree:false lm rm tm bm firstpage_papersize pdf + Cpdftype.typeset ~process_struct_tree lm rm tm bm firstpage_papersize pdf ([firstfont; Cpdftype.BeginDocument] @ title @ flatten lines) in let toc_pages = diff --git a/cpdftoc.mli b/cpdftoc.mli index bc8509a..6ff4ecd 100644 --- a/cpdftoc.mli +++ b/cpdftoc.mli @@ -1,4 +1,4 @@ (** Table of contents *) (** Typeset a table of contents and prepend to the document. *) -val typeset_table_of_contents : font:Cpdfembed.cpdffont -> fontsize:float -> title:string -> bookmark:bool -> dotleader:bool -> Pdf.t -> Pdf.t +val typeset_table_of_contents : font:Cpdfembed.cpdffont -> fontsize:float -> title:string -> bookmark:bool -> dotleader:bool -> process_struct_tree:bool -> Pdf.t -> Pdf.t diff --git a/cpdftype.ml b/cpdftype.ml index 552ff11..b64c9a9 100644 --- a/cpdftype.ml +++ b/cpdftype.ml @@ -15,7 +15,7 @@ type element = | NewLine | NewPage | Font of string * Pdftext.font * float -| BeginDest of Pdfdest.t +| BeginDest of Pdfdest.t * string option | EndDest | BeginDocument | Tag of string * int @@ -45,7 +45,7 @@ type state = mutable width_table : float array; (* Widths for charcodes 0..255 *) mutable xpos : float; mutable ypos : float; - mutable dest : Pdfdest.t option} + mutable dest : (Pdfdest.t * string option) option} let width_table_cache = null_hash () @@ -232,7 +232,8 @@ let make_resources fontobjnums = let make_annotations pdf annots = if annots = [] then Pdf.Dictionary [] else - Pdf.Dictionary ["/Annots", Pdf.Array (map (function a -> Pdf.Indirect (Pdf.addobj pdf a)) annots)] + Pdf.Dictionary ["/Annots", Pdf.Array (map (function a -> Pdf.Indirect (Pdf.addobj pdf a)) annots); + "/Tabs", Pdf.Name "/S"] let rec number_tags n = function | Tag (s, _)::t -> Tag (s, n)::number_tags (n + 1) t @@ -329,17 +330,20 @@ let typeset ~process_struct_tree lmargin rmargin tmargin bmargin papersize pdf i s.ypos <- tmargin +. s.fontsize | BeginDocument -> s.ypos <- tmargin +. s.fontsize - | BeginDest dest -> - s.dest <- Some dest + | BeginDest (dest, contents) -> + s.dest <- Some (dest, contents) | EndDest -> if !thisdestrectangles <> [] && s.dest <> None then let annot (minx, miny, maxx, maxy) = + let dest, contents = unopt s.dest in Pdf.Dictionary + ((match contents with None -> [] | Some s -> [("/Contents", Pdf.String s)]) + @ [("/Type", Pdf.Name "/Annot"); ("/Subtype", Pdf.Name "/Link"); ("/Border", Pdf.Array [Pdf.Real 0.; Pdf.Real 0.; Pdf.Real 0.]); ("/Rect", Pdf.Array [Pdf.Real minx; Pdf.Real miny; Pdf.Real maxx; Pdf.Real maxy]); - ("/Dest", Pdfdest.pdfobject_of_destination (unopt s.dest))] + ("/Dest", Pdfdest.pdfobject_of_destination dest)]) in thispageannotations := map annot !thisdestrectangles @ !thispageannotations; s.dest <- None; diff --git a/cpdftype.mli b/cpdftype.mli index b120577..5b43510 100644 --- a/cpdftype.mli +++ b/cpdftype.mli @@ -6,7 +6,7 @@ type element = | NewLine | NewPage | Font of string * Pdftext.font * float -| BeginDest of Pdfdest.t +| BeginDest of Pdfdest.t * string option | EndDest | BeginDocument | Tag of string * int