First stage of PMIN plus 3mm etc

This commit is contained in:
John Whitington 2016-07-21 17:02:11 +01:00
parent 43ffc25b9c
commit ff9e90cb36
3 changed files with 140 additions and 110 deletions

73
cpdf.ml
View File

@ -2082,17 +2082,18 @@ let change_pattern_matrices pdf tr resources =
with
Pdftransform.NonInvertable -> resources
let shift_page ?(fast=false) dx dy pdf _ page =
let transform_op =
Pdfops.Op_cm (Pdftransform.matrix_of_op (Pdftransform.Translate (dx, dy)))
in
let resources' =
change_pattern_matrices pdf (Pdftransform.mktranslate ~-.dx ~-.dy) page.Pdfpage.resources
let shift_page ?(fast=false) dxdylist pdf pnum page =
let dx, dy = List.nth dxdylist (pnum - 1) in
let transform_op =
Pdfops.Op_cm (Pdftransform.matrix_of_op (Pdftransform.Translate (dx, dy)))
in
Pdfpage.prepend_operators pdf [transform_op] ~fast {page with Pdfpage.resources = resources'}
let resources' =
change_pattern_matrices pdf (Pdftransform.mktranslate ~-.dx ~-.dy) page.Pdfpage.resources
in
Pdfpage.prepend_operators pdf [transform_op] ~fast {page with Pdfpage.resources = resources'}
let shift_pdf ?(fast=false) dx dy pdf range =
process_pages (shift_page ~fast dx dy pdf) pdf range
let shift_pdf ?(fast=false) dxdylist pdf range =
process_pages (shift_page ~fast dxdylist pdf) pdf range
(* Change a page's media box so its minimum x and y are 0, making other
operations simpler to think about. Any shift that is done is reflected in
@ -2106,7 +2107,7 @@ let rectify_boxes ?(fast=false) pdf page =
in
let page = change_boxes f pdf page in
if minx <> 0. || miny <> 0.
then shift_page ~fast (-.minx) (-.miny) pdf 0 page
then shift_page ~fast [(-.minx),(-.miny)] pdf 1 page
else page
(* \section{Flip pages} *)
@ -2398,8 +2399,9 @@ let nobble_page pdf _ page =
do_stamp false false (BottomLeft 0.) false false false true pdf page' page (Pdf.empty ())
(* \section{Set media box} *)
let set_mediabox x y w h pdf range =
let crop_page _ page =
let set_mediabox xywhlist pdf range =
let crop_page pnum page =
let x, y, w, h = List.nth xywhlist (pnum - 1) in
{page with
Pdfpage.mediabox =
(Pdf.Array
@ -2419,16 +2421,17 @@ let setBox box minx maxx miny maxy pdf range =
process_pages set_box_page pdf range
(* \section{Cropping} *)
let crop_pdf x y w h pdf range =
let crop_page _ page =
let crop_pdf xywhlist pdf range =
let crop_page pagenum page =
{page with
Pdfpage.rest =
(Pdf.add_dict_entry
page.Pdfpage.rest
"/CropBox"
(Pdf.Array
[Pdf.Real x; Pdf.Real y;
Pdf.Real (x +. w); Pdf.Real (y +. h)]))}
(let x, y, w, h = List.nth xywhlist (pagenum - 1) in
(Pdf.Array
[Pdf.Real x; Pdf.Real y;
Pdf.Real (x +. w); Pdf.Real (y +. h)])))}
in
process_pages crop_page pdf range
@ -2552,26 +2555,28 @@ let upright ?(fast=false) range pdf =
process_pages (upright_page pdf) pdf range
(* \section{Scale page data} *)
let scale_pdf ?(fast=false) sx sy pdf range =
let scale_page _ page =
let f (xmin, ymin, xmax, ymax) =
xmin *. sx, ymin *. sy, xmax *. sx, ymax *. sy
in
let page = change_boxes f pdf page
and matrix = Pdftransform.matrix_of_op (Pdftransform.Scale ((0., 0.), sx, sy)) in
let transform_op =
Pdfops.Op_cm matrix
and resources' =
change_pattern_matrices pdf (Pdftransform.matrix_invert matrix) page.Pdfpage.resources
in
Pdfpage.prepend_operators pdf ~fast [transform_op] {page with Pdfpage.resources = resources'}
in
process_pages scale_page pdf range
let scale_pdf ?(fast=false) sxsylist pdf range =
let scale_page pnum page =
let sx, sy = List.nth sxsylist (pnum - 1) in
let f (xmin, ymin, xmax, ymax) =
xmin *. sx, ymin *. sy, xmax *. sx, ymax *. sy
in
let page = change_boxes f pdf page
and matrix = Pdftransform.matrix_of_op (Pdftransform.Scale ((0., 0.), sx, sy)) in
let transform_op =
Pdfops.Op_cm matrix
and resources' =
change_pattern_matrices pdf (Pdftransform.matrix_invert matrix) page.Pdfpage.resources
in
Pdfpage.prepend_operators pdf ~fast [transform_op] {page with Pdfpage.resources = resources'}
in
process_pages scale_page pdf range
(* Scale to fit page of size x * y *)
(* FIXME: Can we do this in terms of scale_contents - and then just fix up the boxes? For 1.8 *)
let scale_to_fit_pdf ?(fast=false) input_scale x y op pdf range =
let scale_page_to_fit _ page =
let scale_to_fit_pdf ?(fast=false) input_scale xylist op pdf range =
let scale_page_to_fit pnum page =
let x, y = List.nth xylist (pnum - 1) in
let matrix =
let (minx, miny, maxx, maxy) =
(* Use cropbox if available *)

View File

@ -346,11 +346,11 @@ val output_page_info : Pdf.t -> int list -> unit
(** True if a given page in a PDF has a given box *)
val hasbox : Pdf.t -> int -> string -> bool
(** [crop_pdf x y w h pdf range] sets the cropbox on the given pages. *)
val crop_pdf : float -> float -> float -> float -> Pdf.t -> int list -> Pdf.t
(** [crop_pdf xywhlist pdf range] sets the cropbox on the given pages. *)
val crop_pdf : (float * float * float * float) list -> Pdf.t -> int list -> Pdf.t
(** [set_mediabox x y w h pdf range] sets the cropbox on the given pages. *)
val set_mediabox : float -> float -> float -> float -> Pdf.t -> int list -> Pdf.t
(** [set_mediabox xywhlist pdf range] sets the media box on the given pages. *)
val set_mediabox : (float * float * float * float) list -> Pdf.t -> int list -> Pdf.t
(** [setBox boxname x y w h pdf range] sets the given box on the given pages. *)
val setBox : string -> float -> float -> float -> float -> Pdf.t -> int list -> Pdf.t
@ -385,16 +385,18 @@ val vflip_pdf : ?fast:bool -> Pdf.t -> int list -> Pdf.t
(** Flip the given pages horizontally *)
val hflip_pdf : ?fast:bool -> Pdf.t -> int list -> Pdf.t
(** Shift a PDF in x and y (in pts) in the given pages. *)
val shift_pdf : ?fast:bool -> float -> float -> Pdf.t -> int list -> Pdf.t
(** Shift a PDF in x and y (in pts) in the given pages. List of (x, y) pairs is
for all pages in pdf. *)
val shift_pdf : ?fast:bool -> (float * float) list -> Pdf.t -> int list -> Pdf.t
(** Scale a PDF in sx, sy in the given pages. *)
val scale_pdf : ?fast:bool -> float -> float -> Pdf.t -> int list -> Pdf.t
(** Scale a PDF in sx, sy in the given pages. List of (sx, sy) pairs is
for all pages in pdf. *)
val scale_pdf : ?fast:bool -> (float * float) list -> Pdf.t -> int list -> Pdf.t
(** [scale_to_fit_pdf 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 -> float -> float -> float -> 'a -> Pdf.t -> int list -> Pdf.t
val scale_to_fit_pdf : ?fast:bool -> 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

View File

@ -11,6 +11,9 @@ open Pdfio
let initial_file_size = ref 0
let empty = Pdf.empty ()
let emptypage = Pdfpage.blankpage Pdfpaper.a4
(* Wrap up the file reading functions to exit with code 1 when an encryption
problem occurs. This happens when object streams are in an encrypted document
and so it can't be read without the right password... The existing error
@ -738,8 +741,8 @@ let points_of_papersize p =
let c = Pdfunits.convert 0. unit Pdfunits.PdfPoint in
c w, c h
let firstpage pdf =
List.hd (Pdfpage.pages_of_pagetree pdf)
(*let firstpage pdf =
List.hd (Pdfpage.pages_of_pagetree pdf)*)
let cropbox pdf page =
match Pdf.lookup_direct pdf "/CropBox" page.Pdfpage.rest with
@ -824,100 +827,100 @@ let update_last_number pdf page unt op num = function
in
h'::t
let rec parse_units_again pdf numbers papersize more =
let rec parse_units_again pdf page numbers papersize more =
let w, h = points_of_papersize papersize in
parse_units pdf (h::w::numbers) more
parse_units pdf page (h::w::numbers) more
and parse_units pdf numbers = function
and parse_units pdf page numbers = function
| Pdfgenlex.LexName "a10portrait"::more ->
parse_units_again pdf numbers Pdfpaper.a10 more
parse_units_again pdf page numbers Pdfpaper.a10 more
| Pdfgenlex.LexName "a9portrait"::more ->
parse_units_again pdf numbers Pdfpaper.a9 more
parse_units_again pdf page numbers Pdfpaper.a9 more
| Pdfgenlex.LexName "a8portrait"::more ->
parse_units_again pdf numbers Pdfpaper.a8 more
parse_units_again pdf page numbers Pdfpaper.a8 more
| Pdfgenlex.LexName "a7portrait"::more ->
parse_units_again pdf numbers Pdfpaper.a7 more
parse_units_again pdf page numbers Pdfpaper.a7 more
| Pdfgenlex.LexName "a6portrait"::more ->
parse_units_again pdf numbers Pdfpaper.a6 more
parse_units_again pdf page numbers Pdfpaper.a6 more
| Pdfgenlex.LexName "a5portrait"::more ->
parse_units_again pdf numbers Pdfpaper.a5 more
parse_units_again pdf page numbers Pdfpaper.a5 more
| Pdfgenlex.LexName "a4portrait"::more ->
parse_units_again pdf numbers Pdfpaper.a4 more
parse_units_again pdf page numbers Pdfpaper.a4 more
| Pdfgenlex.LexName "a3portrait"::more ->
parse_units_again pdf numbers Pdfpaper.a3 more
parse_units_again pdf page numbers Pdfpaper.a3 more
| Pdfgenlex.LexName "a2portrait"::more ->
parse_units_again pdf numbers Pdfpaper.a2 more
parse_units_again pdf page numbers Pdfpaper.a2 more
| Pdfgenlex.LexName "a1portrait"::more ->
parse_units_again pdf numbers Pdfpaper.a1 more
parse_units_again pdf page numbers Pdfpaper.a1 more
| Pdfgenlex.LexName "a0portrait"::more ->
parse_units_again pdf numbers Pdfpaper.a0 more
parse_units_again pdf page numbers Pdfpaper.a0 more
| Pdfgenlex.LexName "a10landscape"::more ->
parse_units_again pdf numbers (Pdfpaper.landscape Pdfpaper.a10) more
parse_units_again pdf page numbers (Pdfpaper.landscape Pdfpaper.a10) more
| Pdfgenlex.LexName "a9landscape"::more ->
parse_units_again pdf numbers (Pdfpaper.landscape Pdfpaper.a9) more
parse_units_again pdf page numbers (Pdfpaper.landscape Pdfpaper.a9) more
| Pdfgenlex.LexName "a8landscape"::more ->
parse_units_again pdf numbers (Pdfpaper.landscape Pdfpaper.a8) more
parse_units_again pdf page numbers (Pdfpaper.landscape Pdfpaper.a8) more
| Pdfgenlex.LexName "a7landscape"::more ->
parse_units_again pdf numbers (Pdfpaper.landscape Pdfpaper.a7) more
parse_units_again pdf page numbers (Pdfpaper.landscape Pdfpaper.a7) more
| Pdfgenlex.LexName "a6landscape"::more ->
parse_units_again pdf numbers (Pdfpaper.landscape Pdfpaper.a6) more
parse_units_again pdf page numbers (Pdfpaper.landscape Pdfpaper.a6) more
| Pdfgenlex.LexName "a5landscape"::more ->
parse_units_again pdf numbers (Pdfpaper.landscape Pdfpaper.a5) more
parse_units_again pdf page numbers (Pdfpaper.landscape Pdfpaper.a5) more
| Pdfgenlex.LexName "a4landscape"::more ->
parse_units_again pdf numbers (Pdfpaper.landscape Pdfpaper.a4) more
parse_units_again pdf page numbers (Pdfpaper.landscape Pdfpaper.a4) more
| Pdfgenlex.LexName "a3landscape"::more ->
parse_units_again pdf numbers (Pdfpaper.landscape Pdfpaper.a3) more
parse_units_again pdf page numbers (Pdfpaper.landscape Pdfpaper.a3) more
| Pdfgenlex.LexName "a2landscape"::more ->
parse_units_again pdf numbers (Pdfpaper.landscape Pdfpaper.a2) more
parse_units_again pdf page numbers (Pdfpaper.landscape Pdfpaper.a2) more
| Pdfgenlex.LexName "a1landscape"::more ->
parse_units_again pdf numbers (Pdfpaper.landscape Pdfpaper.a1) more
parse_units_again pdf page numbers (Pdfpaper.landscape Pdfpaper.a1) more
| Pdfgenlex.LexName "a0landscape"::more ->
parse_units_again pdf numbers (Pdfpaper.landscape Pdfpaper.a0) more
parse_units_again pdf page numbers (Pdfpaper.landscape Pdfpaper.a0) more
| Pdfgenlex.LexName "uslegalportrait"::more ->
parse_units_again pdf numbers Pdfpaper.uslegal more
parse_units_again pdf page numbers Pdfpaper.uslegal more
| Pdfgenlex.LexName "usletterportrait"::more ->
parse_units_again pdf numbers Pdfpaper.usletter more
parse_units_again pdf page numbers Pdfpaper.usletter more
| Pdfgenlex.LexName "uslegallandscape"::more ->
parse_units_again pdf numbers (Pdfpaper.landscape Pdfpaper.uslegal) more
parse_units_again pdf page numbers (Pdfpaper.landscape Pdfpaper.uslegal) more
| Pdfgenlex.LexName "usletterlandscape"::more ->
parse_units_again pdf numbers (Pdfpaper.landscape Pdfpaper.usletter) more
parse_units_again pdf page numbers (Pdfpaper.landscape Pdfpaper.usletter) more
| Pdfgenlex.LexInt x::Pdfgenlex.LexName "mm"::more ->
parse_units pdf ((mm <| float_of_int x)::numbers) more
parse_units pdf page ((mm <| float_of_int x)::numbers) more
| Pdfgenlex.LexReal x::Pdfgenlex.LexName "mm"::more ->
parse_units pdf (mm x::numbers) more
parse_units pdf page (mm x::numbers) more
| Pdfgenlex.LexInt x::Pdfgenlex.LexName "cm"::more ->
parse_units pdf ((cm <| float_of_int x)::numbers) more
parse_units pdf page ((cm <| float_of_int x)::numbers) more
| Pdfgenlex.LexReal x::Pdfgenlex.LexName "cm"::more ->
parse_units pdf (cm x::numbers) more
parse_units pdf page (cm x::numbers) more
| Pdfgenlex.LexInt x::Pdfgenlex.LexName "in"::more ->
parse_units pdf ((inch <| float_of_int x)::numbers) more
parse_units pdf page ((inch <| float_of_int x)::numbers) more
| Pdfgenlex.LexReal x::Pdfgenlex.LexName "in"::more ->
parse_units pdf (inch x::numbers) more
parse_units pdf page (inch x::numbers) more
| Pdfgenlex.LexInt x::more ->
parse_units pdf (float_of_int x::numbers) more
parse_units pdf page (float_of_int x::numbers) more
| Pdfgenlex.LexReal x::more ->
parse_units pdf (x::numbers) more
parse_units pdf page (x::numbers) more
| Pdfgenlex.LexName "pt"::more ->
parse_units pdf numbers more
parse_units pdf page numbers more
| Pdfgenlex.LexName
( "PW" | "PH" | "CW" | "CH" | "PMINX" | "PMINY" | "PMAXX" | "PMAXY"
| "CMINX" | "CMINY" | "CMAXX" | "CMAXY") as page_characteristic::more ->
parse_units
pdf
((find_page_characteristic pdf (firstpage pdf) page_characteristic)::numbers)
page
((find_page_characteristic pdf page page_characteristic)::numbers)
more
| Pdfgenlex.LexName ("add" | "sub" | "mul" | "div") as op::
((Pdfgenlex.LexInt _ | Pdfgenlex.LexReal _ | Pdfgenlex.LexName
( "PW" | "PH" | "CW" | "CH" | "PMINX" | "PMINY" | "PMAXX" | "PMAXY"
| "CMINX" | "CMINY" | "CMAXX" | "CMAXY")) as num)::
(Pdfgenlex.LexName ("pt" | "mm" | "cm" | "in") as unt)::more ->
parse_units pdf (update_last_number pdf (firstpage pdf) unt op num numbers) more
parse_units pdf page (update_last_number pdf page unt op num numbers) more
| Pdfgenlex.LexName ("add" | "sub" | "mul" | "div") as op::
((Pdfgenlex.LexInt _ | Pdfgenlex.LexReal _ | Pdfgenlex.LexName
( "PW" | "PH" | "CW" | "CH" | "PMINX" | "PMINY" | "PMAXX" | "PMAXY"
| "CMINX" | "CMINY" | "CMAXX" | "CMAXY")) as num)::more ->
parse_units pdf (update_last_number pdf (firstpage pdf) (Pdfgenlex.LexName "pt") op num numbers) more
parse_units pdf page (update_last_number pdf page (Pdfgenlex.LexName "pt") op num numbers) more
| _ -> rev numbers
let rec space_units_inner = function
@ -931,33 +934,56 @@ let rec space_units_inner = function
let space_units s =
implode (space_units_inner (explode s))
let parse_units_string pdf s =
(*Printf.printf "Parsing string [%s]\n" s;*)
let fs = parse_units pdf [] (Pdfgenlex.lex_string <| space_units s) in
(*Printf.printf "Got numbers: %s\n"
(List.fold_left (fun x y -> x ^ " " ^ y) "" (List.map string_of_float
fs));*)
let parse_units_string pdf page s =
Printf.printf "Parsing string [%s]\n" s;
let fs = parse_units pdf page [] (Pdfgenlex.lex_string <| space_units s) in
Printf.printf "Got numbers: %s\n"
(List.fold_left (fun x y -> x ^ " " ^ y) "" (List.map string_of_float fs));
fs
let parse_rectangle pdf s =
try
match parse_units_string pdf s with
match parse_units_string pdf emptypage s with
| [x; y; w; h] -> x, y, w, h
| _ -> error "Bad rectangle specification"
with
_ -> error "Bad rectangle specification"
let parse_rectangles pdf s =
try
let pages = Pdfpage.pages_of_pagetree pdf in
let groups = List.map (fun page -> parse_units_string pdf page s) pages in
List.map
(function
| [x; y; w; h] -> (x, y, w, h)
| _ -> error "Bad rectangle specification")
groups
with
_ -> error "Bad rectangle specification"
let parse_coordinate pdf s =
try
match parse_units_string pdf s with
match parse_units_string pdf emptypage s with
| [dx; dy] -> dx, dy
| _ -> error "Bad coordinate specification"
with
_ -> error "Bad coordinate specification"
let parse_coordinates pdf s =
try
let pages = Pdfpage.pages_of_pagetree pdf in
let groups = List.map (fun page -> parse_units_string pdf page s) pages in
List.map
(function
| [dx; dy] -> (dx, dy)
| _ -> error "Bad coordinate specification")
groups
with
_ -> error "Bad coordinate specification"
let parse_single_number pdf s =
try
match parse_units_string pdf s with
match parse_units_string pdf emptypage s with
| [x] -> x
| _ -> error "Bad number Argument"
with
@ -1026,7 +1052,7 @@ let displaydoctitle b =
try setop (DisplayDocTitle (bool_of_string b)) () with
_ -> failwith "DisplayDocTitle: must use true or false"
let empty = Pdf.empty ()
let setsplitbookmarks i = setop (SplitOnBookmarks i) ()
let setstdout () = args.out <- Stdout
@ -3252,20 +3278,19 @@ let go () =
begin match args.inputs, args.out with
| (_, pagespec, _, _, _, _)::_, _ ->
let pdf = get_single_pdf (Some Crop) false in
let x, y, w, h = parse_rectangle pdf args.rectangle in
let xywhlist = parse_rectangles pdf args.rectangle in
let range = parse_pagespec pdf pagespec in
let pdf = Cpdf.crop_pdf x y w h pdf range in
let pdf = Cpdf.crop_pdf xywhlist pdf range in
write_pdf false pdf
| _ -> error "crop: bad command line"
end
| Some MediaBox ->
begin match args.inputs, args.out with
| (_, pagespec, _, _, _, _)::_, _ ->
let pdf = get_single_pdf (Some MediaBox) false in
let x, y, w, h = parse_rectangle pdf args.rectangle in
let xywhlist = parse_rectangles pdf args.rectangle in
let range = parse_pagespec pdf pagespec in
let pdf = Cpdf.set_mediabox x y w h pdf range in
let pdf = Cpdf.set_mediabox xywhlist pdf range in
write_pdf false pdf
| _ -> error "set media box: bad command line"
end
@ -3554,21 +3579,19 @@ let go () =
| Some Shift ->
let pdf = get_single_pdf args.op false in
let range = parse_pagespec pdf (get_pagespec ()) in
begin match parse_coordinate pdf args.coord with (dx, dy) ->
write_pdf false (Cpdf.shift_pdf ~fast:args.fast dx dy pdf range)
end
let dxdylist = parse_coordinates pdf args.coord in
write_pdf false (Cpdf.shift_pdf ~fast:args.fast dxdylist pdf range)
| Some Scale ->
let pdf = get_single_pdf args.op false in
let range = parse_pagespec pdf (get_pagespec ()) in
begin match parse_coordinate pdf args.coord with (sx, sy) ->
write_pdf false (Cpdf.scale_pdf ~fast:args.fast sx sy pdf range)
end
let sxsylist = parse_coordinates pdf args.coord in
write_pdf false (Cpdf.scale_pdf ~fast:args.fast sxsylist pdf range)
| Some ScaleToFit ->
let pdf = get_single_pdf args.op false in
let range = parse_pagespec pdf (get_pagespec ()) in
let x, y = parse_coordinate pdf args.coord
let xylist = parse_coordinates pdf args.coord
and scale = args.scale in
write_pdf false (Cpdf.scale_to_fit_pdf ~fast:args.fast scale x y args.op pdf range)
write_pdf false (Cpdf.scale_to_fit_pdf ~fast:args.fast scale xylist args.op pdf range)
| Some (ScaleContents scale) ->
let pdf = get_single_pdf args.op false in
let range = parse_pagespec pdf (get_pagespec ()) in