% File:        thumbpdf.sty
% Project:     thumbpdf
% Version:     2003/03/19 v3.3
% Author:      Heiko Oberdiek
%
% Function:    Inclusion of thumbnails
%
% Copyright:   Copyright (C) 1999-2003 Heiko Oberdiek.
%
%              This program may be distributed and/or modified under
%              the conditions of the LaTeX Project Public License,
%              either version 1.2 of this license or (at your option)
%              any later version. The latest version of this license
%              is in
%                http://www.latex-project.org/lppl.txt
%              and version 1.2 or later is part of all distributions
%              of LaTeX version 1999/12/01 or later.
%
%              See file `readme.txt' for a list of files that
%              belong to this project.
%
% Requirement: * pdftex mode:
%                * pdfTeX (plain or latex formats)
%                * thumbnail data file: `<jobname>.tpt'
%              * pdfmark mode:
%                * Ghostscript 6.0, versions below do not work.
%                  Eventually Adobe Distiller can work, but I
%                  cannot test this.
%                * thumbnail data file: `<jobname>.tpm'
%              * Both thumbnail data files are generated by the
%                perl script `thumbpdf(.pl)'.
%
% Use:         * LaTeX2e: \usepackage{thumbpdf}
%                Options: pdftex,
%                         pdfmark, dvips, ps2pdf
%                         vtex, vtexpdfmark
%              * plain:   \input thumbpdf.sty
%                A driver can be defined previously:
%                \def\ThumbpdfDriver{pdfmark}
%              * It is not necessary to set driver `pdftex', `vtex',
%                or `vtexpdfmark', because pdfTeX and VTeX are
%                detected at run time. So package `thumbpdf'
%                chooses the correct driver and ignores other
%                specified drivers.
%
% History:     1999/02/14 v1.0:  first public release
%              1999/02/23 v1.1:  bug in plain-\@thumbwarning removed.
%              1999/03/01 v1.2:  \DefLastObj no longer needed.
%              1999/03/12 v1.3:  Copyright: LPPL
%              1999/05/05 v1.4:  added \the before \inputlineno.
%                                sharing RGB objects.
%              1999/06/13 v1.5
%              1999/07/27 v1.6:  Bug of handling with \pdfpageattr
%                                fixed. The same bug is in hyperref
%                                versions below 6.64 (option
%                                pagetransition).
%                                Warning added, if there are missing
%                                thumbnails.
%              1999/08/08 v1.7:  Bug in \@ThumbPageAttr fixed
%                                (introduced in version 1.6).
%              1999/09/09 v1.8:  \PackageWarning does not work at
%                                the beginning of \shipout, because
%                                \protect has been set to \noexpand
%                                (mysterious LaTeX behaviour?).
%              1999/09/16 v1.9
%              2000/01/11 v1.10: Revised.
%              2000/01/19 v1.11
%              2000/02/11 v1.12: \jobname.tnd supported,
%                                \DeclareThumbs added.
%              2000/02/22 v2.0:  pdfmark support, extra thumbnails are
%                                scanned in file `<jobname>.tno'.
%              2000/02/28 v2.1:  support of `thumbpdf.cfg'.
%              2000/03/07 v2.2
%              2000/03/22 v2.3
%              2000/04/10 v2.4
%              2000/07/29 v2.5
%              2000/09/27 v2.6
%              2000/10/27 v2.7
%              2001/01/12 v2.8
%              2001/03/29 v2.9
%              2001/04/02 v2.10
%              2001/04/26 v2.11
%              2002/01/11 v3.0:  Support for VTeX's PostScript mode added.
%              2002/05/26 v3.1
%              2002/05/26 v3.2
%              2003/03/19 v3.3
%
% \THB@ is the prefix for internal command names.
%
% Prevent that the package is loaded twice (for plain formats).
\expandafter\ifx\csname THB@name\endcsname\relax
  \expandafter\gdef\csname THB@name\endcsname{thumbpdf}
\else
  \expandafter\endinput
\fi

