diff --git a/Makefile b/Makefile index 1bd2544..ca91a5f 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ MODS = cpdfyojson cpdfxmlm \ cpdfunicodedata cpdferror cpdfjson cpdfstrftime cpdfcoord cpdfattach \ cpdfpagespec cpdfposition cpdf cpdfpresent cpdffont cpdftype \ - cpdftexttopdf cpdftoc cpdfcommand + cpdftexttopdf cpdftoc cpdfpad cpdfcommand SOURCES = $(foreach x,$(MODS),$(x).ml $(x).mli) cpdfcommandrun.ml diff --git a/cpdf.ml b/cpdf.ml index d86b0f1..5676d98 100644 --- a/cpdf.ml +++ b/cpdf.ml @@ -1625,107 +1625,6 @@ let removetext range pdf = in process_pages (ppstub removetext_page) pdf range -(* \section{Padding with blank pages.} *) -let insert_after pos page pages = - let before, after = cleave pages pos in - before @ [page] @ after - -(* Insert many. *) -let rec insert_after_many pages = function - | [] -> pages - | (pos, page)::more -> - let pages' = insert_after pos page pages in - insert_after_many pages' (map (fun (p, pa) -> p + 1, pa) more) - -(* For each pagenum in the range, increment the count by padsize, and carry on. e.g -insert_after_many_changes 1 0 [2] [1; 2; 3] --> [(1, 1); (2, 2); (3, 4)] *) -let rec insert_after_many_changes isbefore padsize offset range = function - [] -> [] -| h::t -> - let item = (h, h + offset + if isbefore && mem h range then 1 else 0) in - if mem h range then - item::insert_after_many_changes isbefore padsize (offset + padsize) range t - else - item::insert_after_many_changes isbefore padsize offset range t - -let print_changes = - iter (fun (f, t) -> Printf.printf "%i --> %i\n" f t) - -let pad_with_pdf (range : int list) (pdf : Pdf.t) (isbefore : bool) (padfile : Pdf.t) = - let range = sort compare (setify range) in - let merged = - Pdfmerge.merge_pdfs - false false ["a"; "b"] [pdf; padfile] [ilist 1 (Pdfpage.endpage pdf); ilist 1 (Pdfpage.endpage padfile)] - in - let original_pages, padpages = - cleave (Pdfpage.pages_of_pagetree merged) (Pdfpage.endpage pdf) - in - let newpages = - map - (fun (pagenum, page) -> - if mem pagenum range then - (if isbefore then padpages @ [page] else [page] @ padpages) - else - [page]) - (combine (indx original_pages) original_pages) - in - (* FIXME Provide ~changes here? *) - Pdfpage.change_pages false merged (flatten newpages) - -let pad padwith range pdf isbefore = - match padwith with - Some padfile -> pad_with_pdf range pdf isbefore padfile - | None -> - let i = if isbefore then 1 else 0 in - let pages = Pdfpage.pages_of_pagetree pdf in - let blankpages = - map - (fun n -> - {Pdfpage.content = []; - Pdfpage.mediabox = (select (n + i) pages).Pdfpage.mediabox; - Pdfpage.resources = Pdf.Dictionary []; - Pdfpage.rotate = (select (n + i) pages).Pdfpage.rotate; - Pdfpage.rest = Pdf.remove_dict_entry ((select (n + i) pages).Pdfpage.rest) "/Annots"}) - range - in - let pages' = insert_after_many pages (combine range blankpages) in - let changes = - insert_after_many_changes - isbefore 1 0 (map (fun x -> x + i) range) (ilist 1 (length pages)) - in - Pdfpage.change_pages ~changes true pdf pages' - -let padafter ?padwith range pdf = - let isinpdf n = mem n (ilist 1 (Pdfpage.endpage pdf)) in - if not (fold_left ( && ) true (map isinpdf range)) then - raise (Failure "padafter: range contains pages not present in pdf"); - pad padwith range pdf false - -let padbefore ?padwith range pdf = - let isinpdf n = mem n (ilist 1 (Pdfpage.endpage pdf)) in - if not (fold_left ( && ) true (map isinpdf range)) then - raise (Failure "padbefore: range contains pages not present in pdf"); - pad padwith (map pred range) pdf true - -let padmultiple n pdf = - let neg, n = n < 0, if n < 0 then -n else n in - let pages = Pdfpage.pages_of_pagetree pdf in - let len = length pages in - let pages_to_add = if len / n * n = len then 0 else n - (len mod n) in - if pages_to_add > 0 then - let blankpages = - many - {Pdfpage.content = []; - Pdfpage.mediabox = (select len pages).Pdfpage.mediabox; - Pdfpage.resources = Pdf.Dictionary []; - Pdfpage.rotate = (select len pages).Pdfpage.rotate; - Pdfpage.rest = Pdf.Dictionary []} - pages_to_add - in - let changes = map (fun x -> (x, x)) (ilist 1 (length pages)) in - Pdfpage.change_pages ~changes true pdf (if neg then blankpages @ pages else pages @ blankpages) - else - pdf (* \section{Shift page data} *) let make_mediabox (xmin, ymin, xmax, ymax) = diff --git a/cpdf.mli b/cpdf.mli index 063c193..7262dcf 100644 --- a/cpdf.mli +++ b/cpdf.mli @@ -285,16 +285,6 @@ val trim_marks : ?fast:bool -> Pdf.t -> int list -> Pdf.t val show_boxes : ?fast:bool -> Pdf.t -> int list -> Pdf.t -(** {2 Padding} *) - -(** Put blank pages before the given page numbers *) -val padbefore : ?padwith:Pdf.t -> int list -> Pdf.t -> Pdf.t - -(** Put blank pages after the given page numbers *) -val padafter : ?padwith:Pdf.t -> int list -> Pdf.t -> Pdf.t - -(** Pad to a multiple of n pages *) -val padmultiple : int -> Pdf.t -> Pdf.t (** {2 Annotations} *) diff --git a/cpdfcommand.ml b/cpdfcommand.ml index 11c148f..1347405 100644 --- a/cpdfcommand.ml +++ b/cpdfcommand.ml @@ -3576,7 +3576,7 @@ let go () = None -> None | Some filename -> Some (pdfread_pdf_of_file None None filename) in - write_pdf false (Cpdf.padbefore ?padwith range pdf) + write_pdf false (Cpdfpad.padbefore ?padwith range pdf) | Some PadAfter -> let pdf = get_single_pdf args.op false in let range = parse_pagespec_allow_empty pdf (get_pagespec ()) in @@ -3585,7 +3585,7 @@ let go () = None -> None | Some filename -> Some (pdfread_pdf_of_file None None filename) in - write_pdf false (Cpdf.padafter ?padwith range pdf) + write_pdf false (Cpdfpad.padafter ?padwith range pdf) | Some (PadEvery n) -> let pdf = get_single_pdf args.op false in let range = @@ -3598,13 +3598,13 @@ let go () = None -> None | Some filename -> Some (pdfread_pdf_of_file None None filename) in - write_pdf false (Cpdf.padafter ?padwith range pdf) + write_pdf false (Cpdfpad.padafter ?padwith range pdf) | Some (PadMultiple n) -> let pdf = get_single_pdf args.op false in - write_pdf false (Cpdf.padmultiple n pdf) + write_pdf false (Cpdfpad.padmultiple n pdf) | Some (PadMultipleBefore n) -> let pdf = get_single_pdf args.op false in - write_pdf false (Cpdf.padmultiple (-n) pdf) + write_pdf false (Cpdfpad.padmultiple (-n) pdf) | Some Draft -> let pdf = get_single_pdf args.op false in let range = parse_pagespec_allow_empty pdf (get_pagespec ()) in diff --git a/cpdfpad.ml b/cpdfpad.ml new file mode 100644 index 0000000..43799b8 --- /dev/null +++ b/cpdfpad.ml @@ -0,0 +1,104 @@ +open Pdfutil + +(* \section{Padding with blank pages.} *) +let insert_after pos page pages = + let before, after = cleave pages pos in + before @ [page] @ after + +(* Insert many. *) +let rec insert_after_many pages = function + | [] -> pages + | (pos, page)::more -> + let pages' = insert_after pos page pages in + insert_after_many pages' (map (fun (p, pa) -> p + 1, pa) more) + +(* For each pagenum in the range, increment the count by padsize, and carry on. e.g +insert_after_many_changes 1 0 [2] [1; 2; 3] --> [(1, 1); (2, 2); (3, 4)] *) +let rec insert_after_many_changes isbefore padsize offset range = function + [] -> [] +| h::t -> + let item = (h, h + offset + if isbefore && mem h range then 1 else 0) in + if mem h range then + item::insert_after_many_changes isbefore padsize (offset + padsize) range t + else + item::insert_after_many_changes isbefore padsize offset range t + +let print_changes = + iter (fun (f, t) -> Printf.printf "%i --> %i\n" f t) + +let pad_with_pdf (range : int list) (pdf : Pdf.t) (isbefore : bool) (padfile : Pdf.t) = + let range = sort compare (setify range) in + let merged = + Pdfmerge.merge_pdfs + false false ["a"; "b"] [pdf; padfile] [ilist 1 (Pdfpage.endpage pdf); ilist 1 (Pdfpage.endpage padfile)] + in + let original_pages, padpages = + cleave (Pdfpage.pages_of_pagetree merged) (Pdfpage.endpage pdf) + in + let newpages = + map + (fun (pagenum, page) -> + if mem pagenum range then + (if isbefore then padpages @ [page] else [page] @ padpages) + else + [page]) + (combine (indx original_pages) original_pages) + in + (* FIXME Provide ~changes here? *) + Pdfpage.change_pages false merged (flatten newpages) + +let pad padwith range pdf isbefore = + match padwith with + Some padfile -> pad_with_pdf range pdf isbefore padfile + | None -> + let i = if isbefore then 1 else 0 in + let pages = Pdfpage.pages_of_pagetree pdf in + let blankpages = + map + (fun n -> + {Pdfpage.content = []; + Pdfpage.mediabox = (select (n + i) pages).Pdfpage.mediabox; + Pdfpage.resources = Pdf.Dictionary []; + Pdfpage.rotate = (select (n + i) pages).Pdfpage.rotate; + Pdfpage.rest = Pdf.remove_dict_entry ((select (n + i) pages).Pdfpage.rest) "/Annots"}) + range + in + let pages' = insert_after_many pages (combine range blankpages) in + let changes = + insert_after_many_changes + isbefore 1 0 (map (fun x -> x + i) range) (ilist 1 (length pages)) + in + Pdfpage.change_pages ~changes true pdf pages' + +let padafter ?padwith range pdf = + let isinpdf n = mem n (ilist 1 (Pdfpage.endpage pdf)) in + if not (fold_left ( && ) true (map isinpdf range)) then + raise (Failure "padafter: range contains pages not present in pdf"); + pad padwith range pdf false + +let padbefore ?padwith range pdf = + let isinpdf n = mem n (ilist 1 (Pdfpage.endpage pdf)) in + if not (fold_left ( && ) true (map isinpdf range)) then + raise (Failure "padbefore: range contains pages not present in pdf"); + pad padwith (map pred range) pdf true + +let padmultiple n pdf = + let neg, n = n < 0, if n < 0 then -n else n in + let pages = Pdfpage.pages_of_pagetree pdf in + let len = length pages in + let pages_to_add = if len / n * n = len then 0 else n - (len mod n) in + if pages_to_add > 0 then + let blankpages = + many + {Pdfpage.content = []; + Pdfpage.mediabox = (select len pages).Pdfpage.mediabox; + Pdfpage.resources = Pdf.Dictionary []; + Pdfpage.rotate = (select len pages).Pdfpage.rotate; + Pdfpage.rest = Pdf.Dictionary []} + pages_to_add + in + let changes = map (fun x -> (x, x)) (ilist 1 (length pages)) in + Pdfpage.change_pages ~changes true pdf (if neg then blankpages @ pages else pages @ blankpages) + else + pdf + diff --git a/cpdfpad.mli b/cpdfpad.mli new file mode 100644 index 0000000..ba599a0 --- /dev/null +++ b/cpdfpad.mli @@ -0,0 +1,10 @@ +(** {2 Padding} *) + +(** Put blank pages before the given page numbers *) +val padbefore : ?padwith:Pdf.t -> int list -> Pdf.t -> Pdf.t + +(** Put blank pages after the given page numbers *) +val padafter : ?padwith:Pdf.t -> int list -> Pdf.t -> Pdf.t + +(** Pad to a multiple of n pages *) +val padmultiple : int -> Pdf.t -> Pdf.t