diff --git a/cpdf.ml b/cpdf.ml index 1af65ff..99c8700 100644 --- a/cpdf.ml +++ b/cpdf.ml @@ -1233,156 +1233,7 @@ let list_bookmarks encoding range pdf output = (if mark.Pdfmarks.isopen then "open" else ""))) inrange -(* \section{Stamping files} *) (* o is the stamp, u is the main pdf page *) -let do_stamp fast scale_to_fit isover pdf o u opdf = - (* Scale page stamp o to fit page u *) - let o = - if scale_to_fit then - let sxmin, symin, sxmax, symax = - Pdf.parse_rectangle - (match Pdf.lookup_direct pdf "/CropBox" o.Pdfpage.rest with | Some r -> r | None -> o.Pdfpage.mediabox) - in let txmin, tymin, txmax, tymax = - Pdf.parse_rectangle - (match Pdf.lookup_direct pdf "/CropBox" u.Pdfpage.rest with | Some r -> r | None -> u.Pdfpage.mediabox) - in - let xmag = (txmax -. txmin) /. (sxmax -. sxmin) - in let ymag = (tymax -. tymin) /. (symax -. symin) in - let scale = - if xmag < 0.999 && ymag < 0.999 then - if xmag > ymag then xmag else ymag - else if xmag >= 1.001 && ymag >= 1.001 then - if xmag > ymag then ymag else xmag - else if xmag >= 1.001 then ymag - else xmag - in - let dx = txmin +. ((txmax -. txmin) -. (sxmax -. sxmin) *. scale) /. 2. - in let dy = tymin +. ((tymax -. tymin) -. (symax -. symin) *. scale) /. 2. in - let scale_op = - Pdfops.Op_cm - (Pdftransform.matrix_of_transform - [Pdftransform.Translate (dx, dy); - Pdftransform.Scale ((sxmin, symin), scale, scale)]) - in - Pdfpage.prepend_operators opdf [scale_op] ~fast o - else - o - in - {u with - Pdfpage.content = - (if isover then ( @ ) else ( @@ )) - [protect_removeme pdf u.Pdfpage.resources u.Pdfpage.content] - [protect_removeme pdf o.Pdfpage.resources o.Pdfpage.content]; - Pdfpage.resources = - combine_pdf_resources pdf u.Pdfpage.resources o.Pdfpage.resources} - -(* Alter bookmark destinations given a hash table of (old page reference - * number, new page reference number) pairings *) -let change_destination t = function - Pdfdest.XYZ (Pdfdest.PageObject p, a, b, c) -> - Pdfdest.XYZ (Pdfdest.PageObject (Hashtbl.find t p), a, b, c) - | Pdfdest.Fit (Pdfdest.PageObject p) -> - Pdfdest.Fit (Pdfdest.PageObject (Hashtbl.find t p)) - | Pdfdest.FitH (Pdfdest.PageObject p, x) -> - Pdfdest.FitH (Pdfdest.PageObject (Hashtbl.find t p), x) - | Pdfdest.FitV (Pdfdest.PageObject p, x) -> - Pdfdest.FitV (Pdfdest.PageObject (Hashtbl.find t p), x) - | Pdfdest.FitR (Pdfdest.PageObject p, a, b, c, d) -> - Pdfdest.FitR (Pdfdest.PageObject (Hashtbl.find t p), a, b, c, d) - | Pdfdest.FitB (Pdfdest.PageObject p) -> - Pdfdest.Fit (Pdfdest.PageObject (Hashtbl.find t p)) - | Pdfdest.FitBH (Pdfdest.PageObject p, x) -> - Pdfdest.FitBH (Pdfdest.PageObject (Hashtbl.find t p), x) - | Pdfdest.FitBV (Pdfdest.PageObject p, x) -> - Pdfdest.FitBV (Pdfdest.PageObject (Hashtbl.find t p), x) - | x -> x - -let change_bookmark t m = - {m with Pdfmarks.target = - try change_destination t m.Pdfmarks.target with Not_found -> m.Pdfmarks.target} - -let stamp (fast : bool) scale_to_fit isover range over pdf = - let marks = Pdfmarks.read_bookmarks pdf in - let marks_refnumbers = Pdf.page_reference_numbers pdf in - let pdf = Pdfmarks.remove_bookmarks pdf in - let over = Pdfmarks.remove_bookmarks over in - let pageseqs = ilist 1 (Pdfpage.endpage pdf) in - let over_firstpage_pdf = - match Pdfpage.pages_of_pagetree over with - | [] -> error "empty PDF" - | h::_ -> Pdfpage.change_pages true over [h] - in - let merged = - Pdfmerge.merge_pdfs - ~rotations:[Pdfmerge.DNR; Pdfmerge.DNR] - false false ["a"; "b"] [pdf; over_firstpage_pdf] [pageseqs; [1]] - in - let renamed_pdf = - Pdfpage.change_pages true - merged (Pdfpage.renumber_pages merged (Pdfpage.pages_of_pagetree merged)) - in - let renamed_pages = Pdfpage.pages_of_pagetree renamed_pdf in - let under_pages, over_page = - all_but_last renamed_pages, last renamed_pages - in - let new_pages = - map2 - (fun pageseq under_page -> - do_stamp fast scale_to_fit isover renamed_pdf - (if mem pageseq range then over_page else - Pdfpage.blankpage Pdfpaper.a4) - under_page over) - pageseqs - under_pages - in - let changed = Pdfpage.change_pages true renamed_pdf new_pages in - let new_refnumbers = Pdf.page_reference_numbers changed in - let changetable = hashtable_of_dictionary (List.combine marks_refnumbers new_refnumbers) in - let new_marks = map (change_bookmark changetable) marks in - Pdfmarks.add_bookmarks new_marks changed - -(* Combine pages from two PDFs. For now, assume equal length. *) - -(* If [over] has more pages than [under], chop the excess. If the converse, pad -[over] to the same length *) -let equalize_pages under over = - let length_under = Pdfpage.endpage under - in let length_over = Pdfpage.endpage over - in - if length_over > length_under then - under, - (Pdfpage.change_pages true over (take (Pdfpage.pages_of_pagetree over) length_under)) - else if length_under > length_over then - under, - Pdfpage.change_pages true - over - (Pdfpage.pages_of_pagetree over @ - (many (Pdfpage.blankpage Pdfpaper.a4) (length_under - length_over))) - else - under, over - -let combine_pages (fast : bool) under over scaletofit swap equalize = - let marks_under = Pdfmarks.read_bookmarks under in - let marks_over = Pdfmarks.read_bookmarks over in - let under, over = if equalize then equalize_pages under over else under, over in - let under_length = Pdfpage.endpage under - in let over_length = Pdfpage.endpage over in - if under_length <> over_length then raise (Pdf.PDFError "combine_pages: not of equal length") else - let pageseqs_under = ilist 1 (Pdfpage.endpage under) - in let pageseqs_over = ilist 1 (Pdfpage.endpage over) in - let merged = - Pdfmerge.merge_pdfs ~rotations: [Pdfmerge.DNR; Pdfmerge.DNR] false false ["a"; "b"] [under; over] [pageseqs_under; pageseqs_over] in - let renamed_pdf = - Pdfpage.change_pages true - merged (Pdfpage.renumber_pages merged (Pdfpage.pages_of_pagetree merged)) - in - let under_pages, over_pages = - cleave (Pdfpage.pages_of_pagetree renamed_pdf) under_length - in - let new_pages = - map2 (fun o u -> do_stamp fast scaletofit (not swap) renamed_pdf o u over) over_pages under_pages - in - Pdfmarks.add_bookmarks (marks_under @ marks_over) (Pdfpage.change_pages true renamed_pdf new_pages) (* \section{Split at bookmarks} *) @@ -1627,56 +1478,6 @@ let print_fonts pdf = flprint (fold_left ( ^ ) "" (map string_of_font (list_fonts pdf))) -(* \section{Nobbling for Demo Version} *) -let nobble_page pdf _ page = - let minx, miny, maxx, maxy = - (* Use cropbox if available *) - Pdf.parse_rectangle - (match Pdf.lookup_direct pdf "/CropBox" page.Pdfpage.rest with - | Some r -> r - | None -> page.Pdfpage.mediabox) - in - let fontdict = - match Pdf.lookup_direct pdf "/Font" page.Pdfpage.resources with - | None -> Pdf.Dictionary [] - | Some d -> d - in - let fontname = Pdf.unique_key "F" fontdict in - let width = maxx -. minx in let height = maxy -. miny in - let scalex = - (width *. 1000.) /. float (Pdfstandard14.textwidth false Pdftext.Helvetica "DEMO") - in - let page' = - let font = - Pdf.Dictionary - [("/Type", Pdf.Name "/Font"); - ("/Subtype", Pdf.Name "/Type1"); - ("/BaseFont", Pdf.Name "/Helvetica")] - in let ops = - [Pdfops.Op_BMC "/CPDFSTAMP"; - Pdfops.Op_cm - (Pdftransform.matrix_of_transform - [Pdftransform.Translate (minx, miny +. height /. 2.)]); - Pdfops.Op_gs "/gs0"; - Pdfops.Op_BT; - Pdfops.Op_Tf (fontname, scalex); - Pdfops.Op_Tj "DEMO"; - Pdfops.Op_ET; - Pdfops.Op_EMC] - in - {(Pdfpage.blankpage Pdfpaper.a4) with - Pdfpage.mediabox = page.Pdfpage.mediabox; - Pdfpage.content = [Pdfops.stream_of_ops ops]; - Pdfpage.resources = - Pdf.Dictionary - [("/Font", Pdf.Dictionary [(fontname, font)]); - ("/ExtGState", Pdf.Dictionary - ["/gs0", - Pdf.Dictionary["/Type", Pdf.Name "/ExtGState"; "/ca", Pdf.Real 0.2]]); - ] - } - in - do_stamp false false true pdf page' page (Pdf.empty ()) (* \section{Superimpose text, page numbers etc.} *) @@ -2397,6 +2198,230 @@ let hflip_pdf ?(fast=false) pdf range = in process_pages (flip_page ~fast transform_op pdf) pdf range +let stamp_shift_of_position sw sh w h p = + let half x = x /. 2. in + match p with + | PosCentre (ox, oy) -> ox -. half sw, oy + | PosLeft (ox, oy) -> ox, oy + | PosRight (ox, oy) -> ox -. sw, oy + | Top o -> half w -. half sw, h -. o -. sh + | TopLeft o -> o, h -. sh -. o + | TopRight o -> w -. sw -. o, h -. sh -. o + | Left o -> o, half h -. half sh + | BottomLeft o -> o, o + | Bottom o -> half w -. half sw, o + | BottomRight o -> w -. sw, o + | Right o -> w -. sw -. o, half h -. half sh + | Diagonal | ReverseDiagonal | Centre -> half w -. half sw, half h -. half sh + +let do_stamp fast position scale_to_fit isover pdf o u opdf = + (* Scale page stamp o to fit page u *) + let sxmin, symin, sxmax, symax = + Pdf.parse_rectangle + (match Pdf.lookup_direct pdf "/CropBox" o.Pdfpage.rest with | Some r -> r | None -> o.Pdfpage.mediabox) + in let txmin, tymin, txmax, tymax = + Pdf.parse_rectangle + (match Pdf.lookup_direct pdf "/CropBox" u.Pdfpage.rest with | Some r -> r | None -> u.Pdfpage.mediabox) + in + let o = + if scale_to_fit then + let xmag = (txmax -. txmin) /. (sxmax -. sxmin) in + let ymag = (tymax -. tymin) /. (symax -. symin) in + let scale = + if xmag < 0.999 && ymag < 0.999 then + if xmag > ymag then xmag else ymag + else if xmag >= 1.001 && ymag >= 1.001 then + if xmag > ymag then ymag else xmag + else if xmag >= 1.001 then ymag + else xmag + in + let dx = txmin +. ((txmax -. txmin) -. (sxmax -. sxmin) *. scale) /. 2. in + let dy = tymin +. ((tymax -. tymin) -. (symax -. symin) *. scale) /. 2. in + let scale_op = + Pdfops.Op_cm + (Pdftransform.matrix_of_transform + [Pdftransform.Translate (dx, dy); + Pdftransform.Scale ((sxmin, symin), scale, scale)]) + in + Pdfpage.prepend_operators pdf [scale_op] ~fast o + else + let sw = sxmax -. sxmin + and sh = symax -. symin + and w = txmax -. txmin + and h = tymax -. tymin in + let dx, dy = stamp_shift_of_position sw sh w h position in + let translate_op = + Pdfops.Op_cm + (Pdftransform.matrix_of_transform [Pdftransform.Translate (dx, dy)]) + in + Pdfpage.prepend_operators pdf [translate_op] ~fast o + in + {u with + Pdfpage.content = + (if isover then ( @ ) else ( @@ )) + [protect_removeme pdf u.Pdfpage.resources u.Pdfpage.content] + [protect_removeme pdf o.Pdfpage.resources o.Pdfpage.content]; + Pdfpage.resources = + combine_pdf_resources pdf u.Pdfpage.resources o.Pdfpage.resources} + +(* Alter bookmark destinations given a hash table of (old page reference + * number, new page reference number) pairings *) +let change_destination t = function + Pdfdest.XYZ (Pdfdest.PageObject p, a, b, c) -> + Pdfdest.XYZ (Pdfdest.PageObject (Hashtbl.find t p), a, b, c) + | Pdfdest.Fit (Pdfdest.PageObject p) -> + Pdfdest.Fit (Pdfdest.PageObject (Hashtbl.find t p)) + | Pdfdest.FitH (Pdfdest.PageObject p, x) -> + Pdfdest.FitH (Pdfdest.PageObject (Hashtbl.find t p), x) + | Pdfdest.FitV (Pdfdest.PageObject p, x) -> + Pdfdest.FitV (Pdfdest.PageObject (Hashtbl.find t p), x) + | Pdfdest.FitR (Pdfdest.PageObject p, a, b, c, d) -> + Pdfdest.FitR (Pdfdest.PageObject (Hashtbl.find t p), a, b, c, d) + | Pdfdest.FitB (Pdfdest.PageObject p) -> + Pdfdest.Fit (Pdfdest.PageObject (Hashtbl.find t p)) + | Pdfdest.FitBH (Pdfdest.PageObject p, x) -> + Pdfdest.FitBH (Pdfdest.PageObject (Hashtbl.find t p), x) + | Pdfdest.FitBV (Pdfdest.PageObject p, x) -> + Pdfdest.FitBV (Pdfdest.PageObject (Hashtbl.find t p), x) + | x -> x + +let change_bookmark t m = + {m with Pdfmarks.target = + try change_destination t m.Pdfmarks.target with Not_found -> m.Pdfmarks.target} + +let stamp position fast scale_to_fit isover range over pdf = + let marks = Pdfmarks.read_bookmarks pdf in + let marks_refnumbers = Pdf.page_reference_numbers pdf in + let pdf = Pdfmarks.remove_bookmarks pdf in + let over = Pdfmarks.remove_bookmarks over in + let pageseqs = ilist 1 (Pdfpage.endpage pdf) in + let over_firstpage_pdf = + match Pdfpage.pages_of_pagetree over with + | [] -> error "empty PDF" + | h::_ -> Pdfpage.change_pages true over [h] + in + let merged = + Pdfmerge.merge_pdfs + ~rotations:[Pdfmerge.DNR; Pdfmerge.DNR] + false false ["a"; "b"] [pdf; over_firstpage_pdf] [pageseqs; [1]] + in + let renamed_pdf = + Pdfpage.change_pages true + merged (Pdfpage.renumber_pages merged (Pdfpage.pages_of_pagetree merged)) + in + let renamed_pages = Pdfpage.pages_of_pagetree renamed_pdf in + let under_pages, over_page = + all_but_last renamed_pages, last renamed_pages + in + let new_pages = + map2 + (fun pageseq under_page -> + do_stamp fast position scale_to_fit isover renamed_pdf + (if mem pageseq range then over_page else + Pdfpage.blankpage Pdfpaper.a4) + under_page over) + pageseqs + under_pages + in + let changed = Pdfpage.change_pages true renamed_pdf new_pages in + let new_refnumbers = Pdf.page_reference_numbers changed in + let changetable = hashtable_of_dictionary (List.combine marks_refnumbers new_refnumbers) in + let new_marks = map (change_bookmark changetable) marks in + Pdfmarks.add_bookmarks new_marks changed + +(* Combine pages from two PDFs. For now, assume equal length. *) + +(* If [over] has more pages than [under], chop the excess. If the converse, pad +[over] to the same length *) +let equalize_pages under over = + let length_under = Pdfpage.endpage under + in let length_over = Pdfpage.endpage over + in + if length_over > length_under then + under, + (Pdfpage.change_pages true over (take (Pdfpage.pages_of_pagetree over) length_under)) + else if length_under > length_over then + under, + Pdfpage.change_pages true + over + (Pdfpage.pages_of_pagetree over @ + (many (Pdfpage.blankpage Pdfpaper.a4) (length_under - length_over))) + else + under, over + +let combine_pages (fast : bool) under over scaletofit swap equalize = + let marks_under = Pdfmarks.read_bookmarks under in + let marks_over = Pdfmarks.read_bookmarks over in + let under, over = if equalize then equalize_pages under over else under, over in + let under_length = Pdfpage.endpage under + in let over_length = Pdfpage.endpage over in + if under_length <> over_length then raise (Pdf.PDFError "combine_pages: not of equal length") else + let pageseqs_under = ilist 1 (Pdfpage.endpage under) + in let pageseqs_over = ilist 1 (Pdfpage.endpage over) in + let merged = + Pdfmerge.merge_pdfs ~rotations: [Pdfmerge.DNR; Pdfmerge.DNR] false false ["a"; "b"] [under; over] [pageseqs_under; pageseqs_over] in + let renamed_pdf = + Pdfpage.change_pages true + merged (Pdfpage.renumber_pages merged (Pdfpage.pages_of_pagetree merged)) + in + let under_pages, over_pages = + cleave (Pdfpage.pages_of_pagetree renamed_pdf) under_length + in + let new_pages = + map2 (fun o u -> do_stamp fast (BottomLeft 0.) scaletofit (not swap) renamed_pdf o u over) over_pages under_pages + in + Pdfmarks.add_bookmarks (marks_under @ marks_over) (Pdfpage.change_pages true renamed_pdf new_pages) + +let nobble_page pdf _ page = + let minx, miny, maxx, maxy = + (* Use cropbox if available *) + Pdf.parse_rectangle + (match Pdf.lookup_direct pdf "/CropBox" page.Pdfpage.rest with + | Some r -> r + | None -> page.Pdfpage.mediabox) + in + let fontdict = + match Pdf.lookup_direct pdf "/Font" page.Pdfpage.resources with + | None -> Pdf.Dictionary [] + | Some d -> d + in + let fontname = Pdf.unique_key "F" fontdict in + let width = maxx -. minx in let height = maxy -. miny in + let scalex = + (width *. 1000.) /. float (Pdfstandard14.textwidth false Pdftext.Helvetica "DEMO") + in + let page' = + let font = + Pdf.Dictionary + [("/Type", Pdf.Name "/Font"); + ("/Subtype", Pdf.Name "/Type1"); + ("/BaseFont", Pdf.Name "/Helvetica")] + in let ops = + [Pdfops.Op_BMC "/CPDFSTAMP"; + Pdfops.Op_cm + (Pdftransform.matrix_of_transform + [Pdftransform.Translate (minx, miny +. height /. 2.)]); + Pdfops.Op_gs "/gs0"; + Pdfops.Op_BT; + Pdfops.Op_Tf (fontname, scalex); + Pdfops.Op_Tj "DEMO"; + Pdfops.Op_ET; + Pdfops.Op_EMC] + in + {(Pdfpage.blankpage Pdfpaper.a4) with + Pdfpage.mediabox = page.Pdfpage.mediabox; + Pdfpage.content = [Pdfops.stream_of_ops ops]; + Pdfpage.resources = + Pdf.Dictionary + [("/Font", Pdf.Dictionary [(fontname, font)]); + ("/ExtGState", Pdf.Dictionary + ["/gs0", + Pdf.Dictionary["/Type", Pdf.Name "/ExtGState"; "/ca", Pdf.Real 0.2]]); + ] + } + in + do_stamp false (BottomLeft 0.) false true pdf page' page (Pdf.empty ()) + (* \section{Set media box} *) let set_mediabox x y w h pdf range = let crop_page _ page = diff --git a/cpdf.mli b/cpdf.mli index 7888e1c..4773280 100644 --- a/cpdf.mli +++ b/cpdf.mli @@ -14,6 +14,23 @@ 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. *) +(** Possible positions for adding text and other uses. See cpdfmanual.pdf *) +type position = + | PosCentre of float * float + | PosLeft of float * float + | PosRight of float * float + | Top of float + | TopLeft of float + | TopRight of float + | Left of float + | BottomLeft of float + | Bottom of float + | BottomRight of float + | Right of float + | Diagonal + | ReverseDiagonal + | Centre + (** {2 Debug} *) (** Debug: Print out a PDF in readable form to the terminal *) @@ -178,10 +195,10 @@ swapped. If [fast] is true, the PDFs are assumed to be well-formed and no fixes are done. *) val combine_pages : bool -> Pdf.t -> Pdf.t -> bool -> bool -> bool -> Pdf.t -(** [stamp scale_to_fit fast isover range over pdf] stamps the first page of +(** [stamp scale_to_fit position fast isover range over pdf] stamps the first page of [over] over each page of the PDF. The arguments have the same meaning as in [combine_pages]. *) -val stamp : bool -> bool -> bool -> int list -> Pdf.t -> Pdf.t -> Pdf.t +val stamp : position -> bool -> bool -> bool -> int list -> Pdf.t -> Pdf.t -> Pdf.t (** {2 Splitting PDFs} *) @@ -217,22 +234,6 @@ val list_fonts : Pdf.t -> (int * string * string * string * string) list (** Expand the string "now" to a PDF date string, ignoring any other string *) val expand_date : string -> string -(** Possible positions for adding text and other uses. See cpdfmanual.pdf *) -type position = - | PosCentre of float * float - | PosLeft of float * float - | PosRight of float * float - | Top of float - | TopLeft of float - | TopRight of float - | Left of float - | BottomLeft of float - | Bottom of float - | BottomRight of float - | Right of float - | Diagonal - | ReverseDiagonal - | Centre (** Produce a debug string of a [position] *) val string_of_position : position -> string diff --git a/cpdfcommand.ml b/cpdfcommand.ml index 88ff257..3c15870 100644 --- a/cpdfcommand.ml +++ b/cpdfcommand.ml @@ -864,10 +864,13 @@ let setaddbookmarks s = setop (AddBookmarks s) () let setstampon f = - setop (StampOn f) () + setop (StampOn f) (); + (* Due to an earlier bad decision (default position), we have this nasty hack *) + if args.position = Cpdf.TopLeft 100. then args.position <- Cpdf.BottomLeft 0. let setstampunder f = - setop (StampUnder f) () + setop (StampUnder f) (); + if args.position = Cpdf.TopLeft 100. then args.position <- Cpdf.BottomLeft 0. let setstamponmulti f = setop (StampOn f) (); @@ -3099,12 +3102,7 @@ let go () = | Some Split -> begin match args.inputs, args.out with | [(f, ranges, _, _, _)], File output_spec -> - let pdf = get_single_pdf args.op true - (*and filename = - match f with - | InFile n -> n - | _ -> ""*) - in + let pdf = get_single_pdf args.op true in let enc = match args.crypt_method with | "" -> None @@ -3245,7 +3243,6 @@ let go () = begin match args.inputs with | [(k, _, _, _, _) as input] -> let pdf = get_pdf_from_input_kind input args.op k in - (* Convert from string to int *) let topage = try match args.topage with @@ -3344,7 +3341,6 @@ let go () = in let overpdf = if args.uprightstamp then Cpdf.upright ~fast:args.fast (ilist 1 (Pdfpage.endpage overpdf)) overpdf else overpdf in let pdf = get_single_pdf args.op false in - (*let marks = Pdfmarks.read_bookmarks pdf in*) let range = parse_pagespec pdf (get_pagespec ()) in let pdf = if args.ismulti @@ -3352,10 +3348,8 @@ let go () = let overpdf = equalize_pages_extend pdf overpdf in Cpdf.combine_pages args.fast pdf overpdf true false false else - Cpdf.stamp args.fast args.scale_stamp_to_fit true range overpdf pdf + Cpdf.stamp args.position args.fast args.scale_stamp_to_fit true range overpdf pdf in - (*let p = Pdfmarks.add_bookmarks marks pdf in - Pdfwrite.debug_whole_pdf p;*) write_pdf false pdf | Some (StampUnder under) -> let underpdf = @@ -3365,16 +3359,16 @@ let go () = in let underpdf = if args.uprightstamp then Cpdf.upright ~fast:args.fast (ilist 1 (Pdfpage.endpage underpdf)) underpdf else underpdf in let pdf = get_single_pdf args.op false in - (*let marks = Pdfmarks.read_bookmarks pdf in*) let range = parse_pagespec pdf (get_pagespec ()) in let pdf = if args.ismulti then let underpdf = equalize_pages_extend pdf underpdf in Cpdf.combine_pages args.fast pdf underpdf true true false - else Cpdf.stamp args.fast args.scale_stamp_to_fit false range underpdf pdf + else + Cpdf.stamp args.position args.fast args.scale_stamp_to_fit false range underpdf pdf in - write_pdf false pdf (*(Pdfmarks.add_bookmarks marks pdf)*) + write_pdf false pdf | Some (CombinePages over) -> write_pdf false (Cpdf.combine_pages args.fast (get_single_pdf args.op false) (pdfread_pdf_of_file None None over) false false true) diff --git a/cpdfmanual.pdf b/cpdfmanual.pdf index df8aa59..ddb7524 100644 Binary files a/cpdfmanual.pdf and b/cpdfmanual.pdf differ diff --git a/cpdfmanual.tex b/cpdfmanual.tex index 4268419..3bef149 100644 --- a/cpdfmanual.tex +++ b/cpdfmanual.tex @@ -6,6 +6,7 @@ % Explain page labels in -page-info % Correct the documentation for -diagonal and -reverse-diagonal % Explain octal escape sequences in meta fields with -raw +% is scale_to_fit in do_stamp documented? \documentclass[a4paper,makeidx]{memoir} \usepackage{palatino} @@ -1160,7 +1161,9 @@ writing to \texttt{out.pdf}. A watermark should go underneath each page: \small\verb!cpdf -stamp-under topsecret.pdf in.pdf -o out.pdf! \end{framed} - \noindent The \texttt{-combine-pages} operation takes two PDF files and stamps each +\noindent The position commands in \Sref{position} can be used to locate the stamp more precisely (they are calculated relative to the crop box of the stamp). Or, preprocess the stamp with \texttt{-shift} first. + + The \texttt{-combine-pages} operation takes two PDF files and stamps each page of one over each page of the other. The length of the output is the same as the length of the ``under'' file. For instance: \begin{framed}