% Package identification in the log file
\begingroup
  \def\x[#1]{\endgroup\immediate\write-1{Package: thumbpdf #1}}%
  \ifx\ProvidesPackage\UnDeFiNeD
  \else
    \ifx\ProvidesPackage\relax
    \else
      \def\x{\endgroup\ProvidesPackage{thumbpdf}}%
    \fi
  \fi
\x[2003/03/19 v3.3 Inclusion of thumbnails (HO)]%

% Dummy for \thisthumb and \DeclareThumbs. It is overwritten,
% if the checks succeed and the whole package is loaded.
\def\thisthumb#1{}
\def\DeclareThumbs#1{}

% Check part, keep help macros local:
\begingroup

  % For use of `@' in command names.
  \catcode`\@=11

  % Now we define utils of the LaTeX kernel, if they aren't.
  \expandafter\ifx\csname @firstoftwo\endcsname\relax
    \long\def\@firstoftwo#1#2{#1}%
    \long\def\@secondoftwo#1#2{#2}%
  \fi
  \expandafter\ifx\csname @ifundefined\endcsname\relax
    \def\@ifundefined#1{%
      \expandafter\ifx\csname#1\endcsname\relax
        \expandafter\@firstoftwo
      \else
        \expandafter\@secondoftwo
      \fi
    }%
  \fi

  % If a check fails, a warning is produced and the package exits.
  \@ifundefined{PackageWarningNoLine}{%
    \def\PackageWarningNoLine#1#2{%
      \immediate\write16{}%
      \immediate\write16{Package #1 Warning: #2.}%
      \immediate\write16{}%
    }%
  }{}

  \long\def\@ReturnAfterFi#1\fi{\fi#1}
  \long\def\@ReturnAfterElseFi#1\else#2\fi{\fi#1}

  \def\THB@WarnEnd#1{%
    \PackageWarningNoLine{thumbpdf}{#1}%
    \endgroup
    \endinput
  }

  % \csname-Trick because of \outer definition of \newread.
  % \globaldefs=-1 in order to make the allocation of \newread local.
  \@ifundefined{IfFileExists}{%
    \edef\x{\the\globaldefs}%
    \globaldefs-1\relax
    \csname newread\endcsname\THB@TempRead
    \globaldefs\x\relax
    \def\IfFileExists#1{%
      \openin\THB@TempRead=#1\relax
      \ifeof\THB@TempRead
        \closein\THB@TempRead
        \expandafter\@secondoftwo
      \else
        \closein\THB@TempRead
        \expandafter\@firstoftwo
      \fi
    }%
  }{}

  % Load .cfg file if it exists
  \IfFileExists{thumbpdf.cfg}{%
    \@ifundefined{@@input}{%
      \input thumbpdf.cfg\relax
    }{%
      \input{thumbpdf.cfg}%
    }%
  }{}

  % LaTeX2e options
  \def\THB@pdftex{pdftex}
  \def\THB@pdfmark{pdfmark}
  \def\THB@vtex{vtex}
  \@ifundefined{ThumbpdfDriver}{\let\ThumbpdfDriver\empty}{}
  \@ifundefined{DeclareOption}{}{%
    \DeclareOption{pdftex}{\let\ThumbpdfDriver\THB@pdftex}%
    \DeclareOption{pdfmark}{\let\ThumbpdfDriver\THB@pdfmark}%
    \DeclareOption{dvips}{\let\ThumbpdfDriver\THB@pdfmark}%
    \DeclareOption{ps2pdf}{\let\ThumbpdfDriver\THB@pdfmark}%
    \DeclareOption{vtex}{\let\ThumbpdfDriver\THB@vtex}%
    \DeclareOption{vtexpdfmark}{\let\ThumbpdfDriver\THB@vtex}%
    \ProcessOptions\relax
  }
  \edef\x{\ThumbpdfDriver}
  \expandafter\lowercase\expandafter{%
    \expandafter\gdef\expandafter\ThumbpdfDriver\expandafter{\x}%
  }
  \def\x{dvips}\ifx\ThumbpdfDriver\x
    \global\let\ThumbpdfDriver\THB@pdfmark
  \fi
  \def\x{ps2pdf}\ifx\ThumbpdfDriver\x
    \global\let\ThumbpdfDriver\THB@pdfmark
  \fi
  \def\x{vtexpdfmark}\ifx\ThumbpdfDriver\x
    \global\let\ThumbpdfDriver\THB@vtex
  \fi

  % Check: Called by pdfTeX or VTeX? Driver correct?
  \ifcase\@ifundefined{pdfoutput}0\pdfoutput\relax
    \@ReturnAfterElseFi{%
      \ifcase0\@ifundefined{OpMode}1{\ifnum\OpMode=2 \else 1\fi} %
        \global\let\ThumbpdfDriver\THB@vtex
      \else
        \@ReturnAfterFi{%
          \ifx\ThumbpdfDriver\THB@pdfmark
          \else
            \@ReturnAfterFi{%
              \ifx\ThumbpdfDriver\empty
                \@ReturnAfterElseFi{%
                  \THB@WarnEnd{%
                    Missing driver name%
                  }%
                }%
              \else
                \@ReturnAfterFi{%
                  \ifx\ThumbpdfDriver\THB@pdftex
                    \@ReturnAfterElseFi{%
                      \THB@WarnEnd{%
                        You need pdfTeX in PDF mode for driver `pdftex'%
                      }%
                    }%
                  \else
                    \@ReturnAfterFi{%
                      \ifx\ThumbpdfDriver\THB@vtex
                        \@ReturnAfterElseFi{%
                          \THB@WarnEnd{%
                            You need VTeX in PS mode for driver `vtex'%
                          }%
                        }%
                      \else
                        \@ReturnAfterFi{%
                          \THB@WarnEnd{%
                            Driver `\ThumbpdfDriver' not supported%
                          }%
                        }%
                      \fi
                    }%
                  \fi
                }%
              \fi
            }%
          \fi
        }%
      \fi
    }%
  \else
    \global\let\ThumbpdfDriver\THB@pdftex
  \fi

  % Check: Does data file exists?
  \edef\THB@datafile{%
    \jobname.tp\ifx\ThumbpdfDriver\THB@pdftex t\else m\fi
  }%
  \IfFileExists{\THB@datafile}{}{%
    \THB@WarnEnd{Thumbnail data file `\THB@datafile' not found}%
  }%

  % Some macros need \PackageWarning
  \expandafter\ifx\csname PackageWarning\endcsname\relax
    \gdef\PackageWarning#1#2{%
      \immediate\write16{}%
      \immediate\write16{%
        Package `#1' warning: #2 on input line \the\inputlineno.%
      }%
      \immediate\write16{}%
    }%
  \fi

  % definition of \DeclareThumbs
  \gdef\DeclareThumbs#1{%
    \begingroup
      % check LaTeX's \if@filesw
      \expandafter\ifx\csname if@filesw\expandafter\endcsname
                      \csname iffalse\endcsname
      \else
        \csname newwrite\endcsname\THB@thumbopt
        \immediate\openout\THB@thumbopt=\jobname.tno
        % Definition of \thumb that also works with plain format.
        \def\thumb##1##{\THB@thumb{##1}}%
        \def\THB@thumb##1##2{%
          \immediate\write\THB@thumbopt{%
            \string\thumb##1{##2}%
          }%
        }%
        \let\protect\string
        % process data
        #1%
        % end of file
        \immediate\write\THB@thumbopt{\string\endinput}%
      \fi
    \endgroup
    \global\let\DeclareThumbs\THB@DeclareThumbs
  }
  \def\THB@DeclareThumbs#1{%
    \PackageWarning{\THB@name}{Too many \string\DeclareThumbs}%
  }

  % pdfmark part
  \ifx\ThumbpdfDriver\THB@pdfmark
    % the header file includes already the regular thumbnails.
    \special{header=\THB@datafile}%
    \begingroup
      \def\DefThisThumb#1{%
        \global\expandafter\let\csname thumb#1\endcsname\empty
      }%
      % ignore PostScript comment char
      \catcode`\%=9
      \@ifundefined{@@input}{\input\THB@datafile\relax}
                            {\input{\THB@datafile}}
    \endgroup
    % definition of \thisthumb
    \gdef\thisthumb#1{%
      \expandafter\ifx\csname thumb#1\endcsname\relax
        \PackageWarning{\THB@name}{Thumbnail `#1' undefined}%
      \else
        \special{ps:{THB\string_#1} thisTHB}%
      \fi
    }%
    % end of pdfmark part
    \endgroup\expandafter\endinput
  \fi

  % vtex part
  \ifx\ThumbpdfDriver\THB@vtex
    % the header file includes already the regular thumbnails.
    \ifnum\@ifundefined{VTeXversion}0\VTeXversion<753 %
      \ifcase\@ifundefined{gexmode}1\gexmode
        % without GeX
        \immediate\special{header=\THB@datafile}%
      \else
        % with GeX
        \begingroup
          \edef\x{\the\globaldefs}%
          \globaldefs-1\relax
          \csname newread\endcsname\THB@TempRead
          \globaldefs\x\relax
          \openin\THB@TempRead=\THB@datafile\relax
          \def\x{%
            \catcode`\%=12 %
            \catcode`\|=0 %
            \catcode`\{=12 %
            \catcode`\}=12 %
            \catcode`\ =12 %
            \catcode`\\=12 %
            \catcode`\_=12 %
            \let\par\empty
            \loop
            \ifcase\ifeof\THB@TempRead 1 \else 0 \fi
              \read\THB@TempRead to \THB@line
              \immediate\special{!=\THB@line}%
            \repeat
            \closein\THB@TempRead
            \endgroup
          }%
        \x
      \fi
    \else
      \immediate\special{headercopy=\THB@datafile}%
    \fi
    \begingroup
      \def\DefThisThumb#1{%
        \global\expandafter\let\csname thumb#1\endcsname\empty
      }%
      % ignore PostScript comment char
      \catcode`\%=9
      \@ifundefined{@@input}{\input\THB@datafile\relax}
                            {\input{\THB@datafile}}
    \endgroup
    % definition of \thisthumb
    \gdef\thisthumb#1{%
      \expandafter\ifx\csname thumb#1\endcsname\relax
        \PackageWarning{\THB@name}{Thumbnail `#1' undefined}%
      \else
        \special{!={THB\string_#1} thisTHB}%
      \fi
    }%
    % end of vtex part
    \endgroup\expandafter\endinput
  \fi

  % pdftex part
  \global\let\THB@datafile\THB@datafile
\endgroup

\expandafter\chardef\csname THB@AtCode\endcsname=\the\catcode`\@
\catcode`\@=11

% The thumbnails are numbered with the output pages:
% `thb1.png' means the thumbnail of the first output page,
% `thb28.png' the thumbnail of the 28th written page,
% regardless of the page number.
%   Therefore we need a new counter that is incremented with each
% page that is written to the pdf file.
\newcount\c@thumb
\c@thumb 0\relax

\newif\ifTHB@thisthumb

\def\thisthumb#1{%
  \global\THB@thisthumbtrue
  \THB@AddPageAttr{#1}%
}

% Now we enhance \shipout in order to
% * increment the output page counter (\c@thumb),
% * check if a thumbnail exists,
% * add/remove the thumbnail entry to the pdf page attributes.
\let\THBorg@shipout\shipout
\def\shipout{\THB@AddThumb\THBorg@shipout}
\def\THB@AddThumb{%
  \begingroup
    \global\advance\c@thumb by 1\relax
    \ifTHB@thisthumb
      \global\THB@thisthumbfalse % reset switch
    \else
      \THB@AddPageAttr{\the\c@thumb}%
    \fi
  \endgroup
}
\def\THB@AddPageAttr#1{%
  % Remove previous /Thumb entry.
  \expandafter\THB@RemoveThumbAttr\the\pdfpageattr^^J/Thumb{} 0 R\END
  % Check, if thumb exists.
  \expandafter\ifx\csname thumb#1\endcsname\relax
    % \PackageWarning cannot be used, because \protect=\noexpand.
    \immediate\write16{}%
    \immediate\write16{Package \THB@name\space Warning: %
      Thumbnail `#1' undefined %
      on input line \the\inputlineno.%
    }%
    \immediate\write16{}%
  \else
    \begingroup
      \edef\x{\endgroup
        \global\pdfpageattr{%
          \the\pdfpageattr
          ^^J/Thumb \csname thumb#1\endcsname\space 0 R%
        }%
      }%
    \x
  \fi
}
\def\THB@RemoveThumbAttr#1^^J/Thumb#2#3 0 R#4\END{%
  \ifx\\#2\\%
    \global\pdfpageattr{#1}%
  \else
    \THB@RemoveThumbAttr#1#4\END
  \fi
}

% Many commands and catcode changes are only necessary to read
% the data file, so we do this in a group.
\begingroup

  % These commands are used in `<jobname>.tpt'
  \def\DefThumb#1{%
    \expandafter\xdef\csname thumb#1\endcsname{\the\pdflastobj}%
  }%

  \def\DefRGB#1{%
    \expandafter\edef\csname thumbRGB#1\endcsname{\the\pdflastobj}%
  }%
  \def\UseRGB#1{\csname thumbRGB#1\endcsname}%

  % Now the catcodes to read `<jobname>.tpt' follows:
  \def\SetCatcodeRange#1#2{%
    \c@thumb=#1
    \loop
      \catcode\c@thumb=12
    \ifnum\c@thumb<#2
      \advance\c@thumb by 1
    \repeat
  }
  \SetCatcodeRange{0}{12}%
  % ^^M
  \SetCatcodeRange{14}{31}%
  % space
  \SetCatcodeRange{33}{36}% ! " # $
  % percent
  \SetCatcodeRange{38}{63}% & ' ( ) * + , - . / 0-9 : ; < = > ?
  % @ A-Z
  \catcode`\[=12
  % backslash
  \catcode`\]=12
  % ^
  \SetCatcodeRange{95}{96}% _ '
  % a-z {
  \catcode`\|=12
  % }
  \SetCatcodeRange{126}{255}% ~ 127 8-bit

  % commands for special characters used in `<jobname>.tpt'.
  \edef\~{\space}% in stream data to avoid `\ ' at line end.
  \let\ \~%
  \edef\+{\string^}%
  \begingroup
    \lccode`1=`\\
    \lccode`2=`\^^M
    \lccode`3=`\{
    \lccode`4=`\}
    \lccode`5=`\%
  \lowercase{\endgroup
    \def\\{1}%
    \def\/{2}%
    \def\{{3}%
    \def\}{4}%
    \def\%{5}%
  }

  % no white space by line ends
  \endlinechar=-1

  % process data file and include the thumbnails
  % in the current pdf file
  \expandafter\ifx\csname @@input\endcsname\relax
    \input\THB@datafile\relax
  \else
    \input{\THB@datafile}%
  \fi
\endgroup
% restore catcode of `@'.
\catcode`\@=\THB@AtCode\relax
\endinput
