From dc2380298a93b3c0f621b77e0fd9a4ac833e26e9 Mon Sep 17 00:00:00 2001 From: John Whitington Date: Fri, 16 Dec 2022 16:49:59 +0000 Subject: [PATCH] more --- cpdfcommand.ml | 108 +++++++++++++++++++++++++++++++++++++------------ cpdfdraw.ml | 9 ++++- cpdfdraw.mli | 2 + 3 files changed, 91 insertions(+), 28 deletions(-) diff --git a/cpdfcommand.ml b/cpdfcommand.ml index 2007187..c715430 100644 --- a/cpdfcommand.ml +++ b/cpdfcommand.ml @@ -1746,9 +1746,18 @@ let whingemalformed () = prerr_string "Command line must be of exactly the form\ncpdf -gs -gs-malformed-force -o \n"; exit 1 -(* Drawing operations. Just the parsed command line ops. We convert to actual PDF operations later. *) +(* Drawing operations. FIXME: Clear this around ANDs? *) +let drawops = + let t = Hashtbl.create 10 in + Hashtbl.add t "_" []; + t -let drawops = ref [] +(* For now, re-using a save name is undefined, and nesting them is undefined too. To fix in both cases. *) +let currstash = ref "_" + +let addop o = + let v = Hashtbl.find drawops !currstash in + Hashtbl.replace drawops !currstash (o::v) let col_of_string s = match parse_color s with @@ -1758,44 +1767,44 @@ let col_of_string s = | exception _ -> Cpdfdraw.NoCol let setstroke s = - drawops := Cpdfdraw.SetStroke (col_of_string s)::!drawops + addop (Cpdfdraw.SetStroke (col_of_string s)) let setfill s = - drawops := Cpdfdraw.SetFill (col_of_string s)::!drawops + addop (Cpdfdraw.SetFill (col_of_string s)) let addrect s = let x, y, w, h = Cpdfcoord.parse_rectangle (Pdf.empty ()) s in - drawops := Cpdfdraw.Rect (x, y, w, h)::!drawops + addop (Cpdfdraw.Rect (x, y, w, h)) let addto s = let x, y = Cpdfcoord.parse_coordinate (Pdf.empty ()) s in - drawops := Cpdfdraw.To (x, y)::!drawops + addop (Cpdfdraw.To (x, y)) let addline s = let x, y = Cpdfcoord.parse_coordinate (Pdf.empty ()) s in - drawops := Cpdfdraw.Line (x, y)::!drawops + addop (Cpdfdraw.Line (x, y)) let stroke () = - drawops := Cpdfdraw.Stroke::!drawops + addop Cpdfdraw.Stroke let fill () = - drawops := Cpdfdraw.Fill::!drawops + addop Cpdfdraw.Fill let fillevenodd () = - drawops := Cpdfdraw.FillEvenOdd::!drawops + addop Cpdfdraw.FillEvenOdd let strokefill () = - drawops := Cpdfdraw.FillStroke::!drawops + addop Cpdfdraw.FillStroke let strokefillevenodd () = - drawops := Cpdfdraw.FillStrokeEvenOdd::!drawops + addop Cpdfdraw.FillStrokeEvenOdd let closepath () = - drawops := Cpdfdraw.ClosePath::!drawops + addop Cpdfdraw.ClosePath let setthickness s = try - drawops := Cpdfdraw.SetLineThickness (float_of_string s)::!drawops + addop (Cpdfdraw.SetLineThickness (float_of_string s)) with _ -> error "Thickness must be a number" @@ -1807,7 +1816,7 @@ let setcap s = | "square" -> 2 | _ -> error "Unknown cap type" in - drawops := Cpdfdraw.SetLineCap num::!drawops + addop (Cpdfdraw.SetLineCap num) let setjoin s = let num = @@ -1817,38 +1826,77 @@ let setjoin s = | "bevel" -> 2 | _ -> error "Unknown join type" in - drawops := Cpdfdraw.SetLineJoin num::!drawops + addop (Cpdfdraw.SetLineJoin num) let setmiter s = try - drawops := Cpdfdraw.SetMiterLimit (float_of_string s)::!drawops + addop (Cpdfdraw.SetMiterLimit (float_of_string s)) with _ -> error "Miter limit must be a number" +let readfloats s = map float_of_string (String.split_on_char ' ' s) + let setdash s = try let x, y = - let nums = map float_of_string (String.split_on_char ' ' s) in - all_but_last nums, last nums + let nums = readfloats s in all_but_last nums, last nums in - drawops := Cpdfdraw.SetDashPattern (x, y)::!drawops + addop (Cpdfdraw.SetDashPattern (x, y)) with _ -> error "Dash pattern elements must one or more numbers" let push () = - drawops := Cpdfdraw.Push::!drawops + addop Cpdfdraw.Push let pop () = - drawops := Cpdfdraw.Pop::!drawops + addop Cpdfdraw.Pop let setmatrix s = - match map float_of_string (String.split_on_char ' ' s) with + match readfloats s with | [a; b; c; d; e; f] -> - drawops := Cpdfdraw.Matrix {Pdftransform.a = a; Pdftransform.b = b; Pdftransform.c = c; - Pdftransform.d = d; Pdftransform.e = e; Pdftransform.f = f}::!drawops + addop (Cpdfdraw.Matrix {Pdftransform.a = a; Pdftransform.b = b; Pdftransform.c = c; + Pdftransform.d = d; Pdftransform.e = e; Pdftransform.f = f}) | _ -> error "Matrix must have six numbers" | exception _ -> error "Matrix elements must be numbers" +let setmtranslate s = + match readfloats s with + | [a; b] -> addop (Cpdfdraw.Matrix (Pdftransform.matrix_of_transform [Pdftransform.Translate (a, b)])) + | _ | exception _ -> error "-mtranslate takes two numbers" + +let setmrotate s = + match readfloats s with + | [a; b; c] -> addop (Cpdfdraw.Matrix (Pdftransform.matrix_of_transform [Pdftransform.Rotate ((a, b), c)])) + | _ | exception _ -> error "-mrotate takes three numbers" + +let setmscale s = + match readfloats s with + | [a; b; c; d] -> addop (Cpdfdraw.Matrix (Pdftransform.matrix_of_transform [Pdftransform.Scale ((a, b), c, d)])) + | _ | exception _ -> error "-mtranslate takes four numbers" + +let setmshearx s = + match readfloats s with + | [a; b; c] -> addop (Cpdfdraw.Matrix (Pdftransform.matrix_of_transform [Pdftransform.ShearX ((a, b), c)])) + | _ | exception _ -> error "-mshearx takes three numbers" + +let setmsheary s = + match readfloats s with + | [a; b; c] -> addop (Cpdfdraw.Matrix (Pdftransform.matrix_of_transform [Pdftransform.ShearY ((a, b), c)])) + | _ | exception _ -> error "-msheary takes three numbers" + +let savexobj s = + Hashtbl.add drawops s []; + currstash := s + +let endsave s = + currstash := "_" + +let usexobj s = + try + addop (Cpdfdraw.SoftXObject (rev (Hashtbl.find drawops s))) + with + _ -> error (Printf.sprintf "Could not find stashed graphics %s\n" s) + (* Parse a control file, make an argv, and then make Arg parse it. *) let rec make_control_argv_and_parse filename = control_args := !control_args @ parse_control_file filename @@ -2647,6 +2695,14 @@ and specs = ("-push", Arg.Unit push, " Push graphics stack"); ("-pop", Arg.Unit pop, " Pop graphics stack"); ("-matrix", Arg.String setmatrix, " Append to graphics matrix"); + ("-mtrans", Arg.String setmtranslate, " Translate the graphics matrix"); + ("-mrot", Arg.String setmrotate, " Rotate the graphics matrix"); + ("-mscale", Arg.String setmscale, " Scale the graphics matrix"); + ("-mshearx", Arg.String setmshearx, " Shear the graphics matrix in X"); + ("-msheary", Arg.String setmshearx, " Shear the graphics matrix in Y"); + ("-save", Arg.String savexobj, " Begin to save graphics operators"); + ("-endsave", Arg.String endsave, " End saving of graphics operators"); + ("-use", Arg.String usexobj, " Use a saved sequence of graphics operators"); (* These items are undocumented *) ("-remove-unused-resources", Arg.Unit (setop RemoveUnusedResources), ""); ("-stay-on-error", Arg.Unit setstayonerror, ""); @@ -4147,7 +4203,7 @@ let go () = | Some Draw -> let pdf = get_single_pdf args.op false in let range = parse_pagespec_allow_empty pdf (get_pagespec ()) in - write_pdf false (Cpdfdraw.draw args.fast range pdf (rev !drawops)) + write_pdf false (Cpdfdraw.draw args.fast range pdf (rev (Hashtbl.find drawops "_"))) (* Advise the user if a combination of command line flags makes little sense, or error out if it make no sense at all. *) diff --git a/cpdfdraw.ml b/cpdfdraw.ml index d9cc994..6329d6e 100644 --- a/cpdfdraw.ml +++ b/cpdfdraw.ml @@ -26,8 +26,10 @@ type drawops = | Stroke | FillStroke | FillStrokeEvenOdd + | SoftXObject of drawops list + | HardXObject of drawops list -let ops_of_drawop = function +let rec ops_of_drawop = function | Push -> [Pdfops.Op_q] | Pop -> [Pdfops.Op_Q] | Matrix m -> [Pdfops.Op_cm m] @@ -59,8 +61,11 @@ let ops_of_drawop = function | SetLineJoin j -> [Pdfops.Op_j j] | SetMiterLimit m -> [Pdfops.Op_M m] | SetDashPattern (x, y) -> [Pdfops.Op_d (x, y)] + | SoftXObject l | HardXObject l -> + [Pdfops.Op_q] @ ops_of_drawops l @ [Pdfops.Op_Q] -let ops_of_drawops drawops = flatten (map ops_of_drawop drawops) +and ops_of_drawops drawops = + flatten (map ops_of_drawop drawops) (* Draw all the accumulated operators *) let draw fast range pdf drawops = diff --git a/cpdfdraw.mli b/cpdfdraw.mli index 85fbb12..3bb4616 100644 --- a/cpdfdraw.mli +++ b/cpdfdraw.mli @@ -24,5 +24,7 @@ type drawops = | Stroke | FillStroke | FillStrokeEvenOdd + | SoftXObject of drawops list + | HardXObject of drawops list val draw : bool -> int list -> Pdf.t -> drawops list -> Pdf.t