Tuesday, November 6, 2007

Merge PDF documents with LaTeX

Sometimes, a single book comes in multiple PDF documents, one document for a chapter. I often want to merge these PDF document into one single document. There are several possibilites, e.g. using Adobe Acrobat. A less expensive and yet easy solution is to use LaTeX for that purpose. So I have created a simple LaTeX template in which I only have to add the names of the documents to be merged., that's it. Besides, several options are available such as scaling the documents on the fly. The work is done by the LaTex package "pdfpages", see pdfpages at www.ctan.org. The documents are included with \includepdf, the two lines above this command are used here for creating a table of content in the PDF.

%!TEX encoding = UTF-8 Unicode
% -------+---------+---------+---------+---------+---------+---------+---------+
\documentclass{book}
% -------+---------+---------+---------+---------+---------+---------+---------+
% Used Packages
% -------+---------+---------+---------+---------+---------+---------+---------+
\usepackage[pdftex,dvips]{graphicx}
\usepackage[english]{babel}
\usepackage[
 pdfhighlight=/O, colorlinks, linkcolor=black, urlcolor=black, citecolor=black,
 breaklinks, bookmarksopen,bookmarksopenlevel=1,linktocpage
] {hyperref}
\usepackage{fancyhdr}
\usepackage{pdfpages} % That does the trick!
% -------+---------+---------+---------+---------+---------+---------+---------+
% Header
% -------+---------+---------+---------+---------+---------+---------+---------+
\pagestyle{headings}
\pagestyle{fancy}
\fancyhead{}
\fancyfoot{}
%\fancyfoot[LE,RO]{\raisebox{-25mm}{\large\textsf{\thepage}}}
%\fancyfoot[RE,LO]{\raisebox{-25mm}{Merged Document}}
%\fancyfoot[CE,CO]{\raisebox{-25mm}{}}
\renewcommand{\headrulewidth}{0mm}
\renewcommand{\footrulewidth}{0mm}
% -------+---------+---------+---------+---------+---------+---------+---------+
% Settings for including the PDF documents,
% see: 
% http://www.ctan.org/tex-archive/macros/latex/contrib/pdfpages/pdfpages.pdf
% -------+---------+---------+---------+---------+---------+---------+---------+
\includepdfset{pages=-,nup=1x1, pagecommand={\mbox{}}}
% -------+---------+---------+---------+---------+---------+---------+---------+
% The Documents
% -------+---------+---------+---------+---------+---------+---------+---------+
\begin{document}

\phantomsection 
\addcontentsline{toc}{chapter}{Chapter 1}
\includepdf{file1.pdf}

\phantomsection 
\addcontentsline{toc}{chapter}{Chapter 2}
\includepdf{file2.pdf}

% ...

% -------+---------+---------+---------+---------+---------+---------+---------+
\end{document}

Wednesday, August 1, 2007

Shell Script as Startup Item

In my office I'm working with a PC and a Mac. I have two screens (one for the PC, one for the Mac) -- but only one mouse and one keyboard. This is possible with Synergy. This is a client-server tool sending mouse and keyboards events over the network. In order to make this work, I have to start a server on one machine -- I've decided to use the Mac as the server. Since I only need Synergy at work, I wanted to start the server only when I'm at work. Fortunately I've got a static IP address, so I can check with ifconfig and grep whether I'm in my office or not. This is my shell script:

#!/bin/bash
if ifconfig | grep my.static.ip.address
then 
/Applications/synergy-1.3.1/synergys --config /path/to/my/synergy.conf
echo At Work! Synergy started
exit
else echo Not at work!
fi
I want to execute this script as a startup item. First, I simply started the script via the terminal application. But in this case the Terminal.app is started and remains open. I didn't want that. So I wrote a small AppleScript simply starting the shell script. I saved this AppleScript as an application, and now the shell script is executed as a startup but almost invisible. The problem of using a shell script as a startup item is a common one, and the solution is very simple. This is the AppleScript:

do shell script "'/path/to my/shell/script.sh'"
Note that there is a litte trick in this line: The path to my script contains a space. So I have to "double quote" the path with " and '. See also: Apple Developer Connection: Technical Note TN2065

Tuesday, February 20, 2007

SMB over SSH tunnel setup

Sometimes I need access to a SMB server. This SMB server is hidden behind the company's firewall and the only way to get behind the firewall is a SSH server. So you need a so called SSH tunnel to connect your machine (outside the firewall) with the SMB server (inside the firewall). To establish the connection, you need the following information:
  • Name of SSH-server and an account on that server
  • Name of SMB-server and an account on that server
  • Of course, you'll need to know which folder you want to access
