groff-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[groff] 01/01: Add page transitions to pdfs created with gropdf.


From: Deri James
Subject: [groff] 01/01: Add page transitions to pdfs created with gropdf.
Date: Thu, 1 Mar 2018 10:21:09 -0500 (EST)

deri pushed a commit to branch master
in repository groff.

commit f2a92911c552c3995c010f8beb9b89de3612e95a
Author: Deri James <address@hidden>
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  <address@hidden>
+
+       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  <address@hidden>
 
        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->address@hidden if $custompaper;
+       $cpage->{Trans}=FixTrans(\%t) if $t{S};
+
+       if ($#PageAnnots >= 0)
+       {
+           @{$cpage->address@hidden;
+       }
+
        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->address@hidden if $custompaper;
+       $cpage->{Trans}=FixTrans(\%t) if $t{S};
+
+       if ($#PageAnnots >= 0)
+       {
+           @{$cpage->address@hidden;
+       }
+
        PutObj($cpageno);
        OutStream($cpageno+1);
     }
@@ -2414,6 +2559,20 @@ sub do_p
 #    @address@hidden;
 }
 
+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' => address@hidden, '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:



reply via email to

[Prev in Thread] Current Thread [Next in Thread]