#!/usr/bin/env perl # # Copyright (C) 2012 by Robert Marik # ------------------------------------------------------ # # This file 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. # # fancy-preview # ------------- # # This is a script which can be used to extract displayed equations, # theorem-like environments, figures and bibliography references and # attach this material as tooltip to LaTeX \ref, \eqref and \cite # comand. This has been requested by several (pdf)(La)TeX users. See # http://tex.stackexchange.com/questions/15356/showing-the-bibliographic-entry-in-a-popup-when-you-hover-over-the-citation-key # for some discussion and papers # http://permalink.gmane.org/gmane.comp.tex.pdftex/3898 and # http://www.math.huji.ac.il/~erezla/papers/continuity_semisimple.pdf # as demos of interactive PDF. # # Demos for the current script are at # http://user.mendelu.cz/marik/fancy-preview site. Basicaly, you can # find there PDF files with hyperref links. Each link is followed by a # button. This button is invisible in mathematical papers and blue # soap in presentations. # # 1. add "\usepackage{hyperref}" to the preamble of your document (say # filename.tex), # # 2. add blank line after each \bibitem command, # # 3. compile with command "bash fancy-preview filename" i.e. no tex # extension is used in the command line # # 4. You may customize this script. # # The script has been tested on Linux, Ubuntu 12.04,TeXlive 2011. # # It works as follows: # 1. We extract desired environments in two runs. We crop the PDF # files and save the information relatex labels from aux file. # 2. We join the files together, we add some background and graphics # to the tooltips. # # # Known bugs, limitations. # ------------------------ # # * Do not use tags involving \ref command, do not use something like # \tag{\ref{someting}-b} inside equation environment. # * Do not use the word tocindent in the labels. # * Do not use elsart class. Use for example article or elsarticle # class. # * Each bibitem must be finished by a blank line. # # # History # ------- # # June 12, 2012: advanced posibilities for configuration # May 24, 2012: bash script converted to Perl for better portability, tests on MS Windows. # May 7, 2012: initial Linux version in bash # use strict; use Getopt::Long; my $filename = $ARGV[0]; my $filename_noext = $filename; $filename_noext =~ s/\.tex//; my $aux_file=$filename_noext.".aux"; my @tempfilenames=($filename_noext.".aux"); my %latex =(); # Setting for two passes of preview.sty $latex{'a'}='\makeatletter\def\nononotags{\def\@eqnnum{\relax}\def\tagform@##1{}}\makeatother\AtBeginDocument{\usepackage[pdftex,active,tightpage,displaymath]{preview}\nononotags}'; $latex{'b'}='\AtEndDocument{\clearpage}\AtBeginDocument{\usepackage[pdftex,active,tightpage]{preview}\setlength\PreviewBorder{5pt}}'; # Do not use third pass of preview.sty by default $latex{'c'}=''; $latex{'a_extra'}=''; $latex{'b_extra'}=''; $latex{'pass_order'}="acb"; # Hacks to get references (in the first pass). # IMPORTANT: each bibitem must be finished by a blank line. $latex{'preview_bibitem'}='\AtBeginDocument{\newenvironment{fakebibitem}{\begin{minipage}{0.75\textwidth}}{\end{minipage}}\PreviewEnvironment{fakebibitem}\renewcommand\bibitem[2][]{\BIBITEM {#2}}\def\BIBITEM#1#2\par{\begin{fakebibitem} #2 \label{fancy:cite:#1}\end{fakebibitem}}}'; $latex{'preview_biblatex'}='\AtBeginDocument{\PreviewEnvironment{fakebibitem}\def\fancycitation#1{\begin{fakebibitem}\setbox0=\hbox{\parbox{0.75\textwidth}{\fullcite{#1}\label{fancy:cite:#1}}}\pdfpagewidth=\wd0\pdfpageheight=\ht0\advance\pdfpageheight by \dp0\copy0\end{fakebibitem}\newpage}}\AtEndDocument{\input '.$filename_noext.'-fancybib.tmp}'; # The environments for extraction in the second pass of preview.sty. $latex{'environments'}="Theorem,theorem,lemma,corollary,definition"; $latex{'snarfenvironments'}="figure"; # The variable with initial commands for all pdflatex calls. $latex{'ini'}='\relax'; my $pdflatex="pdflatex"; my $bibtex="bibtex"; my $pdfcrop="pdfcrop"; # Default options for final compilation with fancytooltips. Change # "previewall" into "preview" to omit tooltips with target on the same # page (useful for presentations). You may also set this option from # the comand line. my $fancy_options="previewall,nosoap"; my $tooltipfile=""; my $help=0; my $version=0; my $date="24.6.2012"; my $versionnumber="0.2"; # The code used in premable. Should define macro \tooltipwraper which # inserts the tooltip extracted in previous compilations into a box # with nontransparent background $latex{'tooltips_envelope_preamble'}='\usepackage{xcolor,tikz}\usetikzlibrary{shadows}\def\tooltipwraper#1{\begin{tikzpicture}\node[drop shadow,fill=yellow!30,draw=black!30, rounded corners=3pt,very thick]{#1};\end{tikzpicture}}'; $latex{'biblatex'}=' % from http://tex.stackexchange.com/questions/15356/showing-the-bibliographic-entry-in-a-popup-when-you-hover-over-the-citation-key/54831#54831 % thanks to Audrey % Apply tooltip to "extratext" area just after inline citation links \DeclareFieldFormat{bibhyperref}{% \tooltip*{\bibhyperref{#1}}{fancy:cite:\thefield{entrykey}}} % Define new citation commands that replace citation links with tooltips \DeclareFieldFormat{bibtooltip}{\tooltip{#1}{fancy:cite:\thefield{entrykey}}} \newrobustcmd*{\tooltiphook}{% \AtNextCite{\DeclareFieldAlias{bibhyperref}{bibtooltip}}} \newrobustcmd*{\tooltipcite}{\tooltiphook\cite} \newrobustcmd*{\tooltipcites}{\tooltiphook\cites} % Apply tooltip to instance where numeric-comp uses \bibhyperref instead % of bibhyperref format \makeatletter \newbibmacro*{cite:dump:tooltip}{% \ifnumgreater{\value{cbx@tempcnta}}{0} {\ifnumgreater{\value{cbx@tempcnta}}{1} {\bibrangedash} {\multicitedelim}% \tooltip* {\bibhyperref[\cbx@lastkey]{% \ifdef\cbx@lastprefix {\printtext[prefixnumber]{\cbx@lastprefix}} {}% \printtext[labelnumber]{\cbx@lastnumber}}} {fancy:cite:\cbx@lastkey}} {}% \setcounter{cbx@tempcnta}{0}% \global\undef\cbx@lastprefix} \ifcsundef{abx@macro@\detokenize{cite:dump}} {}{\renewbibmacro*{cite:dump}{\usebibmacro{cite:dump:tooltip}}} \makeatother '; my %options=(); GetOptions ( "fancy_options=s" => \$options{fancy_options}, "pdfcrop=s" => \$options{pdfcrop}, "tooltips=s" => \$options{tooltips}, "ini_file=s" => \$options{ini_file}, "version" => \$version, "help" => \$help); if ($version) { print "$versionnumber\n"; exit(); } if ($help) { my $help_text=' This is fancy-preview script (R. Marik, http://user.mendelu.cz/marik) ============================ The script converts LaTeX files into PDF files. The references are followed by invisible buttons whih allow to show the target in a popup window. The homepage (last version, documentation, tips for users, examples) of the script is http://user.mendelu.cz/marik/fancy-preview OPTIONS: For detailed description see Section 3 of the manual to the fancytooltips package. --fancy_options="text" text is passed as optional parameter to fancytooltips package --pdfcrop="filename" program to crop the boundaries of PDF file --tooltips="filename" the file filename.pdf contains hand-created tooltips and filename.tips optionally keywords to acces these tooltips --ini_file="filename" ini file with the configuration --version prints version and exists --help prints help and exists EXAMPLES: Compile file.tex perl fancy-preview file Compile file.tex, use pdfcrop2 to crop the boundary of PDF file, show only previews where the target is on the different page ./fancy-preview file --fancy_options="preview" --pdfcrop="pdfcrop2" '; print $help_text; exit(); } #### Read configuration from ~/.fancy-preview.ini and ./fancy-preview.ini use Config::IniFiles; my($cfg); sub set_tex_variable { if ($cfg->exists( 'latex', $_[0] )) {$latex{$_[0]}=$cfg->val( 'latex', $_[0]);} } sub read_config { if ( -e $_[0]) { $cfg = Config::IniFiles->new( -file => $_[0]); if ($cfg->exists( 'main', 'pdfcrop' )) {$pdfcrop=$cfg->val( 'main', 'pdfcrop');} if ($cfg->exists( 'main', 'fancy_options' )) {$fancy_options=$cfg->val( 'main', 'fancy_options');} if ($cfg->exists( 'main', 'tooltips' )) {$tooltipfile=$cfg->val( 'main', 'tooltips');} my @options=("tooltips_envelope_preamble","environments","snarfenvironments","a","a_extra","b","b_extra","c","ini","biblatex","pass_order"); foreach my $current_option (@options) {set_tex_variable($current_option);} } } if ($options{ini_file}) { read_config($options{ini_file}); } else { read_config($ENV{"HOME"}."/.fancy-preview.ini"); read_config("./fancy-preview.ini"); } #### end of configuration # command line overrides config file if ($options{fancy_options}) {$fancy_options=$options{fancy_options}}; if ($options{pdfcrop}) {$pdfcrop=$options{pdfcrop}}; if ($options{tooltips}) {$tooltipfile=$options{tooltips}}; my $biblatex=0; # ----------------------------------------------------------------- # We extract stuff from the TeX file, extract the label definition # from aux file and crop the PDF file. Since pdfcrop from texlive # creates large files, we allow customization (see # http://tex.stackexchange.com/questions/42236/pdfcrop-generates-larger-file # ) unlink ("$filename_noext.aux"); # The first compilation to create numbers for equations, theorems, figures, ... system("$pdflatex \"$latex{ini} \\input $filename\""); # We test if the file uses biblatex. If not, thebibliography is supposed. open(LOG, $filename_noext.".log"); my @log_data=; my @log_tmp = grep /^Package: biblatex/, @log_data; my $log_tmp_size=@log_tmp; if ($log_tmp_size>0) {$biblatex=1;} my $preview_references=""; if ($biblatex) { optbibtex(); open(AUX, $aux_file); my @aux_data=; my @result=(); foreach $a (@aux_data) { if (($a =~ m/\\citation{/)&&($a !~ m/{biblatex-control}/)) { $a =~ s/\\citation{/\\fancycitation{/; push(@result, $a); } } close(AUX); sub uniq { return keys %{{ map { $_ => 1 } @_ }}; } open(AUXA, ">$filename_noext"."-fancybib.tmp"); foreach $a (sort(uniq(@result))) { print AUXA $a; } close(AUXA); push (@tempfilenames,$filename_noext."-fancybib.tmp"); $preview_references=$latex{'preview_biblatex'}; } else { $preview_references=$latex{'preview_bibitem'}; } system("$pdflatex \"$latex{ini}\\relax $latex{a}\\relax $latex{'a_extra'}\\relax $preview_references\\relax \\input $filename\""); parse_aux_file_and_crop("a"); # The second pass, in this pass theorem-like environments are # extracted. Two passes are necessary, since numbered equations which # appear in theorems frequently have to been extracted separately (in # the first pass). if($latex{'environments'} ne "") { $latex{'b'}=$latex{'b'}.'\AtBeginDocument{\PreviewEnvironment[{[]}]{'.join('}\PreviewEnvironment[{[]}]{',split(/,/,$latex{'environments'}))."}}"; } if($latex{'snarfenvironments'} ne "") { $latex{'b'}=$latex{'b'}.'\AtBeginDocument{\PreviewSnarfEnvironment[{[]}]{'.join('}\PreviewSnarfEnvironment[{[]}]{',split(/,/,$latex{'snarfenvironments'}))."}}"; } $latex{'b'}=$latex{'b'}.$latex{'b_extra'}; compile_parse_aux_file_and_crop("b"); if($latex{'c'} ne "") { compile_parse_aux_file_and_crop("c"); } else { $latex{'pass_order'} =~ s/c//; } print "\n----------------------------------------------\n------ pdflatex genearting tooltips ----------\n----------------------------------------------"; # We merge all the tooltips in one file. If some hand created # tooltips are also present, we insert these tooltips first in a loop # (multido). Then we insert theorem-like environments (from the second # pass) and finaly equations and citations (from the first pass). my $opt_pdfpages_a=""; my $opt_pdfpages_b=""; my $inserttooltips='\insertttp{'.join('}\insertttp{',split(//,$latex{'pass_order'})).'}'; if ($tooltipfile ne "") { $opt_pdfpages_a='\usepackage{multido}'; $opt_pdfpages_b='\ifx\pdfpagewrapper\undefined\let\pdfpagewrapper\relax\fi\pdfximage{'.$tooltipfile.'.pdf}\edef\FancyPreviewTotalPages{\the\pdflastximagepages}\multido{\i=1+1}{\FancyPreviewTotalPages}{\setbox0=\hbox{\pdfpagewrapper{\includegraphics[page=\i]{'.$tooltipfile.'.pdf}}}\pdfpagewidth=\wd0 \pdfpageheight=\ht0 \advance \pdfpageheight by \dp0 \copy0\newpage}\newpage'; } system("$pdflatex".' "\documentclass{minimal}\usepackage{graphicx}'.$opt_pdfpages_a.'\usepackage[papersize={5in,5in},margin=1pt]{geometry}'.$latex{'tooltips_envelope_preamble'}.'\usepackage[createtips]{fancytooltips}\newdimen\dist \dist=5pt\relax\begin{document}\pagestyle{empty}'.$opt_pdfpages_b.'\relax \gdef\savemaplabels#1#2#3#4{\xdef\temp{#2}} \def\fancypreviewnewlabel#1#2{\savemaplabels#2 \expandafter\ifx\csname keytip:#1:used\endcsname\relax \expandafter\def\csname keytip:#1:used\endcsname{used}\setbox0=\vbox{\kern\dist\hbox{\kern\dist\tooltipwraper{\includegraphics[page=\temp]{'.$filename_noext.'-\ttpfilename-crop.pdf}}\kern\dist}\kern\dist}\pdfpagewidth=\wd0 \pdfpageheight=\ht0 \advance \pdfpageheight by \dp0 \copy0 \keytip{#1}\newpage\fi}\def\insertttp#1{\def\ttpfilename{#1}\input '.$filename_noext.'-#1.tmp}'.$inserttooltips.'\end{document}"'); if ($tooltipfile ne "") { open(TIPS1, ">>minimal.tips"); open(TIPS2, "$tooltipfile.tips"); while () { print TIPS1 $_; } close (TIPS1); close (TIPS2); } # If biblatex is used, we update the information in bib file and hack # the cite-like commands according to the example # http://tex.stackexchange.com/questions/15356/showing-the-bibliographic-entry-in-a-popup-when-you-hover-over-the-citation-key/54831#54831 # $latex{'ini'}=""; if ($biblatex) { system("$pdflatex \"$latex{'ini'}\\relax \\input $filename\""); system("$bibtex $filename_noext.aux"); open(BIBL, ">fancy-preview-biblatex-settings.tex"); print BIBL $latex{'biblatex'}; close (BIBL); push (@tempfilenames,"fancy-preview-biblatex-settings.tex"); $latex{'ini'}='\AtBeginDocument{\input fancy-preview-biblatex-settings.tex}'; } for my $i (1 .. 4){ my $hypersetup='\hypersetup{colorlinks=true}'; print "----------------------------------------------\n------ pdflatex final compilation $i ----------\n----------------------------------------------\n"; system("$pdflatex -jobname=$filename_noext \"$latex{'ini'}".'\RequirePackage{etoolbox}\PassOptionsToPackage{active,mouseover,movetips,filename=minimal,'.$fancy_options.'}{fancytooltips}\AtEndPreamble{\usepackage{fancytooltips}'.$hypersetup.'}\input '.$filename.'"') } foreach my $deletefile (@tempfilenames) {unlink ($deletefile);} print "\n ---------------------------------------------\n fancy-preview with options \"$fancy_options\" on \"$filename\" finished \n The output is in $filename_noext.pdf \n\n If the pdf file is too large, consider pdfcrop option\n and http://tex.stackexchange.com/questions/42236/pdfcrop-generates-larger-file\n ---------------------------------------------\n\n"; sub parse_aux_file_and_crop { # opens aux file, finds lines starting with \newlabel and not involving tocindent and writes them into tmp file open(AUX, $aux_file); my @aux_data=; my @filtered_data_tmp = grep /^\\newlabel/, @aux_data; my @filtered_data = grep !/tocindent/, @filtered_data_tmp; my $aux_file_a=$filename_noext."-".@_[0].".tmp"; open(AUXA, ">$aux_file_a"); foreach my $aa (@filtered_data) { $aa =~ s/\\newlabel{/\\fancypreviewnewlabel{/; print AUXA $aa; } close (AUXA); close (AUX); push(@tempfilenames,$aux_file_a); # crops the file print "\nCropping PDF file, this may take some time ...\n"; system("$pdfcrop $filename_noext.pdf $filename_noext-@_[0]-crop.pdf"); push(@tempfilenames,"$filename_noext-@_[0]-crop.pdf"); } sub compile_parse_aux_file_and_crop { unlink ("$filename_noext.aux"); system("$pdflatex \"$latex{ini} \\input $filename\""); optbibtex(); system("$pdflatex \"$latex{ini} $latex{$_[0]} \\input $filename\""); parse_aux_file_and_crop($_[0]); } sub optbibtex { # runs bibtex and pdflatex if biblatex has been detected ($biblatex variable is 1) if ($biblatex) { system("$bibtex $filename_noext.aux"); system("$pdflatex \"$latex{ini} \\input $filename\""); } }