Extending attachment functions

This commit is contained in:
John Whitington 2015-09-26 19:51:22 +01:00
parent 82cb349e92
commit a68136c6c2
2 changed files with 79 additions and 77 deletions

154
cpdf.ml
View File

@ -673,89 +673,91 @@ let presentation range t d h i dir effect_dur pdf =
Pdfpage.change_pages true pdf pages' Pdfpage.change_pages true pdf pages'
(* Attaching files *) (* Attaching files *)
let make_filestream file = let attach_file ?memory keepversion topage pdf file =
let data = let data =
let ch = open_in_bin file in match memory with
let len = in_channel_length ch in Some data -> data
let stream = mkbytes len in | None ->
let i = input_of_channel ch in let ch = open_in_bin file in
setinit i stream 0 len; let len = in_channel_length ch in
close_in ch; let stream = mkbytes len in
stream let i = input_of_channel ch in
setinit i stream 0 len;
close_in ch;
stream
in in
Pdf.Stream let filestream =
(ref (Pdf.Dictionary Pdf.Stream
[("/Length", Pdf.Integer (bytes_size data)); (ref (Pdf.Dictionary
("/Type", Pdf.Name "/EmbeddedFile")], [("/Length", Pdf.Integer (bytes_size data));
Pdf.Got data)) ("/Type", Pdf.Name "/EmbeddedFile")],
Pdf.Got data))
let attach_file keepversion topage pdf file = in
let filestream = make_filestream file in let filestream_num = Pdf.addobj pdf filestream in
let filestream_num = Pdf.addobj pdf filestream in let filespec =
let filespec = Pdf.Dictionary
Pdf.Dictionary [("/EF", Pdf.Dictionary ["/F", Pdf.Indirect filestream_num]);
[("/EF", Pdf.Dictionary ["/F", Pdf.Indirect filestream_num]); ("/F", Pdf.String (Filename.basename file));
("/F", Pdf.String (Filename.basename file)); ("/Type", Pdf.Name "/F")]
("/Type", Pdf.Name "/F")] in
in match topage with
match topage with | None ->
| None -> (* Look up /Names and /EmbeddedFiles and /Names. *)
(* Look up /Names and /EmbeddedFiles and /Names. *) let rootdict = Pdf.lookup_obj pdf pdf.Pdf.root in
let rootdict = Pdf.lookup_obj pdf pdf.Pdf.root in let namedict =
let namedict = match Pdf.lookup_direct pdf "/Names" rootdict with
match Pdf.lookup_direct pdf "/Names" rootdict with
| None -> Pdf.Dictionary []
| Some namedict -> namedict
in
let embeddednamedict =
match Pdf.lookup_direct pdf "/EmbeddedFiles" namedict with
| None -> Pdf.Dictionary [] | None -> Pdf.Dictionary []
| Some embeddednamedict -> embeddednamedict | Some namedict -> namedict
in in
let elts = let embeddednamedict =
match Pdf.lookup_direct pdf "/Names" embeddednamedict with match Pdf.lookup_direct pdf "/EmbeddedFiles" namedict with
| Some (Pdf.Array elts) -> elts | None -> Pdf.Dictionary []
| _ -> [] | Some embeddednamedict -> embeddednamedict
in in
let names' = Pdf.Array (elts @ [Pdf.String (Filename.basename file); filespec]) in let elts =
let embeddednamedict' = Pdf.add_dict_entry embeddednamedict "/Names" names' in match Pdf.lookup_direct pdf "/Names" embeddednamedict with
let namedict' = Pdf.add_dict_entry namedict "/EmbeddedFiles" embeddednamedict' in | Some (Pdf.Array elts) -> elts
let rootdict' = Pdf.add_dict_entry rootdict "/Names" namedict' in | _ -> []
let rootnum = Pdf.addobj pdf rootdict' in
{pdf with
Pdf.minor = if keepversion then pdf.Pdf.minor else max pdf.Pdf.minor 4;
Pdf.root = rootnum;
Pdf.trailerdict =
Pdf.add_dict_entry
pdf.Pdf.trailerdict "/Root" (Pdf.Indirect rootnum)}
| Some pagenumber ->
let pages = Pdfpage.pages_of_pagetree pdf in
if pagenumber < 0 || pagenumber > length pages then error "attach_file: Page not found" else
let page = select pagenumber pages in
let annots =
match Pdf.lookup_direct pdf "/Annots" page.Pdfpage.rest with
| Some (Pdf.Array annots) -> annots
| _ -> []
in
let rect =
let minx, miny, maxx, maxy = Pdf.parse_rectangle page.Pdfpage.mediabox in
Pdf.Array [Pdf.Real 18.; Pdf.Real (maxy -. 45.); Pdf.Real 45.; Pdf.Real (maxy -. 18.)]
in in
let annot = let names' = Pdf.Array (elts @ [Pdf.String (Filename.basename file); filespec]) in
Pdf.Dictionary let embeddednamedict' = Pdf.add_dict_entry embeddednamedict "/Names" names' in
[("/FS", filespec); let namedict' = Pdf.add_dict_entry namedict "/EmbeddedFiles" embeddednamedict' in
("/Subtype", Pdf.Name "/FileAttachment"); let rootdict' = Pdf.add_dict_entry rootdict "/Names" namedict' in
("/Contents", Pdf.String (Filename.basename file)); let rootnum = Pdf.addobj pdf rootdict' in
("/Rect", rect)] {pdf with
Pdf.minor = if keepversion then pdf.Pdf.minor else max pdf.Pdf.minor 4;
Pdf.root = rootnum;
Pdf.trailerdict =
Pdf.add_dict_entry
pdf.Pdf.trailerdict "/Root" (Pdf.Indirect rootnum)}
| Some pagenumber ->
let pages = Pdfpage.pages_of_pagetree pdf in
if pagenumber < 0 || pagenumber > length pages then error "attach_file: Page not found" else
let page = select pagenumber pages in
let annots =
match Pdf.lookup_direct pdf "/Annots" page.Pdfpage.rest with
| Some (Pdf.Array annots) -> annots
| _ -> []
in
let rect =
let minx, miny, maxx, maxy = Pdf.parse_rectangle page.Pdfpage.mediabox in
Pdf.Array [Pdf.Real 18.; Pdf.Real (maxy -. 45.); Pdf.Real 45.; Pdf.Real (maxy -. 18.)]
in in
let annots' = Pdf.Array (annot::annots) in let annot =
let page' = Pdf.Dictionary
{page with Pdfpage.rest = Pdf.add_dict_entry page.Pdfpage.rest "/Annots" annots'} [("/FS", filespec);
in ("/Subtype", Pdf.Name "/FileAttachment");
let pages' = replace_number pagenumber page' pages in ("/Contents", Pdf.String (Filename.basename file));
let pdf = Pdfpage.change_pages false pdf pages' in ("/Rect", rect)]
{pdf with in
Pdf.minor = if keepversion then pdf.Pdf.minor else max pdf.Pdf.minor 4} let annots' = Pdf.Array (annot::annots) in
let page' =
{page with Pdfpage.rest = Pdf.add_dict_entry page.Pdfpage.rest "/Annots" annots'}
in
let pages' = replace_number pagenumber page' pages in
let pdf = Pdfpage.change_pages false pdf pages' in
{pdf with
Pdf.minor = if keepversion then pdf.Pdf.minor else max pdf.Pdf.minor 4}
let list_attached_files pdf = let list_attached_files pdf =
let toplevel = let toplevel =

View File

@ -149,7 +149,7 @@ val presentation : int list -> string option ->
(** {2 File Attachments} *) (** {2 File Attachments} *)
(** [attach_file keepversion topage pdf filename] attaches the file in [filename] to the pdf, optionally to a page (rather than document-level). If keepversion is true, the PDF version number won't be altered. *) (** [attach_file keepversion topage pdf filename] attaches the file in [filename] to the pdf, optionally to a page (rather than document-level). If keepversion is true, the PDF version number won't be altered. *)
val attach_file : bool -> int option -> Pdf.t -> string -> Pdf.t val attach_file : ?memory:Pdfio.bytes -> bool -> int option -> Pdf.t -> string -> Pdf.t
(** Remove attached files. *) (** Remove attached files. *)
val remove_attached_files : Pdf.t -> Pdf.t val remove_attached_files : Pdf.t -> Pdf.t