deri pushed a commit to branch master in repository groff. commit f2a92911c552c3995c010f8beb9b89de3612e95a Author: Deri James <d...@chuzzlewit.myzen.co.uk> Date: Thu Mar 1 15:16:11 2018 +0000
Add page transitions to pdfs created with gropdf. * src/devices/gropdf.pl: Handle new '\X' commands to support page transitions in presentation mode pdfs. These commands are a subset of the commands used in present.tmac allowing slideshows to be directly produced from -Tpdf without using postscript -> gpresent.pl -> ghostscript. * tmac/pdf.tmac: New macros '.pdfpause' and '.pdftransition' to support page transitions. * src/devices/gropdf.1.man: Document the '\X' commands supported. --- ChangeLog | 15 +++ src/devices/gropdf/gropdf.1.man | 240 ++++++++++++++++++++++++++++++++++++++++ src/devices/gropdf/gropdf.pl | 211 ++++++++++++++++++++++++++++++----- tmac/pdf.tmac | 8 +- 4 files changed, 447 insertions(+), 27 deletions(-) diff --git a/ChangeLog b/ChangeLog index 337bf08..1506e57 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2018-03-01 Deri James <d...@chuzzlewit.myzen.co.uk> + + Add page transitions to pdfs created with gropdf. + + * src/devices/gropdf.pl: Handle new '\X' commands to support page + transitions in presentation mode pdfs. These commands are a subset + of the commands used in present.tmac allowing slideshows to be + directly produced from -Tpdf without using postscript -> gpresent.pl + -> ghostscript. + + * tmac/pdf.tmac: New macros '.pdfpause' and '.pdftransition' to + support page transitions. + + * src/devices/gropdf.1.man: Document the '\X' commands supported. + 2018-03-01 Werner LEMBERG <w...@gnu.org> Use $(AM_V_GEN) and $(AM_V_P) to silence even more file generation. diff --git a/src/devices/gropdf/gropdf.1.man b/src/devices/gropdf/gropdf.1.man index 0ff132e..e07946d 100644 --- a/src/devices/gropdf/gropdf.1.man +++ b/src/devices/gropdf/gropdf.1.man @@ -695,8 +695,54 @@ A subset of these macros are installed automatically when you use so you should not need to use \[oq]\-m pdfmark\[cq] for using most of the PDF functionality. . +.LP +.B gropdf +also supports a subset of the commands introduced in present.tmac. +Specifically it supports:- +.IP +PAUSE +.br +BLOCKS +.br +BLOCKE . .LP +Which allows you to create presentation type PDFs. Many of the other +commands are already available in other macro packages. +.LP +These commands are implemented with +.B groff +X commands:- +.LP +.TP +.BI "\[rs]X'ps: exec %%%%PAUSE" +The section before this is treated as a block and is introduced using the +current BLOCK transition setting (see \[oq]pdf: transition\[cq] below). This command +can be introduced using the macro +.BR .pdfpause . +.TP +.B "\[rs]X'ps: exec %%%%BEGINONCE" +Any text following this command (up to %%%%ENDONCE) is shown only once, +the next %%%%PAUSE will remove it. If producing a non presentation pdf, i.e. +ignoring the pauses, see GROPDF_NOSLIDE below, this text is ignored. +.LP +.TP +.B "\[rs]X'ps: exec %%%%ENDONCE" +This terminates the block defined by %%%%BEGINONCE. This pair of commands +is what implements the .BLOCKS Once/.BLOCKE commands in present.tmac. +.LP +The +.B mom +macro set already has integration with these extensions so you can build +slides with +.BR mom . +.LP +If you use present.tmac with +.B gropdf +there is no need to run the program +.BR presentps (@MAN1EXT@) +since the output will already be a presentation pdf. +.LP All other .B ps: tags are silently ignored. @@ -820,6 +866,193 @@ respectively. . These macros must only be used within page traps.) . +.TP +.BR "\[rs]X'pdf: transition'" "feature mode duration dimension motion direction scale bool" +where +.IP +.I feature +can be either SLIDE or BLOCK. When it is SLIDE the transition is used +when a new slide is introduced to the screen, if BLOCK then this transition +is used for the individual blocks which make up the slide. +.br +.I mode +is the transition type between slides:- +.RS +.IP +.B Split +- Two lines sweep across the screen, revealing the new page. The lines +may be either horizontal or vertical and may move inward from the +edges of the page or outward from the center, as specified by the +.I dimension +and +.I motion +entries, respectively. +.br +.B Blinds +- Multiple lines, evenly spaced across the screen, synchronously +sweep in the same direction to reveal the new page. The lines may be +either horizontal or vertical, as specified by the +.I dimension + entry. Horizontal +lines move downward; vertical lines move to the right. +.br +.B Box +- A rectangular box sweeps inward from the edges of the page or +outward from the center, as specified by the +.I motion +entry, revealing the new page. +.br +.B Wipe +- A single line sweeps across the screen from one edge to the other in +the direction specified by the +.I direction +entry, revealing the new page. +.br +.B Dissolve +- The old page dissolves gradually to reveal the new one. +.br +.B Glitter +- Similar to Dissolve, except that the effect sweeps across the page in a +wide band moving from one side of the screen to the other in the +direction specified by the +.I direction +entry. +.br +.B R +- The new page simply replaces the old one with no special transition +effect; the +.I direction +entry shall be ignored. +.br +.B Fly +- (PDF 1.5) Changes are flown out or in (as specified by +.IR motion ), +in the +direction specified by +.IR direction , +to or from a location that is offscreen except +when +.I direction +is +.BR None . +.br +.B Push +- (PDF 1.5) The old page slides off the screen while the new page +slides in, pushing the old page out in the direction specified by +.IR direction . +.br +.B Cover +- (PDF 1.5) The new page slides on to the screen in the direction +specified by +.IR direction , +covering the old page. +.br +.B Uncover +- (PDF 1.5) The old page slides off the screen in the direction +specified by +.IR direction , +uncovering the new page in the direction +specified by +.IR direction . +.br +.B Fade +- (PDF 1.5) The new page gradually becomes visible through the +old one. +.LP +.RE +.IP +.I duration +is the length of the transition in seconds (default 1). +.LP +.IP +.I dimension +(Optional; +.BR Split " and " Blinds +transition styles only) The dimension in which the +specified transition effect shall occur: +.B H +Horizontal, or +.B V +Vertical. +.LP +.IP +.I motion +(Optional; +.BR Split , +.BR Box " and " Fly +transition styles only) The direction of motion for +the specified transition effect: +.B I +Inward from the edges of the page, or +.B O +Outward from the center of the page. +.LP +.IP +.I direction +(Optional; +.BR Wipe , +.BR Glitter , +.BR Fly , +.BR Cover , +.BR Uncover " and " Push +transition styles only) +The direction in which the specified transition effect shall moves, expressed in +degrees counterclockwise starting from a left-to-right direction. +If the value is a number, it shall be one of: +.B 0 += Left to right, +.B 90 += Bottom to top (Wipe only), +.B 180 += Right to left (Wipe only), +.B 270 += Top to bottom, +.B 315 += Top-left to bottom-right (Glitter only) +The value can be +.BR None , +which is relevant only for the +.B Fly +transition when the value of +.I scale +is not 1.0. +.LP +.IP +.I scale +(Optional; PDF 1.5; +.B Fly +transition style only) The starting or ending scale at +which the changes shall be drawn. If +.I motion +specifies an inward transition, the scale +of the changes drawn shall progress from +.I scale +to 1.0 over the course of the +transition. If +.I motion +specifies an outward transition, the scale of the changes drawn +shall progress from 1.0 to +.I scale +over the course of the transition +.LP +.IP +.I bool +(Optional; PDF 1.5; +.B Fly +transition style only) If +.BR true , +the area that shall be flown +in is rectangular and opaque. +.LP +.IP +This command can be used by calling the macro +.B .pdftransition +using the parameters described above. +.LP +.IP +.B Note: +not all PDF Readers support any or all these transitions. +.LP . .\" ==================================================================== .SS Importing graphics @@ -1011,6 +1244,13 @@ for more details. . .TP .SM +.B GROPDF_NOSLIDE +If this is set true, +.B gropdf +will ignore all commands which produce a presentation pdf, +and produce a normal pdf instead. +.TP +.SM .B SOURCE_DATE_EPOCH A timestamp (expressed as seconds since the Unix epoch) to use as the creation timestamp in place of the current time. diff --git a/src/devices/gropdf/gropdf.pl b/src/devices/gropdf/gropdf.pl index 5e61e2f..8a4b4b6 100644 --- a/src/devices/gropdf/gropdf.pl +++ b/src/devices/gropdf/gropdf.pl @@ -121,12 +121,23 @@ my $wt=-1; my $thislev=1; my $mark=undef; my $suspendmark=undef; + + + my $n_flg=1; my $pginsert=-1; # Growth point for kids array my %pgnames; # 'names' of pages for switchtopage my @outlines=(); # State of Bookmark Outlines at end of each page my $custompaper=0; # Has there been an X papersize my $textenccmap=''; # CMap for groff text.enc encoding +my @XOstream=(); +my @PageAnnots={}; +my $noslide=0; +my $transition={PAGE => {Type => '/Trans', S => '', D => 1, Dm => '/H', M => '/I', Di => 0, SS => 1.0, B => 0}, + BLOCK => {Type => '/Trans', S => '', D => 1, Dm => '/H', M => '/I', Di => 0, SS => 1.0, B => 0}}; +my $firstpause=0; + +$noslide=1 if exists($ENV{GROPDF_NOSLIDE}) and $ENV{GROPDF_NOSLIDE}; my %ppsz=( 'ledger'=>[1224,792], 'legal'=>[612,1008], @@ -328,10 +339,29 @@ while (<>) } +exit 0 if $lct==0; if ($cpageno > 0) { + my $trans='BLOCK'; + + $trans='PAGE' if $firstpause; + + if (scalar(@XOstream)) + { + MakeXO() if $stream; + $stream=join("\n",@XOstream)."\n"; + } + + my %t=%{$transition->{$trans}}; $cpage->{MediaBox}=\@mediabox if $custompaper; + $cpage->{Trans}=FixTrans(\%t) if $t{S}; + + if ($#PageAnnots >= 0) + { + @{$cpage->{Annots}}=@PageAnnots; + } + PutObj($cpageno); OutStream($cpageno+1); } @@ -572,7 +602,7 @@ sub LoadDownload OpenFile(\$f,$dir,"download"); next if !defined($f); $found++; - + while (<$f>) { chomp; @@ -756,6 +786,53 @@ sub do_x $linecap=$1; $stream.="$linecap J\n"; } + elsif ($par=~m/exec %%%%PAUSE/i and !$noslide) + { + my $trans='BLOCK'; + + if ($firstpause) + { + $trans='PAGE'; + $firstpause=0; + } + MakeXO(); + NewPage($trans); + $cat->{PageMode}='/FullScreen'; + } + elsif ($par=~m/exec %%%%BEGINONCE/) + { + if ($noslide) + { + $suppress=1; + } + else + { + my $trans='BLOCK'; + + if ($firstpause) + { + $trans='PAGE'; + $firstpause=0; + } + MakeXO(); + NewPage($trans); + $cat->{PageMode}='/FullScreen'; + } + } + elsif ($par=~m/exec %%%%ENDONCE/) + { + if ($noslide) + { + $suppress=0; + } + else + { + MakeXO(); + NewPage('BLOCK'); + $cat->{PageMode}='/FullScreen'; + pop(@XOstream); + } + } elsif ($par=~m/\[(.+) pdfmark/) { my $pdfmark=$1; @@ -814,7 +891,7 @@ sub do_x $annot->{DATA}->{Type}='/Annot'; FixRect($annot->{DATA}->{Rect}); # Y origin to ll FixPDFColour($annot->{DATA}); - push(@{$cpage->{Annots}},$annotno); + push(@PageAnnots,$annotno); } elsif ($pdfmark=~m/(.+) \/OUT/) { @@ -1118,6 +1195,31 @@ sub do_x } } } + elsif (lc($xprm[1]) eq 'transition') + { + if (uc($xprm[2]) eq 'PAGE' or uc($xprm[2] eq 'SLIDE')) + { + $transition->{PAGE}->{S}='/'.ucfirst($xprm[3]) if $xprm[3] and $xprm[3] ne '.'; + $transition->{PAGE}->{D}=$xprm[4] if $xprm[4] and $xprm[4] ne '.'; + $transition->{PAGE}->{Dm}='/'.$xprm[5] if $xprm[5] and $xprm[5] ne '.'; + $transition->{PAGE}->{M}='/'.$xprm[6] if $xprm[6] and $xprm[6] ne '.'; + $xprm[7]='/None' if $xprm[7] and uc($xprm[7]) eq 'NONE'; + $transition->{PAGE}->{Di}=$xprm[7] if $xprm[7] and $xprm[7] ne '.'; + $transition->{PAGE}->{SS}=$xprm[8] if $xprm[8] and $xprm[8] ne '.'; + $transition->{PAGE}->{B}=$xprm[9] if $xprm[9] and $xprm[9] ne '.'; + } + elsif (uc($xprm[2]) eq 'BLOCK') + { + $transition->{BLOCK}->{S}='/'.ucfirst($xprm[3]) if $xprm[3] and $xprm[3] ne '.'; + $transition->{BLOCK}->{D}=$xprm[4] if $xprm[4] and $xprm[4] ne '.'; + $transition->{BLOCK}->{Dm}='/'.$xprm[5] if $xprm[5] and $xprm[5] ne '.'; + $transition->{BLOCK}->{M}='/'.$xprm[6] if $xprm[6] and $xprm[6] ne '.'; + $xprm[7]='/None' if $xprm[7] and uc($xprm[7]) eq 'NONE'; + $transition->{BLOCK}->{Di}=$xprm[7] if $xprm[7] and $xprm[7] ne '.'; + $transition->{BLOCK}->{SS}=$xprm[8] if $xprm[8] and $xprm[8] ne '.'; + $transition->{BLOCK}->{B}=$xprm[9] if $xprm[9] and $xprm[9] ne '.'; + } + } } elsif (lc(substr($xprm[0],0,9)) eq 'papersize') { @@ -1190,7 +1292,7 @@ sub PutHotSpot $annot->{DATA}->{Rect}=[$mark->{xpos},$mark->{ypos}-$mark->{rsb},$endx+$mark->{lead},$mark->{ypos}-$mark->{rst}]; FixPDFColour($annot->{DATA}); FixRect($annot->{DATA}->{Rect}); # Y origin to ll - push(@{$cpage->{Annots}},$annotno); + push(@PageAnnots,$annotno); } sub sgn @@ -1358,14 +1460,14 @@ sub OpenInc foreach my $dir (@idirs) { $fnm="$dir/$fn"; - + if (-r "$fnm" and open($F,"<$fnm")) { return($F,$fnm); } } } - + return(undef,$fn); } @@ -1384,7 +1486,7 @@ sub LoadPDF my $cont; my ($PD,$PDnm)=OpenInc($pdfnm); - + if (!defined($PD)) { Msg(0,"Failed to open PDF '$pdfnm'"); @@ -2284,59 +2386,59 @@ sub GetChunk my ($type,$hdr,$chunk,@msg); binmode($F); my $enc="ascii"; - + while (1) { # There may be multiple chunks of the same type - + my $ct=read($F,$hdr,2); - + if ($ct==2) { if (substr($hdr,0,1) eq "\x80") { # binary chunk - + my $chunktype=ord(substr($hdr,1,1)); $enc="binary"; - + if (defined($type) and $type != $chunktype) { seek($F,-2,1); last; } - + $type=$chunktype; return if $chunktype == 3; - + $ct=read($F,$hdr,4); - + Msg(1,"Failed to read binary segment length"), return if $ct != 4; - + my $sl=unpack('L',$hdr); my $data; my $chk=read($F,$data,$sl); - + Msg(1 ,"Failed to read binary segment"), return if $chk != $sl; - + $chunk.=$data; } else { # ascii chunk - + my $hex=0; seek($F,-2,1); my $ct=0; - + while (1) { my $lin=<$F>; - + last if !$lin; - + $hex=1,$enc.=" hex" if $segno == 2 and !$ct and $lin=~m/^[A-F0-9a-f]{4,4}/; - + if ($segno !=2 and $lin=~m/^(.*$ascterm\n?)(.*)/) { $chunk.=$1; @@ -2349,11 +2451,11 @@ sub GetChunk seek($F,-length($2)-1,1) if $2; last; } - + chomp($lin), $lin=pack('H*',$lin) if $hex; $chunk.=$lin; $ct++; } - + last; } } @@ -2362,7 +2464,7 @@ sub GetChunk push(@msg,"Failed to read 2 header bytes"); } } - + return $chunk; } @@ -2380,11 +2482,54 @@ sub OutStream sub do_p { + my $trans='BLOCK'; + + $trans='PAGE' if $firstpause; + NewPage($trans); + @XOstream=(); + @PageAnnots=(); + $firstpause=1; +} + +sub FixTrans +{ + my $t=shift; + my $style=$t->{S}; + + if ($style) + { + delete($t->{Dm}) if $style ne '/Split' and $style ne '/Blinds'; + delete($t->{M}) if !($style eq '/Split' or $style eq '/Box' or $style eq '/Fly'); + delete($t->{Di}) if !($style eq '/Wipe' or $style eq '/Glitter' or $style eq '/Fly' or $style eq '/Cover' or $style eq '/Uncover' or $style eq '/Push') or ($style eq '/Fly' and $t->{Di} eq '/None' and $t->{SS} != 1); + delete($t->{SS}) if !($style eq '/Fly'); + delete($t->{B}) if !($style eq '/Fly'); + } + + return($t); +} + +sub NewPage +{ + my $trans=shift; # Start of pages if ($cpageno > 0) { + if ($#XOstream>=0) + { + MakeXO() if $stream; + $stream=join("\n",@XOstream,''); + } + + my %t=%{$transition->{$trans}}; $cpage->{MediaBox}=\@mediabox if $custompaper; + $cpage->{Trans}=FixTrans(\%t) if $t{S}; + + if ($#PageAnnots >= 0) + { + @{$cpage->{Annots}}=@PageAnnots; + } + PutObj($cpageno); OutStream($cpageno+1); } @@ -2414,6 +2559,20 @@ sub do_p # @mediabox=@defaultmb; } +sub MakeXO +{ + $stream.="%mode=$mode\n"; + IsGraphic(); + $stream.="Q\n"; + my $xobj=++$objct; + my $xonm="XO$xobj"; + $pages->{'Resources'}->{'XObject'}->{$xonm}=BuildObj($xobj,{'Type' => '/XObject', 'BBox' => \@mediabox, 'Name' => "/$xonm", 'FormType' => 1, 'Subtype' => '/Form', 'Length' => 0, 'Type' => "/XObject"}); + $obj[$xobj]->{STREAM}=$stream; + $stream=''; + push(@XOstream,"q") if $#XOstream==-1; + push(@XOstream,"/$xonm Do"); +} + sub do_f { my $par=shift; @@ -2966,7 +3125,7 @@ sub PutLine $wd->[0]=~s/!\|!\|/\\/g; $wd->[1]=d3($wd->[1]); } - + if (0) { if (scalar(@lin) == 1 and (!defined($lin[0]->[1]) or $lin[0]->[1] == 0)) diff --git a/tmac/pdf.tmac b/tmac/pdf.tmac index 4a002c3..350f783 100644 --- a/tmac/pdf.tmac +++ b/tmac/pdf.tmac @@ -18,7 +18,7 @@ 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/>. +along with this program. If not, see <http://www.gnu.org/licenses/>. Author's Note ============= @@ -799,6 +799,12 @@ am solely responsible for any bugs I may have introduced into this file. .de pdfswitchtopage .nop \!x X pdf: switchtopage \\$* .. +.de pdfpause +.nop \!x X ps: exec %%%%PAUSE +.. +.de pdftransition +.nop \!x X pdf: transition \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 +.. .\" Local Variables: .\" mode: nroff .\" End: _______________________________________________ Groff-commit mailing list Groff-commit@gnu.org https://lists.gnu.org/mailman/listinfo/groff-commit