The following steps install a SMB connection over a SSH tunnel. I've tested these steps using Mac OS X.
Step 1: Install SSH tunnel
The shell command is simply ssh -N -l username_on_ssh_server -L 139:smb_server:139 ssh_server You may call this line using sudo. After starting the tunnel, it's like you have an SMB-server running on your local machine listening on port 139 (which is the SMB port).
Step 2: Mount SMB on localhost
You can simply mount a SMB folder on your local machine by mount_smbfs -I localhost -U username_win_domain//smb_server_name/remote_folder local_folder This line mounts a folder on the smb server to your local file system.
Example: Assume the ssh-server is "ssh.test.com", the smb-server is "smb.test.com", your user name on ssh.test.com is "jdoe" and you want to mount the remote folder "project" to your local folder "company". Your user name on smb.test.com is "JohnDoe". ssh -N -l jdoe -L 139:smb.test.com:139 ssh.test.com and (in a new terminal window) mount_smbfs -I localhost -U JohnDoe//smb/projects company Some notes on the Finder: After mounting the folder from command line, it is possible that the Finder does not recognize the mounted folder. Browser your file system with the folder to open the folder. Sometime it happes (at least on my system) that the mounted folder cannot be seen in the finder windows. Then I have to open the folder with Cmd-Shift-G. Unmounting the folder also does not work with the finder, you will have to call umount company in the example and restart the finder (Ctrl-Mod click on Finder icon in dock) to remove the icon of the network folder from the desktop.

AppleScript: Convert OmniGraffle documents to PDF

The following AppleScript converts all selected OmniGraffle drawings (*.graffle) to PDF. It is based on Greg Titus's script published here. While Greg's script watches a folder, this script simply converts all selected files. Note: There's no error handling and you may want to change the export settings. If you have CocoThumbX installed, you may want to uncomment line where sub routine "createThumb" is called and change the path to CocoThumbX.
-- converts selected OmniGraffle files to PDF -- based on Greg Titus's script found at -- http://forums.omnigroup.com/showthread.php?t=106&highlight=export+applescript -- -- by jevopi, 2007 tell application "Finder" set these_items to the selection end tell repeat with i from 1 to the count of these_items set this_item to (item i of these_items) as alias set this_info to info for this_item -- insert actions here for: this_item set item_path to POSIX path of this_item set item_folder to (parent of (item i of these_items)) as string set item_name to name of (item i of these_items) set item_ext to name extension of (item i of these_items) set exp_name to my rename(item_name, item_ext, "pdf") set exp_path to item_folder & exp_name set msg to "Path: " & item_path & ", Exp: " & exp_path --display dialog msg buttons {"OK"} default button 1 my omniConvert(this_item, item_path, exp_path) -- Uncomment this line if you have CocoThumb installed -- my createThumb(exp_path) end repeat -- create icon with CocoThumbX on createThumb(exp_path) set theApplication to Drive:Applications:Tools:CocoThumbX" set theFile to alias exp_path tell application "Finder" open theFile using theApplication end tell end createThumb -- this sub-routine just comes up with the new name on rename(item_name, item_ext, new_extension) tell application "Finder" if the item_ext is "" then set the trimmed_name to the file_name else set the trimmed_name to text 1 thru -((length of item_ext) + 2) of the item_name end if set target_name to (the trimmed_name & "." & new_extension) as string end tell return the target_name end rename -- this sub-routine does the export on omniConvert(source_file, source_path, target_path) with timeout of 900 seconds tell application "OmniGraffle" -- save the current export settings so we can replace them later set oldAreaType to area type of current export settings set oldBorder to include border of current export settings set oldBackground to draws background of current export settings -- here is where you set the export settings you want set area type of current export settings to all graphics set include border of current export settings to false set draws background of current export settings to false -- open the file if it isn't already open set needToOpen to (count (documents whose path is source_path)) is 0 if needToOpen then open source_file end if -- do the export set docsWithPath to documents whose path is source_path set theDoc to first item of docsWithPath save theDoc in file target_path -- if the file wasn't already open, close it again if needToOpen then close theDoc end if -- put the original export settings back set area type of current export settings to oldAreaType set include border of current export settings to oldBorder set draws background of current export settings to oldBackground end tell end timeout end omniConvert