Created
March 24, 2022 03:05
-
-
Save goerz/bdb599011e4a9c8e7ae59de5c54cb065 to your computer and use it in GitHub Desktop.
Python script for extracting textblocks from Beamer presentations
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
"""Extract textblocks from a Beamer presentation. | |
This is useful for making Powerpoint slides from Beamer presentations. | |
""" | |
import logging | |
import click | |
from pathlib import Path | |
PREAMBLE = r"""\documentclass[compress, aspectratio=169]{beamer} | |
\usepackage[utf8]{inputenc} | |
\usepackage{braket} | |
\newcommand{\identity}[0]{\mathbf{1}} | |
\newcommand{\Op}[1]{\ensuremath{\mathsf{\hat{#1}}}} | |
\newcommand{\Abs}[1]{\left|#1\right|} | |
\newcommand{\AbsSq}[1]{\left|#1\right|^2} | |
\newcommand{\Norm}[1]{\left\lVert#1\right\rVert} | |
\newcommand{\NormSq}[1]{\Norm{#1}^2} | |
\newcommand{\tr}{\mathrm{tr}} | |
\newcommand{\Tr}{\mathrm{tr}} | |
\newcommand{\SU}{\ensuremath{\text{SU}}} | |
\newcommand{\ketbra}[2]{\ket{#1}\!\bra{#2}} | |
\newcommand{\mirror}{\text{mirror}} | |
\newcommand{\tgt}{\text{tgt}} | |
\newcommand{\pop}{\operatorname{pop}} | |
\newcommand{\dd}{\mathrm{d}} | |
\newcommand{\ii}{\mathrm{i}} | |
\newcommand{\Integers}{\mathbb{Z}} | |
\renewcommand{\Re}{\mathrm{Re}} | |
\renewcommand{\Im}{\mathrm{Im}} | |
\newcommand{\partdifquo}[2][{}]{\frac{\partial #1}{\partial #2}} | |
\newcommand{\Complex}{\mathbb{C}} | |
\usepackage{textcomp} % provides \textmu | |
\usepackage{tikz,pgflibraryshapes} | |
\usepackage{hyperref} | |
\usepackage{fontawesome} | |
\usetikzlibrary{arrows.meta, calc, decorations.pathmorphing, backgrounds, positioning} | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Grid %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
% Set up grid for absolute text positioning (page size = 16 x 9 cm) | |
\usepackage[absolute, overlay]{textpos} % (add `showboxes` for debugging) | |
%\usepackage[absolute, overlay, showboxes]{textpos} % (add `showboxes` for debugging) | |
\textblockorigin{0cm}{0cm} % The grid guides start from top left | |
\setlength{\TPHorizModule}{1cm} % Units are 1 cm ... | |
\setlength{\TPVertModule}{1cm} % ... and y coordinates point down | |
% Now you can use e.g.: | |
% \begin{textblock}{3}(4,2) | |
% \dots | |
% \end{textblock} | |
% to place a block 3cm wide, 4cm right and 2cm up from the bottom left corner | |
%%%%%%%%%%%%%%%%%%%%%%%%%%% Theme Settings %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
\definecolor{DarkBlue}{rgb}{0.1,0.1,0.5} | |
\definecolor{DarkRed}{rgb}{0.75,0.,0.} | |
\definecolor{Magenta}{rgb}{1.0,0.0,1.0} | |
\definecolor{Red}{rgb}{0.894,0.102,0.110} | |
\definecolor{Green}{rgb}{0.302,0.686,0.290} | |
\definecolor{Blue}{rgb}{0.216,0.494,0.722} | |
\definecolor{Orange}{rgb}{1.000,0.498,0.000} | |
\definecolor{Yellow}{rgb}{0.824,0.824,0.082} | |
\definecolor{Brown}{rgb}{0.651,0.337,0.157} | |
\definecolor{LightBlue}{rgb}{0.651,0.808,0.890} | |
\definecolor{Purple}{rgb}{0.596,0.306,0.639} | |
\definecolor{LightPurple}{rgb}{0.792,0.698,0.839} | |
\definecolor{Grey}{rgb}{0.600,0.600,0.600} | |
\definecolor{LightGreen}{rgb}{0.698,0.875,0.541} | |
\definecolor{LightOrange}{rgb}{0.992,0.749,0.435} | |
\definecolor{Pink}{rgb}{0.969,0.506,0.749} | |
\definecolor{Black}{rgb}{0.000,0.000,0.000} | |
\definecolor{LightRed}{rgb}{0.984,0.604,0.600} | |
\definecolor{White}{rgb}{1.000,1.000,1.000} | |
\definecolor{ARLGray25}{rgb}{0.698,0.698,0.698} | |
%%%%%%%%%%%%%%%%%%%%%%%%%%% Theme Settings %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
\usetheme{Berlin} | |
\useoutertheme{shadow} | |
\useinnertheme{default} | |
\setbeamercolor{palette primary}{use=structure,fg=black,bg=black!20!white} | |
\setbeamercolor{palette secondary}{use=structure,fg=black,bg=black!25!white} | |
\setbeamercolor{palette tertiary}{use=structure,fg=black,bg=black!30!white} | |
\setbeamercolor{palette quaternary}{use=structure,fg=black,bg=black!35!white} | |
\setbeamercolor{sidebar}{use=structure,bg=structure.fg!20!white} | |
\setbeamercolor{palette sidebar primary}{use=normal text,fg=normal text.fg} | |
\setbeamercolor{palette sidebar secondary}{use=structure,fg=structure.fg} | |
\setbeamercolor{palette sidebar tertiary}{use=normal text,fg=normal text.fg} | |
\setbeamercolor{palette sidebar quaternary}{use=structure,fg=structure.fg} | |
\setbeamercolor*{titlelike}{parent=palette primary} | |
\setbeamercolor*{separation line}{} | |
\setbeamercolor*{fine separation line}{} | |
\setbeamertemplate{blocks}[rounded][shadow=false] | |
\setbeamerfont{title}{family*=phv, size*={20}{24}} | |
\setbeamerfont{author}{family*=phv, size*={12}{14}} | |
\setbeamerfont{institute}{family*=phv, size*={8.0}{12}} | |
\setbeamerfont{date}{family*=phv, size*={8.0}{12}} | |
\setbeamerfont{classification}{family*=phv, size*={3.78}{4.5}} | |
\setbeamerfont{frametitle}{series=\bfseries, family*=phv, size*={11.34}{14}} | |
\defbeamertemplate*{title page}{customized}[1][]{} | |
\setbeamertemplate{background canvas}{} | |
\setbeamertemplate{headline}{} | |
\setbeamertemplate{footline}{} | |
\setbeamertemplate{frametitle}{} | |
\usefonttheme[onlysmall]{structurebold} | |
\setbeamertemplate{bibliography item}{% | |
\lower2pt\hbox{\pgfuseimage{beamericonarticle}}\insertbiblabel} | |
\mode<presentation>{\beamertemplatenavigationsymbolsempty} | |
%\setbeamercolor{block title}{use=structure,fg=white,bg=red!75!black} | |
%\setbeamercolor{block body}{use=structure,fg=black,bg=red!20!white} | |
\newcommand{\subhead}[1]{{\bf \color{DarkBlue} #1}} | |
\newcommand{\mycircledTerm}[1]{\raisebox{-0.6ex}{\textcircled{\scriptsize #1}}} | |
\newcommand{\mycircled}[1]{\textcircled{\scriptsize #1}} | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
\begin{document} | |
""" | |
POSTAMPLE = r""" | |
\end{document} | |
""" | |
@click.command() | |
@click.help_option('--help', '-h') | |
@click.option('--debug', is_flag=True, | |
help='enable debug logging') | |
@click.argument("infile", type=click.File('r')) | |
@click.argument("outfile", type=click.File('w')) | |
def main(debug, infile, outfile): | |
"""Extract textblocks""" | |
logging.basicConfig(level=logging.WARNING) | |
logger = logging.getLogger(__name__) | |
if debug: | |
logger.setLevel(logging.DEBUG) | |
logger.debug("Enabled debug output") | |
outfile.write(PREAMBLE) | |
in_textblock = False | |
for line in infile: | |
if line.strip().startswith(r"\begin{textblock}"): | |
outfile.write(r"\begin{frame}"+"\n") | |
in_textblock = True | |
if line.strip().startswith(r"\end{textblock}"): | |
outfile.write(line) | |
outfile.write(r"\end{frame}"+"\n\n\n") | |
in_textblock = False | |
if in_textblock: | |
outfile.write(line) | |
outfile.write(POSTAMPLE) | |
click.echo(f"Written to {outfile.name}", err=True) | |
click.echo(f"You can compile with with (pdf)latex", err=True) | |
pdffile = Path(outfile.name).with_suffix(".pdf") | |
click.echo(f"You may split the resulting pdf into pages with e.g. `pdfseparate {pdffile} blocks/%03d.pdf`", err=True) | |
click.echo(f"You can then crop each page with `pdfcrop`", err=True) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment