keithmarshall pushed a commit to branch dev-gropdf-boxes in repository groff.
commit 253d01c19256f3e6fa566f805d4757c13f9a78e4 Author: Bertrand Garrigues <bertrand.garrig...@laposte.net> AuthorDate: Sat Apr 3 01:35:46 2021 +0200 Add Deri James'extension to gropdf to draw boxes and sboxes macros. (see https://lists.gnu.org/archive/html/groff/2021-04/msg00000.html) --- Makefile.am | 1 + contrib/sboxes/msboxes.ms | 287 +++++++++++++++++++++++++++++++++++++++++++ contrib/sboxes/sboxes.am | 39 ++++++ contrib/sboxes/sboxes.tmac | 116 +++++++++++++++++ src/devices/gropdf/gropdf.pl | 140 +++++++++++++++++++++ 5 files changed, 583 insertions(+) diff --git a/Makefile.am b/Makefile.am index aec1bae..1a3292f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -659,6 +659,7 @@ include $(top_srcdir)/contrib/mom/mom.am include $(top_srcdir)/contrib/pdfmark/pdfmark.am include $(top_srcdir)/contrib/pic2graph/pic2graph.am include $(top_srcdir)/contrib/rfc1345/rfc1345.am +include $(top_srcdir)/contrib/sboxes/sboxes.am include $(top_srcdir)/doc/doc.am include $(top_srcdir)/font/devX100/devX100.am include $(top_srcdir)/font/devX100-12/devX100-12.am diff --git a/contrib/sboxes/msboxes.ms b/contrib/sboxes/msboxes.ms new file mode 100644 index 0000000..e715c7e --- /dev/null +++ b/contrib/sboxes/msboxes.ms @@ -0,0 +1,287 @@ +.nr LL 17c +.nr LT \n[LL] +.nr PO 2c +.nr PS 11 +.nr VS 13 +.nr PI 3.5n +.nr HM 2c +.nr FM 2c +.nr QI 7n +.\" .nr PD 7p +.ll 17c +.po 2c +.\" .RP no +.ND March 2021 +.EH '%''March 2021' +.EF '''' +.OH 'Using PDF boxes with the \f[I]ms\f[] macros''%' +.OF '''' +.TL +Using PDF boxes with the \f[I]ms\f[] macros +.AU +Deri James +.AI +d...@chuzzlewit.myzen.co.uk +.\" .AB no +.ds FAM H +.LP +A recent extension to the Groff PDF driver allows coloured rectangles to be +created beneath any output created by groff. The extension is a new "\eX'pdf:'" +command (with a convenience command +.B pdfbackground +with the same parameters):- +.QS +.BoxStart SHADED cornsilk OUTLINED brown INDENT 2n WEIGHT 1p +\M[floralwhite]\c +.pdfbackground pagefill +\M[]\c +.B +\eX'pdf: background +.BI +cmd left top right bottom weight' +.br +.B .pdfbackground +.BI +cmd left top right bottom weight' +.LP +Where:- +.IP cmd 7n +Can be any of "page|fill|box" in combination. So "pagefill" would draw a +rectangle which covers whole current page size (in which case the rest of the +parameters can be omitted because the box dimensions are taken from the +current media size). "boxfill", on the other hand, requires the given +dimensions to place the box. Including "fill" in the command will make the +rectangle filled with the current background colour "\eM[colour]" and including +"box" will give the rectangle a border in the current stroke colour +"\em[colour]". +.sp \n[PD]u +The "cmd" may also be "off", on its own, which will terminate drawing the +current box. If you have specified a page colour +with +.B ".pdfbackground pagefill +it is always the first box in the stack, and if +you specify it again it will replace the first entry. Be aware that the +pagefill box renders the page opaque so tools which "watermark" pdf pages are +unlikely to be successful. To return the background to transparent do a +.B ".pdfbackground off +with no other boxes open +.sp \n[PD]u +Finally the command may be "footnote" followed by a new value for "bottom" +which will be used for all current boxes, just for the current page. This is +to allow room for footnotes which grow during the page.\m[red]\**\m[] +.FS +If the value is negative it is used as an offset from the bottom of the page. +.FE +.LP +.IP left +.IP top +.IP right +.IP bottom 7n +Are the coordinates of the box. The "top" and "bottom" coordinates are +the minimum and maximum for the box, since the actual start of the +box is the vertical position of groff when you issue the command and the bottom of +the box is the point where you turn the box "off". The top and bottom +coordinates are only used if the box drawing extends onto the next page, so, +ordinarily they would be set to the header and footer margins. +.IP weight 7n +If "box" is included in the command then this parameter provides the line width +for the box border. +.BoxStop +.QE +More convenience can be gained by including -msboxes on the groff command line +which includes the macros "BoxStart" and "BoxStop". +.QS +.BoxStart SHADED cornsilk OUTLINED brown INDENT 2n WEIGHT 1p +.BoxStart SHADED cornsilk3 INDENT 2p +.B .BoxStart +.R SHADED +.I colour +.R OUTLINED +.I colour +.R INDENT +.I size +.R WEIGHT +.I size +.BoxStop +.LP +Where SHADED gives the fill colour and OUTLINED the border colour. Omit either +to get a borderless filled box, or just a border with no fill. WEIGHT is used +if the box is OUTLINED. +.LP +INDENT is a value which leaves a gap between the border and the contents inside +the box. +.BoxStop +.QE +Boxes can stacked, so you can start a box within another box, usually the +later boxes would be smaller than the containing box, but this is not +enforced. If using the BoxStart macro the left position is the current indent +minus the INDENT in the command, and the right position is the left position +(calculated above) plus the current line length and twice the indent. +The macro definition of .BoxStart above has been given a box without borders +and a 2p indent. +.QS +.BoxStart SHADED cornsilk OUTLINED brown INDENT 2n WEIGHT 1p +.BoxStart SHADED cornsilk3 INDENT 2p +.B .BoxStop +.BoxStop +.LP +There are no parameters, it closes the last box at the current vertical +position, after adding the Indent spacing. +.BoxStop +.QE +This macro package has one further feature, it attempts to hook into the ms +package to receive notifications when footnotes are growing, so that it can +close boxes before the footnotes are printed. If there are footnotes on a page +it will close current boxes 2p above the footnote separator, this probably +will not match the indent amount requested. +.LP +The above was produced by the following code. +.ds FAM C +.nr PS 9 +.nr VS 10 +.nf +.LP +.BoxStart SHADED white OUTLINED brown INDENT 2n WEIGHT 1p +.nf +\&.nr LL 17c +\&.nr LT \en[LL] +\&.nr PO 2c +\&.nr PS 11 +\&.nr VS 13 +\&.nr PI 3.5n +\&.nr HM 2c +\&.nr FM 2c +\&.nr QI 7n +\&.\" .nr PD 7p +\&.ll 17c +\&.po 2c +\&.\" .RP no +\&.ND March 2021 +\&.EH '%''March 2021' +\&.EF '''' +\&.OH 'Using PDF boxes with the \ef[I]ms\ef[] macros''%' +\&.OF '''' +\&.TL +Using PDF boxes with the \ef[I]ms\ef[] macros +\&.AU +Deri James +\&.AI +d...@chuzzlewit.myzen.co.uk +\&.\" .AB no +\&.ds FAM H +\&.LP +A recent extension to the Groff PDF driver allows coloured rectangles to be +created beneath any output created by groff. The extension is a new "\eX'pdf:'" +command (with a convenience command +\&.B pdfbackground +with the same parameters):- +\&.QS +\&.BoxStart SHADED cornsilk OUTLINED brown INDENT 2n WEIGHT 1p +\eM[floralwhite]\ec +\&.pdfbackground pagefill +\eM[]\ec +\&.B +\eX'pdf: background +\&.BI +cmd left top right bottom weight' +\&.br +\&.B .pdfbackground +\&.BI +cmd left top right bottom weight' +\&.LP +Where:- +\&.IP cmd 7n +Can be any of "page|fill|box" in combination. So "pagefill" would draw a +rectangle which covers whole current page size (in which case the rest of the +parameters can be omitted because the box dimensions are taken from the +current media size). "boxfill", on the other hand, requires the given +dimensions to place the box. Including "fill" in the command will make the +rectangle filled with the current background colour "\eM[colour]" and including +"box" will give the rectangle a border in the current stroke colour +"\em[colour]". +\&.sp \n[PD]u +The "cmd" may also be "off", on its own, which will terminate drawing the +current box. If you have specified a page colour +with +\&.B ".pdfbackground pagefill +it is always the first box in the stack, and if +you specify it again it will replace the first entry. Be aware that the +pagefill box renders the page opaque so tools which "watermark" pdf pages are +unlikely to be successful. To return the background to transparent do a +\&.B ".pdfbackground off +with no other boxes open +\&.sp \n[PD]u +Finally the command may be "footnote" followed by a new value for "bottom" +which will be used for all current boxes, just for the current page. This is +to allow room for footnotes which grow during the page.\m[red]\e**\**\m[] +.FS +This is just a long footnote. Its purpose is only to check that the bottom of +the box on this page has been adjusted because of the size of the footnote. +.FE +\&.FS +If the value is negative it is used as an offset from the bottom of the page. +\&.FE +\&.LP +\&.IP left +\&.IP top +\&.IP right +\&.IP bottom 7n +Are the coordinates of the box. The "top" and "bottom" coordinates are +the minimum and maximum for the box, since the actual start of the +box is the vertical position of groff when you issue the command and the bottom of +the box is the point where you turn the box "off". The top and bottom +coordinates are only used if the box drawing extends onto the next page, so, +ordinarily they would be set to the header and footer margins. +\&.IP weight 7n +If "box" is included in the command then this parameter provides the line width +for the box border. +\&.BoxStop +\&.QE +More convenience can be gained by including -msboxes on the groff command line +which includes the macros "BoxStart" and "BoxStop". +\&.QS +\&.BoxStart SHADED cornsilk OUTLINED brown INDENT 2n WEIGHT 1p +\&.BoxStart SHADED cornsilk3 INDENT 2p +\&.B .BoxStart +\&.R SHADED +\&.I colour +\&.R OUTLINED +\&.I colour +\&.R INDENT +\&.I size +\&.R WEIGHT +\&.I size +\&.BoxStop +\&.LP +Where SHADED gives the fill colour and OUTLINED the border colour. Omit either +to get a borderless filled box, or just a border with no fill. WEIGHT is used +if the box is OUTLINED. +\&.LP +INDENT is a value which leaves a gap between the border and the contents inside +the box. +\&.BoxStop +\&.QE +Boxes can stacked, so you can start a box within another box, usually the +later boxes would be smaller than the containing box, but this is not +enforced. If using the BoxStart macro the left position is the current indent +minus the INDENT in the command, and the right position is the left position +(calculated above) plus the current line length and twice the indent. +The macro definition of .BoxStart above has been given a box without borders +and a 2p indent. +\&.QS +\&.BoxStart SHADED cornsilk OUTLINED brown INDENT 2n WEIGHT 1p +\&.BoxStart SHADED cornsilk3 INDENT 2p +\&.B .BoxStop +\&.BoxStop +\&.LP +There are no parameters, it closes the last box at the current vertical +position, after adding the Indent spacing. +\&.BoxStop +\&.QE +This macro package has one further feature, it attempts to hook into the ms +package to receive notifications when footnotes are growing, so that it can +close boxes before the footnotes are printed. If there are footnotes on a page +it will close current boxes 2p above the footnote separator, this probably +will not match the indent amount requested. +\&.LP +.BoxStop diff --git a/contrib/sboxes/sboxes.am b/contrib/sboxes/sboxes.am new file mode 100644 index 0000000..e362467 --- /dev/null +++ b/contrib/sboxes/sboxes.am @@ -0,0 +1,39 @@ +sboxes_srcdir = $(top_srcdir)/contrib/sboxes +SBOXES_FLAGS = -M$(sboxes_srcdir) -ms -msboxes -Tpdf +# Files installed in $(tmacdir). +SBOXES_NORMAL_FILES = contrib/sboxes/sboxes.tmac +sboxestmacdir = $(tmacdir) +dist_sboxestmac_DATA = $(SBOXES_NORMAL_FILES) + +# Files installed in $(examplesdir)/sboxes. SBOXES_EXAMPLEFILES are located +# in the source tree, while SBOXESPROCESSEDEXAMPLEFILES are generated in +# the build tree. +SBOXES_EXAMPLEFILES= contrib/sboxes/msboxes.ms +if BUILD_EXAMPLES +sboxesexampledir = $(exampledir)/sboxes +dist_sboxesexample_DATA = $(SBOXES_EXAMPLEFILES) +SBOXES_PROCESSEDEXAMPLEFILES = contrib/sboxes/msboxes.pdf +sboxesprocessedexampledir = $(exampledir)/sboxes +nodist_sboxesprocessedexample_DATA = $(SBOXES_PROCESSEDEXAMPLEFILES) +else +EXTRA_DIST += $(SBOXES_EXAMPLEFILES) +endif + +$(SBOXES_PROCESSEDEXAMPLEFILES): $(SBOXES_NORMAL_FILES) \ + groff troff gropdf font/devpdf/build_font_files + +contrib/sboxes/msboxes.pdf: + mkdir -p $(top_builddir)/contrib/sboxes/ + $(top_builddir)/groff $(SBOXES_FLAGS) $(sboxes_srcdir)/msboxes.ms > $@ + +uninstall_groffdirs: uninstall_sboxes +uninstall_sboxes: + if test -d $(DESTDIR)$(exampledir)/sboxes; then \ + rmdir $(DESTDIR)$(exampledir)/sboxes; \ + fi + +# Local Variables: +# fill-column: 72 +# mode: makefile-automake +# End: +# vim: set autoindent filetype=automake textwidth=72: diff --git a/contrib/sboxes/sboxes.tmac b/contrib/sboxes/sboxes.tmac new file mode 100644 index 0000000..6b73027 --- /dev/null +++ b/contrib/sboxes/sboxes.tmac @@ -0,0 +1,116 @@ +.ig + +sboxes.tmac + +Copyright (C) 1989-2021 Free Software Foundation, Inc. + Written by Deri James (d...@chuzzlewit.myzen.co.uk) + +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +.. +.if !\n(.g \ +. ab groff ms macros require groff extensions; aborting +. +.if \n(.C \ +. ab groff ms macros do not work in compatibility mode; aborting +. +.\" See if already loaded. +.if r GSBOX .nx +.nr GSBOX 1 +.nr bx@stack 0 +. +.de pdfbackground +.device pdf: background \\$* +.. +.\" Link into ms macros to trap footnote growth +.am fn@print-sep +.nr bx@pb \\n[nl]u-2p +.nop \!x X pdf: background footnote \\n[bx@pb]z +.rr bx@pb +.. +.\" Has PD been actioned? +.am par*start +.nr bx@PD \\n[PD] +.. +. +.de BoxStart +. fl +. nr bx@stack \\n[bx@stack]+1u +. nr bx@shad 0 +. nr bx@outl 0 +. nr bx@ind 1P +. ds bx@wt 0 +. ds bx@type "\" +. while \\n[.$] \{\ +. ie 'SHADED'\\$1' \{\ +. nop \\M[\\$2]\c +. nr bx@shad 1 +. as bx@type "fill\" +. shift 2 +. \} +. el \{\ +. ie 'OUTLINED'\\$1' \{\ +. nop \\m[\\$2]\c +. nr bx@outl 1 +. as bx@type "box\" +. shift 2 +. \} +. el \{\ +. ie 'WEIGHT'\\$1' \{\ +. ds bx@wt \\$2 +. shift 2 +. \} +. el \{\ +. ie 'INDENT'\\$1' \{\ +. nr bx@ind \\$2 +. shift 2 +. \} +. el \{\ +. tm Unknown Token \\$1 +. shift +. \} +. \} +. \} +. \} +. \} +. +. if '\\*[bx@type]'' .ds bx@type "fill" +. nr bx@l \\n[\\n[.ev]:li]s+\\n[.o]s-\\n[bx@ind]u +. nr bx@r \\n[bx@l]u+\\n[.l]-\\n[\\n[.ev]:li]+(\\n[bx@ind]u*2u) +. nr bx@gap \\n[.v]-\\n[.ps]+\\*[bx@wt] +. nr bx@bot \\n[.p]u-\\n[FM]u+\\n[bx@ind]u+\\n[.ps]u +. nr bx@top \\n[HM]-\\n[bx@ind]u+\\n[bx@gap]u +. ne \\n[bx@ind]u+2v+\\*[bx@wt] +. sp -(2v-(\\n[bx@PD]u*2u))u +. pdfbackground \\*[bx@type] \\n[bx@l]z \\n[bx@top]z \\n[bx@r]z \\n[bx@bot]z \\*[bx@wt] \\n[nl]z +. sp (\\n[bx@ind]u-1v)u +. if (\\n[bx@shad]=1) .nop \\M[]\c +. if (\\n[bx@outl]=1) .nop \\m[]\c +. ds bx@ind\\n[bx@stack] \\n[bx@ind] +. rr bx@shad bx@outl bx@ind bx@bot bx@top bx@l bx@r +. rm wt type +. sp -(\\n[bx@gap]u) +. nr bx@PD 0 +.. +.de BoxStop +. sp \\*[bx@ind\\n[bx@stack]]u-\\n[.psr]u +. pdfbackground off +. nr bx@stack \\n[bx@stack]-1u +.. +.\" Local Variables: +.\" mode: nroff +.\" fill-column: 72 +.\" End: +.\" vim: set filetype=groff textwidth=72: diff --git a/src/devices/gropdf/gropdf.pl b/src/devices/gropdf/gropdf.pl index ec045a9..da2f6dd 100644 --- a/src/devices/gropdf/gropdf.pl +++ b/src/devices/gropdf/gropdf.pl @@ -121,6 +121,7 @@ my $wt=-1; my $thislev=1; my $mark=undef; my $suspendmark=undef; +my $boxmax=0; @@ -137,6 +138,8 @@ my $transition={PAGE => {Type => '/Trans', S => '', D => 1, Dm => '/H', M => '/I BLOCK => {Type => '/Trans', S => '', D => 1, Dm => '/H', M => '/I', Di => 0, SS => 1.0, B => 0}}; my $firstpause=0; my $present=0; +my @bgstack; # Stack of background boxes +my $bgbox=''; # Draw commands for boxes on this page $noslide=1 if exists($ENV{GROPDF_NOSLIDE}) and $ENV{GROPDF_NOSLIDE}; @@ -364,6 +367,32 @@ if ($cpageno > 0) @{$cpage->{Annots}}=@PageAnnots; } + if ($#bgstack > -1 or $bgbox) + { + my $box="q 1 0 0 1 0 0 cm "; + + foreach my $bg (@bgstack) + { + # 0=$bgtype # 1=stroke 2=fill. 4=page + # 1=$strkcol + # 2=$fillcol + # 3=(Left,Top,Right,bottom,LineWeight) + # 4=Start ypos + # 5=Endypos + # 6=Line Weight + + my $pg=$bg->[3] || \@mediabox; + + $bg->[5]=$pg->[3]; # box is continueing to next page + $box.=DrawBox($bg); + $bg->[4]=$pg->[1]; # will continue from page top + } + + $stream=$box.$bgbox."Q\n".$stream; + $bgbox=''; + } + + $boxmax=0; PutObj($cpageno); OutStream($cpageno+1); } @@ -1228,6 +1257,74 @@ sub do_x $present=1; } + elsif (lc($xprm[1]) eq 'background') + { + splice(@xprm,0,2); + my $type=shift(@xprm); + + print STDERR "BX=$_ : $ypos\n"; + if (lc($type) eq 'off') + { + my $sptr=$#bgstack; + if ($sptr > -1) + { + if ($sptr == 0 and $bgstack[0]->[0] & 4) + { + pop(@bgstack); + } + else + { + $bgstack[$sptr]->[5]=GraphY($ypos); + $bgbox=DrawBox(pop(@bgstack)).$bgbox; + } + } + } + elsif (lc($type) eq 'footnote') + { + my $t=GetPoints($xprm[0]); + $boxmax=($t<0)?abs($t):GraphY($t); + } + else + { + my $bgtype=0; + + foreach (@xprm) + { + $_=GetPoints($_); + } + + $bgtype|=2 if $type=~m/box/i; + $bgtype|=1 if $type=~m/fill/i; + $bgtype|=4 if $type=~m/page/i; + $bgtype|=1 if $bgtype==4; + my $bgwt=$xprm[4]; + $bgwt=$xprm[0] if !defined($bgwt) and $#xprm == 0; + my (@bg)=(@xprm); + my $bg=\@bg; + + if (!defined($bg[3]) or $bgtype & 4) + { + $bg=undef; + } + else + { + FixRect($bg); + } + + if ($bgtype) + { + if ($bgtype & 4) + { + shift(@bgstack) if $#bgstack >= 0 and $bgstack[0]->[0] & 4; + unshift(@bgstack,[$bgtype,$strkcol,$fillcol,$bg,GraphY($ypos),GraphY($bg[3]||0),$bgwt || 0.4]); + } + else + { + push(@bgstack,[$bgtype,$strkcol,$fillcol,$bg,GraphY($ypos),GraphY($bg[3]||0),$bgwt || 0.4]); + } + } + } + } } elsif (lc(substr($xprm[0],0,9)) eq 'papersize') { @@ -2541,6 +2638,32 @@ sub NewPage @{$cpage->{Annots}}=@PageAnnots; } + if ($#bgstack > -1 or $bgbox) + { + my $box="q 1 0 0 1 0 0 cm "; + + foreach my $bg (@bgstack) + { + # 0=$bgtype # 1=stroke 2=fill. 4=page + # 1=$strkcol + # 2=$fillcol + # 3=(Left,Top,Right,bottom,LineWeight) + # 4=Start ypos + # 5=Endypos + # 6=Line Weight + + my $pg=$bg->[3] || \@defaultmb; + + $bg->[5]=$pg->[3]; # box is continueing to next page + $box.=DrawBox($bg); + $bg->[4]=$pg->[1]; # will continue from page top + } + + $stream=$box.$bgbox."Q\n".$stream; + $bgbox=''; + $boxmax=0; + } + PutObj($cpageno); OutStream($cpageno+1); } @@ -2570,6 +2693,23 @@ sub NewPage # @mediabox=@defaultmb; } +sub DrawBox +{ + my $bg=shift; + my $res=''; + my $pg=$bg->[3] || \@mediabox; + $bg->[4]=$pg->[1], $bg->[5]=$pg->[3] if $bg->[0] & 4; + my $bot=$bg->[5]; + $bot=$boxmax if $boxmax > $bot; + my $wid=$pg->[2]-$pg->[0]; + my $dep=$bot-$bg->[4]; + + $res="$bg->[1] $bg->[2] $bg->[6] w\n"; + $res.="$pg->[0] $bg->[4] $wid $dep re f " if $bg->[0] & 1; + $res.="$pg->[0] $bg->[4] $wid $dep re s " if $bg->[0] & 2; + return("$res\n"); +} + sub MakeXO { $stream.="%mode=$mode\n"; _______________________________________________ Groff-commit mailing list Groff-commit@gnu.org https://lists.gnu.org/mailman/listinfo/groff-commit