From 671a637271eaffb479b23ddb9878995d4b7491d9 Mon Sep 17 00:00:00 2001 From: John Whitington Date: Thu, 12 Aug 2021 20:38:55 +0100 Subject: [PATCH] cpdfposition --- Makefile | 2 +- cpdf.ml | 197 ++++++++++++++--------------------------------- cpdf.mli | 47 ++--------- cpdfcommand.ml | 56 +++++++------- cpdfposition.ml | 88 +++++++++++++++++++++ cpdfposition.mli | 32 ++++++++ 6 files changed, 210 insertions(+), 212 deletions(-) create mode 100644 cpdfposition.ml create mode 100644 cpdfposition.mli diff --git a/Makefile b/Makefile index b61d8f8..e9c6302 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # Build the cpdf command line tools and top level MODS = tjutil tjutf16 tjllist tjparserMonad tjjson xmlm \ - cpdfwriteJSON cpdfstrftime cpdfcoord cpdfpagespec cpdf cpdfcommand + cpdfwriteJSON cpdfstrftime cpdfcoord cpdfpagespec cpdfposition cpdf cpdfcommand SOURCES = $(foreach x,$(MODS),$(x).ml $(x).mli) cpdfcommandrun.ml diff --git a/cpdf.ml b/cpdf.ml index 73fe76f..463be48 100644 --- a/cpdf.ml +++ b/cpdf.ml @@ -1268,94 +1268,6 @@ let print_fonts pdf = (* \section{Superimpose text, page numbers etc.} *) -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 - -let string_of_position = function - | PosCentre (a, b) -> Printf.sprintf "PosCentre %f %f" a b - | PosLeft (a, b) -> Printf.sprintf "PosLeft %f %f" a b - | PosRight (a, b) -> Printf.sprintf "PosRight %f %f" a b - | Top a -> Printf.sprintf "Top %f" a - | TopLeft a -> Printf.sprintf "TopLeft %f" a - | TopRight a -> Printf.sprintf "TopRight %f" a - | Left a -> Printf.sprintf "Left %f" a - | BottomLeft a -> Printf.sprintf "BottomLeft %f" a - | Bottom a -> Printf.sprintf "Bottom %f" a - | BottomRight a -> Printf.sprintf "BottomRight %f" a - | Right a -> Printf.sprintf "Right %f" a - | Diagonal -> "Diagonal" - | ReverseDiagonal -> "Reverse Diagonal" - | Centre -> "Centre" - -type orientation = - | Horizontal - | Vertical - | VerticalDown - -type justification = LeftJustify | CentreJustify | RightJustify - -(* Given the mediabox, calculate an absolute position for the text. *) -let calculate_position ignore_d w (xmin, ymin, xmax, ymax) orientation pos = - let rot = if orientation = VerticalDown then rad_of_deg 270. else 0. in - match pos with - | Centre -> - (xmin +. xmax) /. 2. -. w /. 2., - (ymin +. ymax) /. 2., - rot - | Diagonal -> - let angle = atan ((ymax -. ymin) /. (xmax -. xmin)) - in let cx, cy = (xmax +. xmin) /. 2., (ymax +. ymin) /. 2. in - let dl = w /. 2. in - let dx = dl *. cos angle - in let dy = dl *. sin angle in - cx -. dx, cy -. dy, angle - | ReverseDiagonal -> - let angle = atan ((ymax -. ymin) /. (xmax -. xmin)) - in let cx, cy = (xmax +. xmin) /. 2., (ymax +. ymin) /. 2. in - let dl = w /. 2. in - let dx = dl *. cos angle - in let dy = dl *. sin angle in - cx -. dx, (ymax +. ymin) -. (cy -. dy), angle -. ((2. *. pi) -. ((pi -. (2. *. angle)) *. 2.) /. 2.) +. pi - | PosLeft (x, y) -> xmin +. x, ymin +. y, rot - | PosCentre (x, y) -> xmin +. x -. (w /. 2.), ymin +. y, rot - | PosRight (x, y) -> xmin +. x -. w, ymin +. y, rot - | Top d -> - let d = if ignore_d then 0. else d in - (xmin +. xmax) /. 2. -. w /. 2., ymax -. d, rot - | TopLeft d -> - let d = if ignore_d then 0. else d in - xmin +. d, ymax -. d, rot - | TopRight d -> - let d = if ignore_d then 0. else d in - xmax -. d -. w, ymax -. d, rot - | Left d -> - let d = if ignore_d then 0. else d in - xmin +. d, (ymax +. ymin) /. 2., rot - | BottomLeft d -> - let d = if ignore_d then 0. else d in - xmin +. d, ymin +. d, rot - | Bottom d -> - let d = if ignore_d then 0. else d in - (xmin +. xmax) /. 2. -. w /. 2., ymin +. d, rot - | BottomRight d -> - let d = if ignore_d then 0. else d in - xmax -. d -. w, ymin +. d, rot - | Right d -> - let d = if ignore_d then 0. else d in - xmax -. d -. w, (ymax +. ymin) /. 2., rot (* Process UTF8 text to /WinAnsiEncoding string. *) let winansi_of_utf8 s = @@ -1445,33 +1357,37 @@ let ops longest_w metrics x y rotate hoffset voffset outline linewidth unique_fo Pdfops.Op_EMC; Pdfops.Op_Q] +type justification = LeftJustify | CentreJustify | RightJustify + (* Find the h-offset for justification based on the longest width, the current width, the justification and the position. *) -let find_justification_offsets longest_w w position = function - | LeftJustify -> - begin match position with - | TopLeft _ | Left _ | PosLeft _ | BottomLeft _ -> 0. - | Top _ | PosCentre _ | Bottom _ | Centre -> (longest_w -. w) /. 2. - | TopRight _ | BottomRight _ | PosRight _ | Right _ -> longest_w -. w - | Diagonal -> 0. - | ReverseDiagonal -> 0. - end - | RightJustify -> - begin match position with - | TopLeft _ | Left _ | PosLeft _ | BottomLeft _ -> ~-.(longest_w -. w) - | Top _ | PosCentre _ | Bottom _ | Centre -> ~-.((longest_w -. w) /. 2.) - | TopRight _ | BottomRight _ | PosRight _ | Right _ -> 0. - | Diagonal -> 0. - | ReverseDiagonal -> 0. - end - | CentreJustify -> - begin match position with - | TopLeft _ | Left _ | PosLeft _ | BottomLeft _ -> ~-.((longest_w -. w) /. 2.) - | Top _ | PosCentre _ | Bottom _ | Centre -> 0. - | TopRight _ | BottomRight _ | PosRight _ | Right _ -> (longest_w -. w) /. 2. - | Diagonal -> 0. - | ReverseDiagonal -> 0. - end +let find_justification_offsets longest_w w position j = + let open Cpdfposition in + match j with + | LeftJustify -> + begin match position with + | TopLeft _ | Left _ | PosLeft _ | BottomLeft _ -> 0. + | Top _ | PosCentre _ | Bottom _ | Centre -> (longest_w -. w) /. 2. + | TopRight _ | BottomRight _ | PosRight _ | Right _ -> longest_w -. w + | Diagonal -> 0. + | ReverseDiagonal -> 0. + end + | RightJustify -> + begin match position with + | TopLeft _ | Left _ | PosLeft _ | BottomLeft _ -> ~-.(longest_w -. w) + | Top _ | PosCentre _ | Bottom _ | Centre -> ~-.((longest_w -. w) /. 2.) + | TopRight _ | BottomRight _ | PosRight _ | Right _ -> 0. + | Diagonal -> 0. + | ReverseDiagonal -> 0. + end + | CentreJustify -> + begin match position with + | TopLeft _ | Left _ | PosLeft _ | BottomLeft _ -> ~-.((longest_w -. w) /. 2.) + | Top _ | PosCentre _ | Bottom _ | Centre -> 0. + | TopRight _ | BottomRight _ | PosRight _ | Right _ -> (longest_w -. w) /. 2. + | Diagonal -> 0. + | ReverseDiagonal -> 0. + end (* Lex an integer from the table *) let extract_num header s = @@ -1599,6 +1515,8 @@ let extract_text extract_text_font_size pdf range = fold_left (fun x y -> x ^ (if x <> "" && y <> "" then "\n" else "") ^ y) "" (map_pages (extract_page_text extract_text_font_size pdf) pdf range) + + let addtext metrics lines linewidth outline fast colour fontname embed bates batespad fontsize font underneath position hoffset voffset text pages orientation cropbox opacity @@ -1696,7 +1614,7 @@ let addtext else Pdf.parse_rectangle page.Pdfpage.mediabox in - let x, y, rotate = calculate_position false textwidth mediabox orientation position in + let x, y, rotate = Cpdfposition.calculate_position false textwidth mediabox orientation position in let hoffset, voffset = if position = Diagonal || position = ReverseDiagonal then -. (cos ((pi /. 2.) -. rotate) *. voffset), sin ((pi /. 2.) -. rotate) *. voffset @@ -1785,6 +1703,7 @@ let let lines = map unescape_string (split_at_newline text) in let pdf = ref pdf in let voffset = + let open Cpdfposition in match position with | Bottom _ | BottomLeft _ | BottomRight _ -> ref (0. -. (linespacing *. fontsize *. (float (length lines) -. 1.))) @@ -1824,7 +1743,7 @@ let iter (fun line -> let voff, hoff = - if orientation = Vertical then 0., -.(!voffset) else !voffset, 0. + if orientation = Cpdfposition.Vertical then 0., -.(!voffset) else !voffset, 0. in pdf := addtext metrics lines linewidth outline fast colour fontname @@ -2241,20 +2160,21 @@ let stamp_shift_of_position topline midline sw sh w h p = else if topline then sh else 0. in - match p with - | PosCentre (ox, oy) -> ox -. half sw, oy -. dy - | PosLeft (ox, oy) -> ox, oy -. dy - | PosRight (ox, oy) -> ox -. sw, oy -. dy - | Top o -> half w -. half sw, h -. o -. sh -. dy - | TopLeft o -> o, h -. sh -. o -. dy - | TopRight o -> w -. sw -. o, h -. sh -. o -. dy - | Left o -> o, half h -. half sh -. dy - | BottomLeft o -> o, o -. dy - | Bottom o -> half w -. half sw, o -. dy - | BottomRight o -> w -. sw -. o, o -. dy - | Right o -> w -. sw -. o, half h -. half sh -. dy - | Diagonal | ReverseDiagonal | Centre -> - half w -. half sw, half h -. half sh -. dy + let open Cpdfposition in + match p with + | PosCentre (ox, oy) -> ox -. half sw, oy -. dy + | PosLeft (ox, oy) -> ox, oy -. dy + | PosRight (ox, oy) -> ox -. sw, oy -. dy + | Top o -> half w -. half sw, h -. o -. sh -. dy + | TopLeft o -> o, h -. sh -. o -. dy + | TopRight o -> w -. sw -. o, h -. sh -. o -. dy + | Left o -> o, half h -. half sh -. dy + | BottomLeft o -> o, o -. dy + | Bottom o -> half w -. half sw, o -. dy + | BottomRight o -> w -. sw -. o, o -. dy + | Right o -> w -. sw -. o, half h -. half sh -. dy + | Diagonal | ReverseDiagonal | Centre -> + half w -. half sw, half h -. half sh -. dy (* Combine Pdfpage.rest items for two PDFs. For now, we combine /Annots, and * copy everything else from adict. What else should we combine? *) @@ -2819,13 +2739,13 @@ let scale_to_fit_pdf ?(fast=false) position input_scale xylist op pdf range = let scale = fmin fx fy *. input_scale in let trans_x = match position with - Left _ -> 0. - | Right _ -> (x -. (maxx *. scale)) + Cpdfposition.Left _ -> 0. + | Cpdfposition.Right _ -> (x -. (maxx *. scale)) | _ -> (x -. (maxx *. scale)) /. 2. and trans_y = match position with - | Top _ -> (y -. (maxy *. scale)) - | Bottom _ -> 0. + | Cpdfposition.Top _ -> (y -. (maxy *. scale)) + | Cpdfposition.Bottom _ -> 0. | _ -> (y -. (maxy *. scale)) /. 2. in (Pdftransform.matrix_of_transform @@ -2853,8 +2773,9 @@ let scale_page_contents ?(fast=false) scale position pdf pnum page = | Some r -> r | None -> page.Pdfpage.mediabox) in - let sx, sy, _ = calculate_position true 0. box Horizontal position in + let sx, sy, _ = Cpdfposition.calculate_position true 0. box Horizontal position in let tx, ty = + let open Cpdfposition in match position with | Top t -> 0., -.t | TopLeft t -> t, -.t @@ -3343,14 +3264,8 @@ let dc = "http://purl.org/dc/elements/1.1/" let rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" -(* For OCaml < 4.00 *) -let string_trim s = - implode - (rev (dropwhile - Pdf.is_whitespace (rev (dropwhile Pdf.is_whitespace (explode s))))) - let combine_with_spaces strs = - string_trim + String.trim (fold_left (fun x y -> x ^ (if x <> "" then ", " else "") ^ y) "" strs) (* Collect all
  • elements inside a seq, bag, or alt. Combine with commas. If diff --git a/cpdf.mli b/cpdf.mli index ea06c35..027cc18 100644 --- a/cpdf.mli +++ b/cpdf.mli @@ -14,23 +14,6 @@ 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 *) @@ -174,7 +157,7 @@ val combine_pages : bool -> Pdf.t -> Pdf.t -> bool -> bool -> bool -> Pdf.t (** [stamp relative_to_cropbox position topline midline fast scale_to_fit 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 -> position -> bool -> bool -> bool -> bool -> bool -> int list -> Pdf.t -> Pdf.t -> Pdf.t +val stamp : bool -> Cpdfposition.position -> bool -> bool -> bool -> bool -> bool -> int list -> Pdf.t -> Pdf.t -> Pdf.t (** {2 Splitting PDFs} *) @@ -194,32 +177,12 @@ 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 - -(** Produce a debug string of a [position] *) -val string_of_position : position -> string - -(** Orientation of the string on the page *) -type orientation = - | Horizontal - | Vertical - | VerticalDown - (** Justification of multiline text *) type justification = | LeftJustify | CentreJustify | RightJustify -(** [calculate_position ignore_d w (xmin, ymin, xmax, ymax) orientation pos] calculates -the absolute position of text given its width, bounding box, orientation and -position. If [ignore_d] is true, the distance from the position (e.g 10 in -TopLeft 10) is ignored (considered zero). *) -val calculate_position : - bool -> - float -> - float * float * float * float -> - orientation -> position -> float * float * float - (** Call [add_texts metrics linewidth outline fast fontname font bates batespad colour position linespacing fontsize underneath text pages orientation relative_to_cropbox midline_adjust topline filename pdf]. For details see cpdfmanual.pdf *) @@ -234,13 +197,13 @@ val addtexts : int -> (* bates number *) int option -> (* bates padding width *) float * float * float -> (*colour*) - position -> (*position*) + Cpdfposition.position -> (*position*) float -> (*linespacing*) float -> (*fontsize*) bool -> (*underneath*) string ->(*text*) int list ->(*page range*) - orientation ->(*orientation*) + Cpdfposition.orientation ->(*orientation*) bool ->(*relative to cropbox?*) float ->(*opacity*) justification ->(*justification*) @@ -323,10 +286,10 @@ val scale_pdf : ?fast:bool -> (float * float) list -> Pdf.t -> int list -> Pdf.t (** [scale_to_fit_pdf fast position input_scale x y op pdf range] scales a page to fit the page size given by (x, y) and by the [input_scale] (e.g 1.0 = scale to fit, 0.9 = scale to fit leaving a border etc.). [op] is unused. *) -val scale_to_fit_pdf : ?fast:bool -> position -> float -> (float * float) list -> 'a -> Pdf.t -> int list -> Pdf.t +val scale_to_fit_pdf : ?fast:bool -> Cpdfposition.position -> float -> (float * float) list -> 'a -> Pdf.t -> int list -> Pdf.t (** Scale the contents of a page by a given factor centred around a given point in a given range. *) -val scale_contents : ?fast:bool -> position -> float -> Pdf.t -> int list -> Pdf.t +val scale_contents : ?fast:bool -> Cpdfposition.position -> float -> Pdf.t -> int list -> Pdf.t val trim_marks : ?fast:bool -> Pdf.t -> int list -> Pdf.t diff --git a/cpdfcommand.ml b/cpdfcommand.ml index 938fcc8..78cb56d 100644 --- a/cpdfcommand.ml +++ b/cpdfcommand.ml @@ -379,7 +379,7 @@ type args = mutable fontsize : float; mutable color : float * float * float; mutable opacity : float; - mutable position : Cpdf.position; + mutable position : Cpdfposition.position; mutable underneath : bool; mutable linespacing : float; mutable midline : bool; @@ -388,7 +388,7 @@ type args = mutable bates : int; mutable batespad : int option; mutable prerotate : bool; - mutable orientation : Cpdf.orientation; + mutable orientation : Cpdfposition.orientation; mutable relative_to_cropbox : bool; mutable keepversion : bool; mutable bycolumns : bool; @@ -483,7 +483,7 @@ let args = fontsize = 12.; color = 0., 0., 0.; opacity = 1.; - position = Cpdf.TopLeft 100.; + position = Cpdfposition.TopLeft 100.; underneath = false; linespacing = 1.; midline = false; @@ -492,7 +492,7 @@ let args = bates = 0; batespad = None; prerotate = false; - orientation = Cpdf.Horizontal; + orientation = Cpdfposition.Horizontal; relative_to_cropbox = false; keepversion = false; bycolumns = false; @@ -587,7 +587,7 @@ let reset_arguments () = args.fontsize <- 12.; args.color <- 0., 0., 0.; args.opacity <- 1.; - args.position <- Cpdf.TopLeft 100.; + args.position <- Cpdfposition.TopLeft 100.; args.underneath <- false; args.linespacing <- 1.; args.midline <- false; @@ -596,7 +596,7 @@ let reset_arguments () = args.bates <- 0; args.batespad <- None; args.prerotate <- false; - args.orientation <- Cpdf.Horizontal; + args.orientation <- Cpdfposition.Horizontal; args.relative_to_cropbox <- false; args.keepversion <- false; args.bycolumns <- false; @@ -1047,11 +1047,11 @@ let setaddbookmarks s = let setstampon 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. + if args.position = Cpdfposition.TopLeft 100. then args.position <- Cpdfposition.BottomLeft 0. let setstampunder f = setop (StampUnder f) (); - if args.position = Cpdf.TopLeft 100. then args.position <- Cpdf.BottomLeft 0. + if args.position = Cpdfposition.TopLeft 100. then args.position <- Cpdfposition.BottomLeft 0. let setstampasxobject f = setop (StampAsXObject f) () @@ -1061,58 +1061,58 @@ let setcombinepages f = let setposcenter s = let x, y = Cpdfcoord.parse_coordinate empty s in - args.position <- Cpdf.PosCentre (x, y) + args.position <- Cpdfposition.PosCentre (x, y) let setposleft s = let x, y = Cpdfcoord.parse_coordinate empty s in - args.position <- Cpdf.PosLeft (x, y) + args.position <- Cpdfposition.PosLeft (x, y) let setposright s = let x, y = Cpdfcoord.parse_coordinate empty s in - args.position <- Cpdf.PosRight (x, y) + args.position <- Cpdfposition.PosRight (x, y) let settop n = - args.position <- Cpdf.Top (Cpdfcoord.parse_single_number empty n); + args.position <- Cpdfposition.Top (Cpdfcoord.parse_single_number empty n); args.justification <- Cpdf.CentreJustify let settopleft n = - args.position <- Cpdf.TopLeft (Cpdfcoord.parse_single_number empty n); + args.position <- Cpdfposition.TopLeft (Cpdfcoord.parse_single_number empty n); args.justification <- Cpdf.LeftJustify let settopright n = - args.position <- Cpdf.TopRight (Cpdfcoord.parse_single_number empty n); + args.position <- Cpdfposition.TopRight (Cpdfcoord.parse_single_number empty n); args.justification <- Cpdf.RightJustify let setleft n = - args.position <- Cpdf.Left (Cpdfcoord.parse_single_number empty n); + args.position <- Cpdfposition.Left (Cpdfcoord.parse_single_number empty n); args.justification <- Cpdf.LeftJustify let setbottomleft n = - args.position <- Cpdf.BottomLeft (Cpdfcoord.parse_single_number empty n); + args.position <- Cpdfposition.BottomLeft (Cpdfcoord.parse_single_number empty n); args.justification <- Cpdf.LeftJustify let setbottom n = - args.position <- Cpdf.Bottom (Cpdfcoord.parse_single_number empty n); + args.position <- Cpdfposition.Bottom (Cpdfcoord.parse_single_number empty n); args.justification <- Cpdf.CentreJustify let setbottomright n = - args.position <- Cpdf.BottomRight (Cpdfcoord.parse_single_number empty n); + args.position <- Cpdfposition.BottomRight (Cpdfcoord.parse_single_number empty n); args.justification <- Cpdf.RightJustify let setright n = - args.position <- Cpdf.Right (Cpdfcoord.parse_single_number empty n); + args.position <- Cpdfposition.Right (Cpdfcoord.parse_single_number empty n); args.justification <- Cpdf.RightJustify let setdiagonal n = - args.position <- Cpdf.Diagonal; + args.position <- Cpdfposition.Diagonal; args.justification <- Cpdf.CentreJustify let setreversediagonal n = - args.position <- Cpdf.ReverseDiagonal; + args.position <- Cpdfposition.ReverseDiagonal; args.justification <- Cpdf.CentreJustify let setcenter n = - args.position <- Cpdf.Centre; + args.position <- Cpdfposition.Centre; args.justification <- Cpdf.CentreJustify let setbatespad n = @@ -1220,7 +1220,7 @@ let setscaletofitscale f = let setscalecontents f = detect_duplicate_op (ScaleContents f); args.op <- Some (ScaleContents f); - args.position <- Cpdf.Diagonal (* Will be center *) + args.position <- Cpdfposition.Diagonal (* Will be center *) let setsqueeze () = args.squeeze <- true; @@ -1345,10 +1345,10 @@ let setp2ppath p = args.path_to_p2p <- p let settextvertical () = - args.orientation <- Cpdf.Vertical + args.orientation <- Cpdfposition.Vertical let settextverticaldown () = - args.orientation <- Cpdf.VerticalDown + args.orientation <- Cpdfposition.VerticalDown let setfrombox s = detect_duplicate_op CopyBox; @@ -3351,12 +3351,12 @@ let addrectangle Pdf.parse_rectangle page.Pdfpage.mediabox in let x, y, _ = - Cpdf.calculate_position false w mediabox Cpdf.Horizontal position + Cpdfposition.calculate_position false w mediabox Cpdfposition.Horizontal position in let x, y = match position with - Cpdf.Top _ | Cpdf.TopLeft _ | Cpdf.TopRight _ -> (x, y -. h) - | Cpdf.Centre | Cpdf.PosCentre _ -> (x, y -. (h /. 2.)) + Cpdfposition.Top _ | Cpdfposition.TopLeft _ | Cpdfposition.TopRight _ -> (x, y -. h) + | Cpdfposition.Centre | Cpdfposition.PosCentre _ -> (x, y -. (h /. 2.)) | _ -> (x, y) in let ops = diff --git a/cpdfposition.ml b/cpdfposition.ml new file mode 100644 index 0000000..b139603 --- /dev/null +++ b/cpdfposition.ml @@ -0,0 +1,88 @@ +open Pdfutil + +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 + +let string_of_position = function + | PosCentre (a, b) -> Printf.sprintf "PosCentre %f %f" a b + | PosLeft (a, b) -> Printf.sprintf "PosLeft %f %f" a b + | PosRight (a, b) -> Printf.sprintf "PosRight %f %f" a b + | Top a -> Printf.sprintf "Top %f" a + | TopLeft a -> Printf.sprintf "TopLeft %f" a + | TopRight a -> Printf.sprintf "TopRight %f" a + | Left a -> Printf.sprintf "Left %f" a + | BottomLeft a -> Printf.sprintf "BottomLeft %f" a + | Bottom a -> Printf.sprintf "Bottom %f" a + | BottomRight a -> Printf.sprintf "BottomRight %f" a + | Right a -> Printf.sprintf "Right %f" a + | Diagonal -> "Diagonal" + | ReverseDiagonal -> "Reverse Diagonal" + | Centre -> "Centre" + +type orientation = + | Horizontal + | Vertical + | VerticalDown + +(* Given the mediabox, calculate an absolute position for the text. *) +let calculate_position ignore_d w (xmin, ymin, xmax, ymax) orientation pos = + let rot = if orientation = VerticalDown then rad_of_deg 270. else 0. in + match pos with + | Centre -> + (xmin +. xmax) /. 2. -. w /. 2., + (ymin +. ymax) /. 2., + rot + | Diagonal -> + let angle = atan ((ymax -. ymin) /. (xmax -. xmin)) + in let cx, cy = (xmax +. xmin) /. 2., (ymax +. ymin) /. 2. in + let dl = w /. 2. in + let dx = dl *. cos angle + in let dy = dl *. sin angle in + cx -. dx, cy -. dy, angle + | ReverseDiagonal -> + let angle = atan ((ymax -. ymin) /. (xmax -. xmin)) + in let cx, cy = (xmax +. xmin) /. 2., (ymax +. ymin) /. 2. in + let dl = w /. 2. in + let dx = dl *. cos angle + in let dy = dl *. sin angle in + cx -. dx, (ymax +. ymin) -. (cy -. dy), angle -. ((2. *. pi) -. ((pi -. (2. *. angle)) *. 2.) /. 2.) +. pi + | PosLeft (x, y) -> xmin +. x, ymin +. y, rot + | PosCentre (x, y) -> xmin +. x -. (w /. 2.), ymin +. y, rot + | PosRight (x, y) -> xmin +. x -. w, ymin +. y, rot + | Top d -> + let d = if ignore_d then 0. else d in + (xmin +. xmax) /. 2. -. w /. 2., ymax -. d, rot + | TopLeft d -> + let d = if ignore_d then 0. else d in + xmin +. d, ymax -. d, rot + | TopRight d -> + let d = if ignore_d then 0. else d in + xmax -. d -. w, ymax -. d, rot + | Left d -> + let d = if ignore_d then 0. else d in + xmin +. d, (ymax +. ymin) /. 2., rot + | BottomLeft d -> + let d = if ignore_d then 0. else d in + xmin +. d, ymin +. d, rot + | Bottom d -> + let d = if ignore_d then 0. else d in + (xmin +. xmax) /. 2. -. w /. 2., ymin +. d, rot + | BottomRight d -> + let d = if ignore_d then 0. else d in + xmax -. d -. w, ymin +. d, rot + | Right d -> + let d = if ignore_d then 0. else d in + xmax -. d -. w, (ymax +. ymin) /. 2., rot diff --git a/cpdfposition.mli b/cpdfposition.mli new file mode 100644 index 0000000..a70cfe1 --- /dev/null +++ b/cpdfposition.mli @@ -0,0 +1,32 @@ +(** 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 + +(** Orientation of the string on the page *) +type orientation = Horizontal | Vertical | VerticalDown + +(** [calculate_position ignore_d w (xmin, ymin, xmax, ymax) orientation pos] calculates +the absolute position of text given its width, bounding box, orientation and +position. If [ignore_d] is true, the distance from the position (e.g 10 in +TopLeft 10) is ignored (considered zero). *) +val calculate_position : + bool -> + float -> + float * float * float * float -> + orientation -> position -> float * float * float