Split off a little code
This commit is contained in:
parent
1377c5af83
commit
5ae9ffe25f
2
Makefile
2
Makefile
|
@ -1,6 +1,6 @@
|
|||
# Build the cpdf command line tools and top level
|
||||
MODS = cpdfstream tjutil tjutf16 tjllist tjparsermonad tjjson \
|
||||
xmlm cpdfjson cpdfstrftime cpdfcoord \
|
||||
xmlm cpdferror cpdfjson cpdfstrftime cpdfcoord cpdfattach \
|
||||
cpdfpagespec cpdfposition cpdf cpdfcommand
|
||||
|
||||
SOURCES = $(foreach x,$(MODS),$(x).ml $(x).mli) cpdfcommandrun.ml
|
||||
|
|
229
cpdf.ml
229
cpdf.ml
|
@ -1,6 +1,7 @@
|
|||
(* CPDF Core routines *)
|
||||
open Pdfutil
|
||||
open Pdfio
|
||||
open Cpdferror
|
||||
|
||||
let debug = ref false
|
||||
|
||||
|
@ -434,12 +435,6 @@ let protect fast pdf resources content =
|
|||
let qs = addstream (many Pdfops.Op_Q deficit @ [Pdfops.Op_Q]) in
|
||||
[Pdf.Indirect q] @ content @ [Pdf.Indirect qs]
|
||||
|
||||
exception SoftError of string
|
||||
|
||||
let error s = raise (SoftError s)
|
||||
|
||||
exception HardError of string
|
||||
|
||||
(* Union two resource dictionaries from the same PDF. *)
|
||||
let combine_pdf_resources pdf a b =
|
||||
let a_entries =
|
||||
|
@ -532,228 +527,6 @@ let presentation range t d h i dir effect_dur pdf =
|
|||
in
|
||||
Pdfpage.change_pages true pdf pages'
|
||||
|
||||
(* Attaching files *)
|
||||
let attach_file ?memory keepversion topage pdf file =
|
||||
let data =
|
||||
match memory with
|
||||
Some data -> data
|
||||
| None ->
|
||||
let ch = open_in_bin file in
|
||||
let len = in_channel_length ch in
|
||||
let stream = mkbytes len in
|
||||
let i = input_of_channel ch in
|
||||
setinit i stream 0 len;
|
||||
close_in ch;
|
||||
stream
|
||||
in
|
||||
let filestream =
|
||||
Pdf.Stream
|
||||
(ref (Pdf.Dictionary
|
||||
[("/Length", Pdf.Integer (bytes_size data));
|
||||
("/Type", Pdf.Name "/EmbeddedFile");
|
||||
("/Params",
|
||||
Pdf.Dictionary
|
||||
[("/Size", Pdf.Integer (bytes_size data));
|
||||
("/CheckSum", Pdf.String (Digest.string (string_of_bytes data)))
|
||||
])],
|
||||
Pdf.Got data))
|
||||
in
|
||||
let filestream_num = Pdf.addobj pdf filestream in
|
||||
let basename = Pdftext.pdfdocstring_of_utf8 (Filename.basename file) in
|
||||
let filespec =
|
||||
Pdf.Dictionary
|
||||
[("/EF", Pdf.Dictionary ["/F", Pdf.Indirect filestream_num]);
|
||||
("/F", Pdf.String basename);
|
||||
("/Type", Pdf.Name "/Filespec");
|
||||
("/Desc", Pdf.String "");
|
||||
("/UF", Pdf.String basename)]
|
||||
in
|
||||
match topage with
|
||||
| None ->
|
||||
(* Look up /Names and /EmbeddedFiles and /Names. *)
|
||||
let rootdict = Pdf.lookup_obj pdf pdf.Pdf.root in
|
||||
let namedict =
|
||||
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 []
|
||||
| Some embeddednamedict -> embeddednamedict
|
||||
in
|
||||
let elts =
|
||||
match Pdf.lookup_direct pdf "/Names" embeddednamedict with
|
||||
| Some (Pdf.Array elts) -> elts
|
||||
| _ -> []
|
||||
in
|
||||
let filespecobj = Pdf.addobj pdf filespec in
|
||||
let names' = Pdf.Array (elts @ [Pdf.String basename; Pdf.Indirect filespecobj]) in
|
||||
let embeddednamedict' = Pdf.add_dict_entry embeddednamedict "/Names" names' in
|
||||
let namedict' = Pdf.add_dict_entry namedict "/EmbeddedFiles" embeddednamedict' in
|
||||
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
|
||||
let filespecobj = Pdf.addobj pdf filespec in
|
||||
let annot =
|
||||
Pdf.Dictionary
|
||||
[("/FS", Pdf.Indirect filespecobj);
|
||||
("/Subtype", Pdf.Name "/FileAttachment");
|
||||
("/Contents", Pdf.String basename);
|
||||
("/Rect", rect)]
|
||||
in
|
||||
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 true pdf pages' in
|
||||
{pdf with
|
||||
Pdf.minor = if keepversion then pdf.Pdf.minor else max pdf.Pdf.minor 4}
|
||||
|
||||
type attachment =
|
||||
{name : string;
|
||||
pagenumber : int;
|
||||
data : unit -> Pdfio.bytes}
|
||||
|
||||
let list_attached_files pdf =
|
||||
let toplevel =
|
||||
match Pdf.lookup_direct pdf "/Root" pdf.Pdf.trailerdict with
|
||||
| None -> []
|
||||
| Some rootdict ->
|
||||
match Pdf.lookup_direct pdf "/Names" rootdict with
|
||||
| None -> []
|
||||
| Some namedict ->
|
||||
match Pdf.lookup_direct pdf "/EmbeddedFiles" namedict with
|
||||
| Some nametree ->
|
||||
map
|
||||
(function (x, ef) ->
|
||||
match Pdf.lookup_direct pdf "/EF" ef with
|
||||
| Some ((Pdf.Dictionary _) as d) ->
|
||||
begin match Pdf.lookup_direct pdf "/F" d with
|
||||
| Some stream ->
|
||||
{name = x;
|
||||
pagenumber = 0;
|
||||
data =
|
||||
(fun () ->
|
||||
try
|
||||
Pdf.getstream stream;
|
||||
Pdfcodec.decode_pdfstream pdf stream;
|
||||
match stream with
|
||||
Pdf.Stream {contents = (_, Pdf.Got data)} -> data
|
||||
| _ -> raise Not_found
|
||||
with
|
||||
_ -> raise (Pdf.PDFError "could not retreive attachment data"))}
|
||||
| None -> raise (Pdf.PDFError "/F not found")
|
||||
end
|
||||
| _ -> raise (Pdf.PDFError "/EF not found"))
|
||||
(option_map
|
||||
(function (Pdf.String s, ef) -> Some (s, ef) | _ -> None)
|
||||
(Pdf.contents_of_nametree pdf nametree))
|
||||
| _ -> []
|
||||
in let pagelevel =
|
||||
let pages = Pdfpage.pages_of_pagetree pdf in
|
||||
flatten
|
||||
(map2
|
||||
(fun page pagenumber ->
|
||||
option_map
|
||||
(function annot ->
|
||||
match Pdf.lookup_direct pdf "/Subtype" annot with
|
||||
| Some (Pdf.Name "/FileAttachment") ->
|
||||
(match Pdf.lookup_direct pdf "/Contents" annot with
|
||||
| Some (Pdf.String s) ->
|
||||
begin match Pdf.lookup_direct pdf "/FS" annot with
|
||||
| Some ((Pdf.Dictionary _) as d) ->
|
||||
(*Printf.eprintf "%s\n%!" (Pdfwrite.string_of_pdf d);*)
|
||||
begin match Pdf.lookup_direct pdf "/EF" d with
|
||||
| Some ((Pdf.Dictionary _) as d) ->
|
||||
begin match Pdf.lookup_direct pdf "/F" d with
|
||||
| Some stream ->
|
||||
Some
|
||||
{name = s;
|
||||
pagenumber = pagenumber;
|
||||
data =
|
||||
(fun () ->
|
||||
try
|
||||
Pdf.getstream stream;
|
||||
Pdfcodec.decode_pdfstream pdf stream;
|
||||
match stream with
|
||||
Pdf.Stream {contents = (_, Pdf.Got data)} -> data
|
||||
| _ -> raise Not_found
|
||||
with
|
||||
_ -> raise (Pdf.PDFError "could not retreive attachment data"))}
|
||||
| _ -> raise (Pdf.PDFError "no /F found in attachment")
|
||||
end
|
||||
| _ ->
|
||||
Some
|
||||
{name = s;
|
||||
pagenumber = pagenumber;
|
||||
data = (fun () -> raise (Pdf.PDFError "no attachment data"))}
|
||||
end
|
||||
| _ -> None
|
||||
end
|
||||
| _ -> None)
|
||||
| _ -> None)
|
||||
(match Pdf.lookup_direct pdf "/Annots" page.Pdfpage.rest with
|
||||
| Some (Pdf.Array annots) -> annots
|
||||
| _ -> []))
|
||||
pages
|
||||
(indx pages))
|
||||
in
|
||||
toplevel @ pagelevel
|
||||
|
||||
(* \section{Remove Attached files} *)
|
||||
let remove_attached_files_on_pages pdf =
|
||||
let remove_from_page page =
|
||||
{page with Pdfpage.rest =
|
||||
Pdf.add_dict_entry page.Pdfpage.rest "/Annots"
|
||||
(Pdf.Array
|
||||
(option_map
|
||||
(function annot ->
|
||||
match Pdf.lookup_direct pdf "/Subtype" annot with
|
||||
| Some (Pdf.Name "/FileAttachment") -> None
|
||||
| _ -> Some annot)
|
||||
(match Pdf.lookup_direct pdf "/Annots" page.Pdfpage.rest with
|
||||
| Some (Pdf.Array annots) -> annots
|
||||
| _ -> [])))}
|
||||
in
|
||||
Pdfpage.change_pages true pdf (map remove_from_page (Pdfpage.pages_of_pagetree pdf))
|
||||
|
||||
let remove_attached_files pdf =
|
||||
let pdf = remove_attached_files_on_pages pdf in
|
||||
match Pdf.lookup_direct pdf "/Root" pdf.Pdf.trailerdict with
|
||||
| None -> pdf
|
||||
| Some rootdict ->
|
||||
match Pdf.lookup_direct pdf "/Names" rootdict with
|
||||
| None -> pdf
|
||||
| Some namedict ->
|
||||
let namedict' = Pdf.remove_dict_entry namedict "/EmbeddedFiles" in
|
||||
let rootdict' = Pdf.add_dict_entry rootdict "/Names" namedict' in
|
||||
let rootdict'num = Pdf.addobj pdf rootdict' in
|
||||
{pdf with
|
||||
Pdf.root =
|
||||
rootdict'num;
|
||||
Pdf.trailerdict =
|
||||
Pdf.add_dict_entry pdf.Pdf.trailerdict "/Root" (Pdf.Indirect rootdict'num)}
|
||||
|
||||
(* \section{Copy an /ID from one file to another} *)
|
||||
let copy_id keepversion copyfrom copyto =
|
||||
match Pdf.lookup_direct copyfrom "/ID" copyfrom.Pdf.trailerdict with
|
||||
|
|
20
cpdf.mli
20
cpdf.mli
|
@ -9,11 +9,6 @@ all - the PDF string is output as-is. [UTF8] converts loslessly to UTF8.
|
|||
correspond to 7 bit ASCII. *)
|
||||
type encoding = Raw | UTF8 | Stripped
|
||||
|
||||
exception SoftError of string
|
||||
exception HardError of string
|
||||
(** Two exceptions recommended for use with the library, though currently not
|
||||
raised by any function in this module. Cpdfcommand uses them extensively. *)
|
||||
|
||||
(** {2 Debug} *)
|
||||
|
||||
(** Debug: Print out a PDF in readable form to the terminal *)
|
||||
|
@ -91,21 +86,6 @@ adds a presentation on the pages in [range]. See cpdfmanual.pdf for details.
|
|||
val presentation : int list -> string option ->
|
||||
float option -> bool -> bool -> int -> float -> Pdf.t -> Pdf.t
|
||||
|
||||
(** {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. *)
|
||||
val attach_file : ?memory:Pdfio.bytes -> bool -> int option -> Pdf.t -> string -> Pdf.t
|
||||
|
||||
(** Remove attached files. *)
|
||||
val remove_attached_files : Pdf.t -> Pdf.t
|
||||
|
||||
type attachment =
|
||||
{name : string;
|
||||
pagenumber : int;
|
||||
data : unit -> Pdfio.bytes}
|
||||
|
||||
(** List attached files. Attachment name and page number. Page 0 is document level. *)
|
||||
val list_attached_files : Pdf.t -> attachment list
|
||||
|
||||
(** {2 Bookmarks} *)
|
||||
|
||||
(** [parse_bookmark_file verify pdf input] parses the bookmark file in [input].
|
||||
|
|
|
@ -0,0 +1,226 @@
|
|||
open Pdfutil
|
||||
open Pdfio
|
||||
open Cpdferror
|
||||
|
||||
(* Attaching files *)
|
||||
let attach_file ?memory keepversion topage pdf file =
|
||||
let data =
|
||||
match memory with
|
||||
Some data -> data
|
||||
| None ->
|
||||
let ch = open_in_bin file in
|
||||
let len = in_channel_length ch in
|
||||
let stream = mkbytes len in
|
||||
let i = input_of_channel ch in
|
||||
setinit i stream 0 len;
|
||||
close_in ch;
|
||||
stream
|
||||
in
|
||||
let filestream =
|
||||
Pdf.Stream
|
||||
(ref (Pdf.Dictionary
|
||||
[("/Length", Pdf.Integer (bytes_size data));
|
||||
("/Type", Pdf.Name "/EmbeddedFile");
|
||||
("/Params",
|
||||
Pdf.Dictionary
|
||||
[("/Size", Pdf.Integer (bytes_size data));
|
||||
("/CheckSum", Pdf.String (Digest.string (string_of_bytes data)))
|
||||
])],
|
||||
Pdf.Got data))
|
||||
in
|
||||
let filestream_num = Pdf.addobj pdf filestream in
|
||||
let basename = Pdftext.pdfdocstring_of_utf8 (Filename.basename file) in
|
||||
let filespec =
|
||||
Pdf.Dictionary
|
||||
[("/EF", Pdf.Dictionary ["/F", Pdf.Indirect filestream_num]);
|
||||
("/F", Pdf.String basename);
|
||||
("/Type", Pdf.Name "/Filespec");
|
||||
("/Desc", Pdf.String "");
|
||||
("/UF", Pdf.String basename)]
|
||||
in
|
||||
match topage with
|
||||
| None ->
|
||||
(* Look up /Names and /EmbeddedFiles and /Names. *)
|
||||
let rootdict = Pdf.lookup_obj pdf pdf.Pdf.root in
|
||||
let namedict =
|
||||
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 []
|
||||
| Some embeddednamedict -> embeddednamedict
|
||||
in
|
||||
let elts =
|
||||
match Pdf.lookup_direct pdf "/Names" embeddednamedict with
|
||||
| Some (Pdf.Array elts) -> elts
|
||||
| _ -> []
|
||||
in
|
||||
let filespecobj = Pdf.addobj pdf filespec in
|
||||
let names' = Pdf.Array (elts @ [Pdf.String basename; Pdf.Indirect filespecobj]) in
|
||||
let embeddednamedict' = Pdf.add_dict_entry embeddednamedict "/Names" names' in
|
||||
let namedict' = Pdf.add_dict_entry namedict "/EmbeddedFiles" embeddednamedict' in
|
||||
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
|
||||
let filespecobj = Pdf.addobj pdf filespec in
|
||||
let annot =
|
||||
Pdf.Dictionary
|
||||
[("/FS", Pdf.Indirect filespecobj);
|
||||
("/Subtype", Pdf.Name "/FileAttachment");
|
||||
("/Contents", Pdf.String basename);
|
||||
("/Rect", rect)]
|
||||
in
|
||||
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 true pdf pages' in
|
||||
{pdf with
|
||||
Pdf.minor = if keepversion then pdf.Pdf.minor else max pdf.Pdf.minor 4}
|
||||
|
||||
type attachment =
|
||||
{name : string;
|
||||
pagenumber : int;
|
||||
data : unit -> Pdfio.bytes}
|
||||
|
||||
let list_attached_files pdf =
|
||||
let toplevel =
|
||||
match Pdf.lookup_direct pdf "/Root" pdf.Pdf.trailerdict with
|
||||
| None -> []
|
||||
| Some rootdict ->
|
||||
match Pdf.lookup_direct pdf "/Names" rootdict with
|
||||
| None -> []
|
||||
| Some namedict ->
|
||||
match Pdf.lookup_direct pdf "/EmbeddedFiles" namedict with
|
||||
| Some nametree ->
|
||||
map
|
||||
(function (x, ef) ->
|
||||
match Pdf.lookup_direct pdf "/EF" ef with
|
||||
| Some ((Pdf.Dictionary _) as d) ->
|
||||
begin match Pdf.lookup_direct pdf "/F" d with
|
||||
| Some stream ->
|
||||
{name = x;
|
||||
pagenumber = 0;
|
||||
data =
|
||||
(fun () ->
|
||||
try
|
||||
Pdf.getstream stream;
|
||||
Pdfcodec.decode_pdfstream pdf stream;
|
||||
match stream with
|
||||
Pdf.Stream {contents = (_, Pdf.Got data)} -> data
|
||||
| _ -> raise Not_found
|
||||
with
|
||||
_ -> raise (Pdf.PDFError "could not retreive attachment data"))}
|
||||
| None -> raise (Pdf.PDFError "/F not found")
|
||||
end
|
||||
| _ -> raise (Pdf.PDFError "/EF not found"))
|
||||
(option_map
|
||||
(function (Pdf.String s, ef) -> Some (s, ef) | _ -> None)
|
||||
(Pdf.contents_of_nametree pdf nametree))
|
||||
| _ -> []
|
||||
in let pagelevel =
|
||||
let pages = Pdfpage.pages_of_pagetree pdf in
|
||||
flatten
|
||||
(map2
|
||||
(fun page pagenumber ->
|
||||
option_map
|
||||
(function annot ->
|
||||
match Pdf.lookup_direct pdf "/Subtype" annot with
|
||||
| Some (Pdf.Name "/FileAttachment") ->
|
||||
(match Pdf.lookup_direct pdf "/Contents" annot with
|
||||
| Some (Pdf.String s) ->
|
||||
begin match Pdf.lookup_direct pdf "/FS" annot with
|
||||
| Some ((Pdf.Dictionary _) as d) ->
|
||||
(*Printf.eprintf "%s\n%!" (Pdfwrite.string_of_pdf d);*)
|
||||
begin match Pdf.lookup_direct pdf "/EF" d with
|
||||
| Some ((Pdf.Dictionary _) as d) ->
|
||||
begin match Pdf.lookup_direct pdf "/F" d with
|
||||
| Some stream ->
|
||||
Some
|
||||
{name = s;
|
||||
pagenumber = pagenumber;
|
||||
data =
|
||||
(fun () ->
|
||||
try
|
||||
Pdf.getstream stream;
|
||||
Pdfcodec.decode_pdfstream pdf stream;
|
||||
match stream with
|
||||
Pdf.Stream {contents = (_, Pdf.Got data)} -> data
|
||||
| _ -> raise Not_found
|
||||
with
|
||||
_ -> raise (Pdf.PDFError "could not retreive attachment data"))}
|
||||
| _ -> raise (Pdf.PDFError "no /F found in attachment")
|
||||
end
|
||||
| _ ->
|
||||
Some
|
||||
{name = s;
|
||||
pagenumber = pagenumber;
|
||||
data = (fun () -> raise (Pdf.PDFError "no attachment data"))}
|
||||
end
|
||||
| _ -> None
|
||||
end
|
||||
| _ -> None)
|
||||
| _ -> None)
|
||||
(match Pdf.lookup_direct pdf "/Annots" page.Pdfpage.rest with
|
||||
| Some (Pdf.Array annots) -> annots
|
||||
| _ -> []))
|
||||
pages
|
||||
(indx pages))
|
||||
in
|
||||
toplevel @ pagelevel
|
||||
|
||||
(* \section{Remove Attached files} *)
|
||||
let remove_attached_files_on_pages pdf =
|
||||
let remove_from_page page =
|
||||
{page with Pdfpage.rest =
|
||||
Pdf.add_dict_entry page.Pdfpage.rest "/Annots"
|
||||
(Pdf.Array
|
||||
(option_map
|
||||
(function annot ->
|
||||
match Pdf.lookup_direct pdf "/Subtype" annot with
|
||||
| Some (Pdf.Name "/FileAttachment") -> None
|
||||
| _ -> Some annot)
|
||||
(match Pdf.lookup_direct pdf "/Annots" page.Pdfpage.rest with
|
||||
| Some (Pdf.Array annots) -> annots
|
||||
| _ -> [])))}
|
||||
in
|
||||
Pdfpage.change_pages true pdf (map remove_from_page (Pdfpage.pages_of_pagetree pdf))
|
||||
|
||||
let remove_attached_files pdf =
|
||||
let pdf = remove_attached_files_on_pages pdf in
|
||||
match Pdf.lookup_direct pdf "/Root" pdf.Pdf.trailerdict with
|
||||
| None -> pdf
|
||||
| Some rootdict ->
|
||||
match Pdf.lookup_direct pdf "/Names" rootdict with
|
||||
| None -> pdf
|
||||
| Some namedict ->
|
||||
let namedict' = Pdf.remove_dict_entry namedict "/EmbeddedFiles" in
|
||||
let rootdict' = Pdf.add_dict_entry rootdict "/Names" namedict' in
|
||||
let rootdict'num = Pdf.addobj pdf rootdict' in
|
||||
{pdf with
|
||||
Pdf.root =
|
||||
rootdict'num;
|
||||
Pdf.trailerdict =
|
||||
Pdf.add_dict_entry pdf.Pdf.trailerdict "/Root" (Pdf.Indirect rootdict'num)}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
(** {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. *)
|
||||
val attach_file : ?memory:Pdfio.bytes -> bool -> int option -> Pdf.t -> string -> Pdf.t
|
||||
|
||||
(** Remove attached files. *)
|
||||
val remove_attached_files : Pdf.t -> Pdf.t
|
||||
|
||||
type attachment =
|
||||
{name : string;
|
||||
pagenumber : int;
|
||||
data : unit -> Pdfio.bytes}
|
||||
|
||||
(** List attached files. Attachment name and page number. Page 0 is document level. *)
|
||||
val list_attached_files : Pdf.t -> attachment list
|
|
@ -27,17 +27,17 @@ it had been loaded. *)
|
|||
let pdfread_pdf_of_input ?revision a b c =
|
||||
try Pdfread.pdf_of_input ?revision a b c with
|
||||
Pdf.PDFError s when String.length s >=10 && String.sub s 0 10 = "Encryption" ->
|
||||
raise (Cpdf.SoftError "Bad owner or user password when reading document")
|
||||
raise (Cpdferror.SoftError "Bad owner or user password when reading document")
|
||||
|
||||
let pdfread_pdf_of_channel_lazy ?revision ?source b c d =
|
||||
try Pdfread.pdf_of_channel_lazy ?revision ?source b c d with
|
||||
Pdf.PDFError s when String.length s >=10 && String.sub s 0 10 = "Encryption" ->
|
||||
raise (Cpdf.SoftError "Bad owner or user password when reading document")
|
||||
raise (Cpdferror.SoftError "Bad owner or user password when reading document")
|
||||
|
||||
let pdfread_pdf_of_file ?revision a b c =
|
||||
try Pdfread.pdf_of_file ?revision a b c with
|
||||
Pdf.PDFError s when String.length s >=10 && String.sub s 0 10 = "Encryption" ->
|
||||
raise (Cpdf.SoftError "Bad owner or user password when reading document")
|
||||
raise (Cpdferror.SoftError "Bad owner or user password when reading document")
|
||||
|
||||
let optstring = function
|
||||
| "" -> None
|
||||
|
@ -2352,7 +2352,7 @@ let rec get_single_pdf ?(decrypt=true) ?(fail=false) op read_lazy =
|
|||
else
|
||||
pdfread_pdf_of_file ?revision (optstring u) (optstring o) inname
|
||||
with
|
||||
| Cpdf.SoftError _ as e -> raise e (* Bad owner or user password *)
|
||||
| Cpdferror.SoftError _ as e -> raise e (* Bad owner or user password *)
|
||||
| _ ->
|
||||
if args.gs_malformed then
|
||||
begin
|
||||
|
@ -2446,7 +2446,7 @@ let rec get_pdf_from_input_kind ?(read_lazy=false) ?(decrypt=true) ?(fail=false)
|
|||
else
|
||||
pdfread_pdf_of_file ?revision (optstring u) (optstring o) s
|
||||
with
|
||||
| Cpdf.SoftError _ as e -> raise e (* Bad owner or user password *)
|
||||
| Cpdferror.SoftError _ as e -> raise e (* Bad owner or user password *)
|
||||
| e ->
|
||||
Printf.printf "%s\n" (Printexc.to_string e);
|
||||
if args.gs_malformed then
|
||||
|
@ -4046,9 +4046,9 @@ let go () =
|
|||
write_pdf false (Cpdf.scale_contents ~fast:args.fast args.position scale pdf range)
|
||||
| Some ListAttachedFiles ->
|
||||
let pdf = get_single_pdf args.op false in
|
||||
let attachments = Cpdf.list_attached_files pdf in
|
||||
let attachments = Cpdfattach.list_attached_files pdf in
|
||||
iter
|
||||
(fun a -> Printf.printf "%i %s\n" a.Cpdf.pagenumber a.Cpdf.name)
|
||||
(fun a -> Printf.printf "%i %s\n" a.Cpdfattach.pagenumber a.Cpdfattach.name)
|
||||
attachments;
|
||||
flprint ""
|
||||
| Some DumpAttachedFiles ->
|
||||
|
@ -4059,7 +4059,7 @@ let go () =
|
|||
| Stdout -> error "Can't dump attachments to stdout"
|
||||
end
|
||||
| Some RemoveAttachedFiles ->
|
||||
write_pdf false (Cpdf.remove_attached_files (get_single_pdf args.op false))
|
||||
write_pdf false (Cpdfattach.remove_attached_files (get_single_pdf args.op false))
|
||||
| Some (AttachFile files) ->
|
||||
begin match args.inputs with
|
||||
| [(k, _, _, _, _, _) as input] ->
|
||||
|
@ -4072,7 +4072,7 @@ let go () =
|
|||
| Some s -> Some (int_of_string s)
|
||||
with _ -> error "Bad -to-page"
|
||||
in
|
||||
let pdf = fold_left (Cpdf.attach_file args.keepversion topage) pdf (rev files) in
|
||||
let pdf = fold_left (Cpdfattach.attach_file args.keepversion topage) pdf (rev files) in
|
||||
write_pdf false pdf
|
||||
| _ -> error "attach file: No input file specified"
|
||||
end
|
||||
|
@ -4499,8 +4499,8 @@ let go_withargv argv =
|
|||
if args.debug then raise e else exit 2
|
||||
else
|
||||
raise StayOnError
|
||||
| Cpdf.SoftError s -> soft_error s
|
||||
| Cpdf.HardError s -> error s
|
||||
| Cpdferror.SoftError s -> soft_error s
|
||||
| Cpdferror.HardError s -> error s
|
||||
| e ->
|
||||
prerr_string
|
||||
("cpdf encountered an unexpected error. Technical Details follow:\n" ^
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
(** Two exceptions recommended for use with the library, though currently not
|
||||
raised by any function in this module. Cpdfcommand uses them extensively. *)
|
||||
exception SoftError of string
|
||||
|
||||
exception HardError of string
|
||||
|
||||
let error s = raise (SoftError s)
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
exception SoftError of string
|
||||
val error : string -> 'a
|
||||
exception HardError of string
|
Loading…
Reference in New Issue