1

I installed a2ps on Mac OS X 10.10.4 via brew. My ~/.a2psrc contains Options: --medium=Letter -P pdf. But when I do a2ps foo.txt no PDF file is generated (this used to work on Ubuntu/Debian Linux). When I do a2ps -o foo.pdf foo.txt I get a PDF, but it cannot be opened (maybe it is corrupted?). However, on a2ps -o foo.pdf foo.txt I get a PS which I can then convert to PDF (and open). How can I make a2ps foo.txt to produce a valid PDF on Mac OS X? Note that I'm looking specifically for the command line a2ps, no GUI or other programs (obviously it's easy to generate a PDF from a text file with other tools)

3
  • 2
    Does man a2ps or info a2ps answer your question? – fd0 Jul 21 '15 at 12:54
  • @Marius Hofert, Please checkout my updated answer as I've added info for installing a2pdf which will create PDF Documents from Text Documents via the Command Line in Terminal. – user3439894 Jul 21 '15 at 14:14
  • @fd0 No, but user3439894 explanation helped. – Marius Hofert Jul 21 '15 at 17:27
4

The a2ps utility is for formatting files for printing on a PostScript printer, hence its name is not a2pdf.

The file you created under Linux (or OS X), which is a miss-named .pdf file, is in fact a PostScript file and many Linux Distros will open it anyway. Thus leading you to believe is was a PDF Document when in reality it's not.

Looking at the file created under Linux in a Hex Editor its header starts off with, e.g., %!PS-Adobe-3.0 and a PDF Document starts with, e.g., %PDF-1.6%.

This is why you get the "The file “filename.pdf” could not be opened. It may be damaged or use a file format that Preview doesn’t recognize." error message under OS X when trying to open a PostScript Document with a miss-named PDF Document extension.

Update: Installing a2pdf

After doing a little research I found a2pdf. Further research required having Font::TTF::Font and PDF::API2 also installed. So I downloaded all three packages master.zip (for a2pdf), Font-TTF-1.04.tar.gz and PDF-API2-2.023.tar.gz.

Next I extracted all three and installed them in the same manner in the following order, Font::TTF::Font, PDF::API2 then the master.zip (for a2pdf). I did this in a Terminal using the following commands.

$ cd $target_directory
$ perl Makefile.PL
$ make
$ sudo make install

I then tested, from my Home Directory, with: a2pdf filename.txt > filename.pdf

It create filename.pdf and I then opened it in Preview just fine as a PDF Document.

That said, there are other modules that can be installed to do things like syntax highlighting, e.g. Perl::Tidy. So you'll need to do a bit more research to utilize the full capabilities of a2pdf.

Note: I have Xcode and Command Line Tools for Xcode installed and as long as you have Command Line Tools for Xcode installed, which is a Homebrew prerequisite, you can install all of this from the Terminal the old fashioned way if not available from Homebrew, which I do not believe it is.

1
  • Thanks, that's very informative. I didn't know that Linux 'tricked' me here... – Marius Hofert Jul 21 '15 at 17:25
1

This can be done as follows:

  1. Save text file in UTF-8 encoding, even though `a2ps supports Latin1 only (This is done mainly because UTF-8 is standard nowadays.)
  2. Convert text file to Latin1, using recode
  3. Call a2ps on the result
  4. Convert resulting PS file to PDF, using ps2pdf from LaTeX installation
  5. Optionally, use gs to convert the resulting PDF to PDF-1.3 to reduce its file size
  6. Copy the PDF-1.3 back to the directory the text file lives in

In Linux, this can be done by the following script.

The simplest way of calling it is txt2pdf file.txt, assuming it is saved under ~/bin/txt2pdf or some other standard location. It produces file.txt.pdf

 #!/bin/bash

 maketempdir () {
     local result
     if ! result="$(mktemp -d)"; then
         fail 'Cannot create temp directory'
     fi
     echo "$result"
 }

 trycd () {
     if [ "$#" -ne 1 ]; then
         fail 'trycd needs exactly one argument'
     fi

     if ! cd "$1" ; then
         debugoutput 'tried to cd to '"$(readlink -f "$1")"
         fail 'cannot cd to '"$1"
     fi
 }

 fail () {
     #
     # print an error message, then exit with a code
     #
     # $1: error message
     # $2: exit code
     #
     if [ -z "$1" ]; then fail 'Unspecified error' '1'; fi
     if [ -z "$2" ]; then fail "$1" '1';                fi
     yellow "$(bold "$(printf '\n!!!!! %s\n\n' "$1")")" >&2
     sleep 0.2
     exit "$2"
 }

 yellow() {
     local yellow='\e[0;93m'
     local normal='\e[0m'
     echo -ne "${yellow}"    # echo -n: Kein Zeilenumbruch am Ende
     echo -nE "$@"           # echo -e: Escape-Sequenzen interpretieren
     echo -e "${normal}"     # echo -E: Escape-Sequenzen nicht interpretieren
 }

 # tput zu benutzen wäre nicht schlecht. Damit kriegt man aber nur ein
 # blasses Gelb und kein Kanariengelb hin.
 # Außerdem werden Zeilenumbrüche verschluckt, vermutlich wegen des
 #    echo -nE "$@"

 bold() {
     local bold=$(tput bold)
     local normal=$(tput sgr0) 
     echo -ne "${bold}"        # auf Fettschrift umschalten
     echo -nE "$@"             # Text ausgeben
     echo -e "${normal}"       # auf normale Schrift umschalten
 }

 # http://stackoverflow.com/questions/5947742/
 # how-to-change-the-output-color-of-echo-in-linux
 # 2017-01-07

 debugoutput() {
     if [ "$#" -ne 1 ]; then
         fail 'debugoutput needs exactly one argument'
     fi
     printf '%s\n' "$1" >&2
 }


 tempdir="$(maketempdir)"
 readonly tempdir

 wd=$(readlink -e $(pwd))
 readonly wd

 trycd "$dir"
 trycd "$wd"

 orientation=null
 verbose=null

 case "$#" in

     1)
         exec "$0" --portrait "$1"
         ;;

     2)
         ## 1. Fall: "$1" ist --verbose, "$2" ist die Eingabedatei
         ## 2. Fall: "$1" ist die Ausrichtung, "$2" ist die Eingabedatei

         case "$1" in

             --verbose)
                 orientation='--portrait'
                 verbose=true
                 ;;
             --portrait|--landscape)
                 orientation="$1"
                 verbose=false
                 ;;
             *)
                 fail 'Erster Parameter muss Ausrichtung angeben oder --verbose lauten'
                 ;;
         esac
         infile="$2"
         ;;

     3)

         case "$1" in

             --portrait|--landscape)
                 orientation="$1"
                 ;;
             *)
                 fail 'Erster Parameter muss Ausrichtung angeben'
                 ;;
         esac

         case "$2" in            
             --verbose)
                 orientation="$1"
                 verbose=true
                 ;;
             *)
                 fail 'Zweiter Parameter muss --verbose lauten'
                 ;;
         esac

         infile="$(readlink -e "$3")"

         if [ -z "$infile" ]; then
             fail 'Eingabedatei '"$3"' existiert nicht'
         fi

         if [ ! -f "$infile" ]; then
             fail 'Eingabedatei '"$infile"' existiert nicht'
         fi
         ;;

     *)
         cat <<EOF
 Usage: $0 dateiname
 Usage: $0 [--portrait | --landscape] dateiname
 Usage: $0 --verbose dateiname
 Usage: $0 [--portrait | --landscape] --verbose dateiname
 EOF
         exit 1
         ;;
 esac

 readonly infile
 # readonly orientation # später
 readonly verbose
 # echo 'orientation='"$orientation"
 # echo 'verbose='"$verbose"
 # echo 'infile='"$infile"

 ###### 1. Schritt: Eingabedatei nach latin1 konvertieren

 bn=$(basename "$infile")
 tempfilename="$tempdir"'/'"$bn"'.txt' # will be latin1 after recode
 if ! cp -a "$infile" "$tempfilename"; then
     fail 'Cannot copy '"$bn"' to tempdir'
 fi

 if ! recode UTF-8..Latin1 "$tempfilename"; then
     fail 'Cannot recode '"$tempfilename"' from UTF-8 to Latin1' 
 fi

 psout="${tempfilename%.*}"'.ps'

 ###### 2. Schritt: a2ps aufrufen

 case "$orientation" in

     --portrait)
         a2ps -q -Eplain -R --encoding=latin1 --columns=1 -l 85 -o "$psout" "$tempfilename"
         ;;

     --landscape)
         a2ps -q -Eplain -r --encoding=latin1 --columns=1 -l 115 -o "$psout" "$tempfilename"
         ;;

 esac

 ###### 3. Schritt: ps nach PDF konvertieren

 pdfout="${psout/.ps/.pdf}"

 if ! ps2pdf "$psout" "$pdfout"; then
     fail 'Konnte PS nicht nach PDF konvertieren'
 fi

 ###### 4. Schritt: Erzeugte PDF-Datei so klein wie möglich machen

 smallout="${pdfout/.pdf/.small.pdf}"
 out="${smallout/.small/}"

 if ! gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.3 -dNOPAUSE\
      -dQUIET -dBATCH -sOutputFile="$smallout" "$pdfout"
 then
     fail 'Konnte PDF-Datei nicht verkleinern'
 fi

 if ! mv -f "$smallout" "$out"; then
     fail 'Konnte Ausgabedatei nicht erstellen'
 fi

 ###### 5. Schritt: PDF in das Verzeichnis kopieren, in dem die Eingabedatei liegt

 if ! cp -a "$out" "$wd"; then
     fail 'Konnte Ausgabedatei nicht in Eingabeverzeichnis schreiben'
 fi

 if [ "$verbose" = 'true' ]; then
     echo "$wd"/"$(basename "$out")"
 fi

 if ! rm -rf "$tempdir"; then
     fail 'Konnte temporäres Verzeichnis nicht löschen'
 fi

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .