This commit is contained in:
John Whitington 2021-11-15 11:17:15 -08:00
parent b908e5f57d
commit 0b5f46044e
5 changed files with 61 additions and 35 deletions

View File

@ -1,5 +1,6 @@
2.5 (Upcoming 2022) 2.5 (Upcoming 2022)
o When adding text or graphics, may choose CYMK or Grey instead of RGB
o Append e.g DUP2 to a page range to make 1,2,3 --> 1,1,2,2,3,3 etc. o Append e.g DUP2 to a page range to make 1,2,3 --> 1,1,2,2,3,3 etc.
o The -list-fonts operation now obeys the range o The -list-fonts operation now obeys the range
o New operation -print-font-table gives (charcode, unicode, glyph name) triples o New operation -print-font-table gives (charcode, unicode, glyph name) triples

57
cpdf.ml
View File

@ -3,6 +3,11 @@ open Pdfutil
open Pdfio open Pdfio
open Cpdferror open Cpdferror
type color =
Grey of float
| RGB of float * float * float
| CYMK of float * float * float * float
let debug = ref false let debug = ref false
let xmp_template = let xmp_template =
@ -1183,6 +1188,16 @@ let metrics_rot n =
let metrics_baseline_adjustment () = !ops_baseline_adjustment let metrics_baseline_adjustment () = !ops_baseline_adjustment
let colour_op = function
| RGB (r, g, b) -> Pdfops.Op_rg (r, g, b)
| Grey g -> Pdfops.Op_g g
| CYMK (c, y, m, k) -> Pdfops.Op_k (c, y, m, k)
let colour_op_stroke = function
| RGB (r, g, b) -> Pdfops.Op_RG (r, g, b)
| Grey g -> Pdfops.Op_G g
| CYMK (c, y, m, k) -> Pdfops.Op_K (c, y, m, k)
let ops longest_w metrics x y rotate hoffset voffset outline linewidth unique_fontname unique_extgstatename colour fontsize text = let ops longest_w metrics x y rotate hoffset voffset outline linewidth unique_fontname unique_extgstatename colour fontsize text =
if metrics then if metrics then
ops_metrics := ops_metrics :=
@ -1197,9 +1212,7 @@ let ops longest_w metrics x y rotate hoffset voffset outline linewidth unique_fo
Pdfops.Op_BT; Pdfops.Op_BT;
] @ ] @
(if outline then [Pdfops.Op_w linewidth; Pdfops.Op_Tr 1] else [Pdfops.Op_Tr 0]) @ (if outline then [Pdfops.Op_w linewidth; Pdfops.Op_Tr 1] else [Pdfops.Op_Tr 0]) @
[ [colour_op colour; colour_op_stroke colour]
(match colour with (r, g, b) -> Pdfops.Op_rg (r, g, b));
(match colour with (r, g, b) -> Pdfops.Op_RG (r, g, b))]
@ @
(match unique_extgstatename with None -> [] | Some n -> [Pdfops.Op_gs n]) (match unique_extgstatename with None -> [] | Some n -> [Pdfops.Op_gs n])
@ @
@ -2850,8 +2863,8 @@ let addrectangle
[ [
Pdfops.Op_q; Pdfops.Op_q;
Pdfops.Op_BMC "/CPDFSTAMP"; Pdfops.Op_BMC "/CPDFSTAMP";
(match colour with (r, g, b) -> Pdfops.Op_rg (r, g, b)); colour_op colour;
(match colour with (r, g, b) -> Pdfops.Op_RG (r, g, b)) colour_op_stroke colour;
] ]
@ @
(if outline then [Pdfops.Op_w linewidth] else []) (if outline then [Pdfops.Op_w linewidth] else [])
@ -3061,7 +3074,7 @@ let add_border linewidth ~fast pdf =
let firstpage = hd (Pdfpage.pages_of_pagetree pdf) in let firstpage = hd (Pdfpage.pages_of_pagetree pdf) in
let _, _, w, h = Pdf.parse_rectangle firstpage.Pdfpage.mediabox in let _, _, w, h = Pdf.parse_rectangle firstpage.Pdfpage.mediabox in
addrectangle addrectangle
fast (w -. linewidth, h -. linewidth) (0., 0., 0.) true linewidth 1. (Cpdfposition.BottomLeft (linewidth /. 2.)) fast (w -. linewidth, h -. linewidth) (RGB (0., 0., 0.)) true linewidth 1. (Cpdfposition.BottomLeft (linewidth /. 2.))
false false (ilist 1 (Pdfpage.endpage pdf)) pdf false false (ilist 1 (Pdfpage.endpage pdf)) pdf
let impose ~x ~y ~fit ~columns ~rtl ~btt ~center ~margin ~spacing ~linewidth ~fast pdf = let impose ~x ~y ~fit ~columns ~rtl ~btt ~center ~margin ~spacing ~linewidth ~fast pdf =
@ -3579,7 +3592,7 @@ let create_metadata pdf =
<ops minus any text positioning or text rendering ones> <ops minus any text positioning or text rendering ones>
\end{verbatim} \end{verbatim}
*) *)
let blacktext_ops (r, g, b) pdf resources content = let blacktext_ops colour pdf resources content =
let not_text = function let not_text = function
| Pdfops.Op_Tj _ | Pdfops.Op_TJ _ | Pdfops.Op_Tj _ | Pdfops.Op_TJ _
| Pdfops.Op_' _ | Pdfops.Op_'' (_, _, _) | Pdfops.Op_' _ | Pdfops.Op_'' (_, _, _)
@ -3603,7 +3616,7 @@ let blacktext_ops (r, g, b) pdf resources content =
| Pdfops.Op_BT::more -> | Pdfops.Op_BT::more ->
incr textlevel; incr textlevel;
remove_colourops remove_colourops
(Pdfops.Op_rg (r, g, b)::Pdfops.Op_BT::prev) (colour_op colour::Pdfops.Op_BT::prev)
more more
| Pdfops.Op_ET::more -> | Pdfops.Op_ET::more ->
decr textlevel; decr textlevel;
@ -3643,25 +3656,25 @@ let blacktext_ops (r, g, b) pdf resources content =
(* Blacken a form xobject, writing it to the same object. *) (* Blacken a form xobject, writing it to the same object. *)
let blacktext (r, g, b) range pdf = let blacktext c range pdf =
let blacktext_page _ page = let blacktext_page _ page =
let content' = let content' =
blacktext_ops (r, g, b) pdf page.Pdfpage.resources page.Pdfpage.content blacktext_ops c pdf page.Pdfpage.resources page.Pdfpage.content
in in
process_xobjects pdf page (blacktext_ops (r, g, b)); process_xobjects pdf page (blacktext_ops c);
{page with Pdfpage.content = content'} {page with Pdfpage.content = content'}
in in
process_pages (ppstub blacktext_page) pdf range process_pages (ppstub blacktext_page) pdf range
(* \section{Blacken lines} *) (* \section{Blacken lines} *)
let blacklines_ops (r, g, b) pdf resources content = let blacklines_ops c pdf resources content =
let rec blacken_strokeops prev = function let rec blacken_strokeops prev = function
| [] -> rev prev | [] -> rev prev
| Pdfops.Op_CS _::t -> | Pdfops.Op_CS _::t ->
blacken_strokeops (Pdfops.Op_CS "/DeviceRGB"::prev) t blacken_strokeops (Pdfops.Op_CS "/DeviceRGB"::prev) t
| (Pdfops.Op_SC _ | Pdfops.Op_SCN _ | Pdfops.Op_SCNName _ | Pdfops.Op_G _ | (Pdfops.Op_SC _ | Pdfops.Op_SCN _ | Pdfops.Op_SCNName _ | Pdfops.Op_G _
| Pdfops.Op_RG _ | Pdfops.Op_K _)::t -> | Pdfops.Op_RG _ | Pdfops.Op_K _)::t ->
blacken_strokeops (Pdfops.Op_RG (r, g, b)::prev) t blacken_strokeops (colour_op_stroke c::prev) t
| h::t -> blacken_strokeops (h::prev) t | h::t -> blacken_strokeops (h::prev) t
and operators = and operators =
Pdfops.parse_operators pdf resources content Pdfops.parse_operators pdf resources content
@ -3669,25 +3682,25 @@ let blacklines_ops (r, g, b) pdf resources content =
let operators' = blacken_strokeops [] operators in let operators' = blacken_strokeops [] operators in
[Pdfops.stream_of_ops operators'] [Pdfops.stream_of_ops operators']
let blacklines (r, g, b) range pdf = let blacklines c range pdf =
let blacklines_page _ page = let blacklines_page _ page =
let content' = let content' =
blacklines_ops (r, g, b) pdf page.Pdfpage.resources page.Pdfpage.content blacklines_ops c pdf page.Pdfpage.resources page.Pdfpage.content
in in
process_xobjects pdf page (blacklines_ops (r, g, b)); process_xobjects pdf page (blacklines_ops c);
{page with Pdfpage.content = content'} {page with Pdfpage.content = content'}
in in
process_pages (ppstub blacklines_page) pdf range process_pages (ppstub blacklines_page) pdf range
(* \section{Blacken Fills} *) (* \section{Blacken Fills} *)
let blackfills_ops (r, g, b) pdf resources content = let blackfills_ops c pdf resources content =
let rec blacken_fillops prev = function let rec blacken_fillops prev = function
| [] -> rev prev | [] -> rev prev
| Pdfops.Op_cs _::t -> | Pdfops.Op_cs _::t ->
blacken_fillops (Pdfops.Op_cs "/DeviceRGB"::prev) t blacken_fillops (Pdfops.Op_cs "/DeviceRGB"::prev) t
| (Pdfops.Op_sc _ | Pdfops.Op_scn _ | Pdfops.Op_scnName _ | Pdfops.Op_g _ | (Pdfops.Op_sc _ | Pdfops.Op_scn _ | Pdfops.Op_scnName _ | Pdfops.Op_g _
| Pdfops.Op_rg _ | Pdfops.Op_k _)::t -> | Pdfops.Op_rg _ | Pdfops.Op_k _)::t ->
blacken_fillops (Pdfops.Op_rg (r, g, b)::prev) t blacken_fillops (colour_op c::prev) t
| h::t -> blacken_fillops (h::prev) t | h::t -> blacken_fillops (h::prev) t
and operators = and operators =
Pdfops.parse_operators pdf resources content Pdfops.parse_operators pdf resources content
@ -3695,12 +3708,12 @@ let blackfills_ops (r, g, b) pdf resources content =
let operators' = blacken_fillops [] operators in let operators' = blacken_fillops [] operators in
[Pdfops.stream_of_ops operators'] [Pdfops.stream_of_ops operators']
let blackfills (r, g, b) range pdf = let blackfills c range pdf =
let blackfills_page _ page = let blackfills_page _ page =
let content' = let content' =
blackfills_ops (r, g, b) pdf page.Pdfpage.resources page.Pdfpage.content blackfills_ops c pdf page.Pdfpage.resources page.Pdfpage.content
in in
process_xobjects pdf page (blackfills_ops (r, g, b)); process_xobjects pdf page (blackfills_ops c);
{page with Pdfpage.content = content'} {page with Pdfpage.content = content'}
in in
process_pages (ppstub blackfills_page) pdf range process_pages (ppstub blackfills_page) pdf range
@ -4857,3 +4870,5 @@ let extract_images path_to_p2p path_to_im encoding dedup dedup_per_page pdf rang
iter (extract_images_form_xobject path_to_p2p path_to_im encoding dedup dedup_per_page pdf serial stem pnum) forms) iter (extract_images_form_xobject path_to_p2p path_to_im encoding dedup dedup_per_page pdf serial stem pnum) forms)
pages pages
(indx pages) (indx pages)

View File

@ -9,6 +9,11 @@ all - the PDF string is output as-is. [UTF8] converts loslessly to UTF8.
correspond to 7 bit ASCII. *) correspond to 7 bit ASCII. *)
type encoding = Raw | UTF8 | Stripped type encoding = Raw | UTF8 | Stripped
type color =
Grey of float
| RGB of float * float * float
| CYMK of float * float * float * float
(** {2 Debug} *) (** {2 Debug} *)
(** Debug: Print out a PDF in readable form to the terminal *) (** Debug: Print out a PDF in readable form to the terminal *)
@ -178,7 +183,7 @@ val addtexts :
bool -> (* embed font *) bool -> (* embed font *)
int -> (* bates number *) int -> (* bates number *)
int option -> (* bates padding width *) int option -> (* bates padding width *)
float * float * float -> (*colour*) color -> (*colour*)
Cpdfposition.position -> (*position*) Cpdfposition.position -> (*position*)
float -> (*linespacing*) float -> (*linespacing*)
float -> (*fontsize*) float -> (*fontsize*)
@ -201,7 +206,7 @@ val addtexts :
val addrectangle : val addrectangle :
bool -> bool ->
float * float -> float * float ->
float * float * float -> color ->
bool -> bool ->
float -> float ->
float -> float ->
@ -346,13 +351,13 @@ val add_page_labels :
val thinlines : int list -> float -> Pdf.t -> Pdf.t val thinlines : int list -> float -> Pdf.t -> Pdf.t
(** Make all text on certain pages black. *) (** Make all text on certain pages black. *)
val blacktext : float * float * float -> int list -> Pdf.t -> Pdf.t val blacktext : color -> int list -> Pdf.t -> Pdf.t
(** Make all lines on certain pages black. *) (** Make all lines on certain pages black. *)
val blacklines : float * float * float -> int list -> Pdf.t -> Pdf.t val blacklines : color -> int list -> Pdf.t -> Pdf.t
(** Make all fills on certain pages black. *) (** Make all fills on certain pages black. *)
val blackfills : float * float * float -> int list -> Pdf.t -> Pdf.t val blackfills : color -> int list -> Pdf.t -> Pdf.t
(** Remove images from a PDF, optionally adding crossed boxes. *) (** Remove images from a PDF, optionally adding crossed boxes. *)
val draft : string option -> bool -> int list -> Pdf.t -> Pdf.t val draft : string option -> bool -> int list -> Pdf.t -> Pdf.t
@ -419,3 +424,5 @@ val name_of_spec : encoding ->
val extract_images : string -> val extract_images : string ->
string -> string ->
encoding -> bool -> bool -> Pdf.t -> int list -> string -> unit encoding -> bool -> bool -> Pdf.t -> int list -> string -> unit

View File

@ -377,7 +377,7 @@ type args =
mutable font : font; mutable font : font;
mutable fontname : string; mutable fontname : string;
mutable fontsize : float; mutable fontsize : float;
mutable color : float * float * float; mutable color : Cpdf.color;
mutable opacity : float; mutable opacity : float;
mutable position : Cpdfposition.position; mutable position : Cpdfposition.position;
mutable underneath : bool; mutable underneath : bool;
@ -493,7 +493,7 @@ let args =
font = StandardFont Pdftext.TimesRoman; font = StandardFont Pdftext.TimesRoman;
fontname = "Times-Roman"; fontname = "Times-Roman";
fontsize = 12.; fontsize = 12.;
color = 0., 0., 0.; color = Cpdf.RGB (0., 0., 0.);
opacity = 1.; opacity = 1.;
position = Cpdfposition.TopLeft 100.; position = Cpdfposition.TopLeft 100.;
underneath = false; underneath = false;
@ -609,7 +609,7 @@ let reset_arguments () =
args.font <- StandardFont Pdftext.TimesRoman; args.font <- StandardFont Pdftext.TimesRoman;
args.fontname <- "Times-Roman"; args.fontname <- "Times-Roman";
args.fontsize <- 12.; args.fontsize <- 12.;
args.color <- 0., 0., 0.; args.color <- Cpdf.RGB (0., 0., 0.);
args.opacity <- 1.; args.opacity <- 1.;
args.position <- Cpdfposition.TopLeft 100.; args.position <- Cpdfposition.TopLeft 100.;
args.underneath <- false; args.underneath <- false;
@ -1050,11 +1050,11 @@ let setaddtext s =
let parse_color s = let parse_color s =
match String.lowercase s with match String.lowercase s with
| "white" -> 1., 1., 1. | "white" -> Cpdf.RGB (1., 1., 1.)
| "black" -> 0., 0., 0. | "black" -> Cpdf.RGB (0., 0., 0.)
| "red" -> 1., 0., 0. | "red" -> Cpdf.RGB (1., 0., 0.)
| "green" -> 0., 1., 0. | "green" -> Cpdf.RGB (0., 1., 0.)
| "blue" -> 0., 0., 1. | "blue" -> Cpdf.RGB (0., 0., 1.)
| _ -> | _ ->
let getnum = function let getnum = function
| Pdfgenlex.LexInt i -> float i | Pdfgenlex.LexInt i -> float i
@ -1062,7 +1062,9 @@ let parse_color s =
| _ -> error "Bad color" | _ -> error "Bad color"
in in
match Pdfgenlex.lex_string s with match Pdfgenlex.lex_string s with
| [a;b;c] -> getnum a, getnum b, getnum c | [g] -> Cpdf.Grey (getnum g)
| [r;g;b] -> Cpdf.RGB (getnum r, getnum g, getnum b)
| [c; y; m; k] -> Cpdf.CYMK (getnum c, getnum y, getnum m, getnum k)
| _ -> error "Bad color" | _ -> error "Bad color"
let setcolor s = let setcolor s =

View File

@ -8,6 +8,7 @@
%Document new text lookup for -add-text and new -raw mode %Document new text lookup for -add-text and new -raw mode
%Document -print-font-table %Document -print-font-table
%Document NOT and DUP page ranges %Document NOT and DUP page ranges
%Document new colourspaces for -add-text -add-rectangle
\documentclass{book} \documentclass{book}
% Edit here to produce cpdfmanual.pdf, cpdflibmanual.pdf, pycpdfmanual.pdf etc. % Edit here to produce cpdfmanual.pdf, cpdflibmanual.pdf, pycpdfmanual.pdf etc.
\usepackage{comment}\excludecomment{cpdflib}\excludecomment{pycpdflib} \usepackage{comment}\excludecomment{cpdflib}\excludecomment{pycpdflib}