Bywa że klient przysyła Ci treści do umieszczenia na stronie z krótkim komentarzem – „Tak to sobie wyobrażam”. Otwierasz maila i widzisz plik PDF. Są tam pięknie ułożone teksty okraszone kolorowymi fotografiami, wszystko elegancko poukładane i skomponowane, a Ty drapiesz się w głowę i nic nie mówisz bo szkoda słów. Jeśli jesteś webdeveloperem, specjalistą od cięcia i stylowania to szczerze Ci współczuję. Jeśli jednak Twoim jedynym zadaniem jest wydobycie z tego PDF-a wszystkich tekstów oraz grafik to jest nadzieja.
Klikacze lub marzyciele często patrzący w „okna” mogą skorzystać z jednej z rad proponowanych w artykule How to Extract Text from a PDF document lub How Can I Get Text or Images Out of a PDF File?. Alternatywą jest użycie konsoli i wierzcie mi w tym przypadku jest to o wiele wygodniejsze i szybsze rozwiązanie.
Do wyłuskania tekstów używamy programu „pdftotext” będącego częścią programu „xpdf”
Gdyby były problemy z polskimi literami warto zapoznać się z opcją „enc”:
pdftotext -enc Latin2 dokument.pdf |
pdftotext -enc Latin2 dokument.pdf
albo
pdftotext -enc UTF-8 dokument.pdf |
pdftotext -enc UTF-8 dokument.pdf
Z obrazkami robimy identycznie tylko, że używając programu „pdfimages” także będącego konsolowym narzędziem „xpdf-a”
pdfimages ./dokument.pdf przedrostek_obrazka |
pdfimages ./dokument.pdf przedrostek_obrazka
Program „pdfimages” zapisuje obrazki w formacie plików „ppm” więc trzeba je jeszcze przekonwertować do jpg-ów np. przy pomocy programu „pnmtojpeg” będącego częścią większego pakietu programów graficznych „Netpbm„.
for pic in *.ppm
do
pnmtojpeg "${pic}" > "${pic/%ppm/jpg}"
done |
for pic in *.ppm
do
pnmtojpeg "${pic}" > "${pic/%ppm/jpg}"
done
O ile programy „pdftotext” jak i „pdfimages” miałem już w systemie to „pnmtojpeg” trzeba było doinstalować i kiedy już to zrobiłem i przetestowałem przypomniałem sobie, że mam przecież zainstalowanego „ImageMagick-a„, którego użycie okazało się jeszcze prostsze.
mogrify -format jpg *.ppm |
mogrify -format jpg *.ppm
Pliki wynikowe uzyskane po zastosowaniu „mogrify” są większe co sugeruje mniejszą stratę na jakości, poza tym jak się ma „ImageMagick-a” to można z tymi plikami zrobić przy okazji dużo więcej np. automatycznie przeskalować, utworzyć miniatury, dodać ramki czy co nam tam jeszcze przyjdzie do głowy. Tworząc skrypt, który wszystkie wyżej przytoczone komendy zbiera w jedną zdecydowałem się właśnie na „mogrify”.
Plik extractpdf.sh
#!/bin/sh
if [ $# -lt 1 ]; then
echo "Usage: `basename $0` file.pdf"
exit 1;
fi
PDF=$1
FILE_NAME=`basename ${PDF%.*}`
TEMP_DIR="`dirname $PDF`/${FILE_NAME}"
if [ ! -e $TEMP_DIR ]; then
mkdir -p $TEMP_DIR;
fi
pdftotext $PDF "${TEMP_DIR}/${FILE_NAME}.txt"
pdfimages $PDF "${TEMP_DIR}/${FILE_NAME}"
mogrify -format jpg ${TEMP_DIR}/*.ppm
find ${TEMP_DIR}/ -name "*.ppm" -exec rm {} \; |
#!/bin/sh
if [ $# -lt 1 ]; then
echo "Usage: `basename $0` file.pdf"
exit 1;
fi
PDF=$1
FILE_NAME=`basename ${PDF%.*}`
TEMP_DIR="`dirname $PDF`/${FILE_NAME}"
if [ ! -e $TEMP_DIR ]; then
mkdir -p $TEMP_DIR;
fi
pdftotext $PDF "${TEMP_DIR}/${FILE_NAME}.txt"
pdfimages $PDF "${TEMP_DIR}/${FILE_NAME}"
mogrify -format jpg ${TEMP_DIR}/*.ppm
find ${TEMP_DIR}/ -name "*.ppm" -exec rm {} \;
Skrypt oszczędza masę pisania poza tym jest uniwersalny więc nadaje się do wielokrotnego użytku. Teraz wystarczy nadać mu prawa do wykonywania
i cała praca to wywołanie skryptu z podaniem ścieżki do pliku pdf w parametrze
./extractpdf.sh ./dokument.pdf |
./extractpdf.sh ./dokument.pdf
Można pokusić się o rozbudowę tego skryptu o sprawdzanie czy wymagane programy są zainstalowane oraz zwiększyć funkcjonalność poprzez próbę użycia „pnmtojpeg” w przypadku jeśli „ImageMagick” nie jest zainstalowany.
Plik extractpdf2.sh
#!/bin/bash
if [ $# -lt 1 ]; then
echo "Usage: `basename $0` file.pdf"
exit 1;
fi
type -P pdftotext &>/dev/null || { echo "I require pdftotext but it's not installed. Aborting." >&2; exit 1; }
type -P pdfimages &>/dev/null || { echo "I require pdfimages but it's not installed. Aborting." >&2; exit 1; }
if type -P mogrify >/dev/null; then
CONVERTER="mogrify"
else
type -P pnmtojpeg &>/dev/null || { echo "I require the mogrify or pnmtojpeg but none of them is not installed. Aborting." >&2; exit 1; }
CONVERTER="pnmtojpeg"
fi
PDF=$1
FILE_NAME=`basename ${PDF%.*}`
TEMP_DIR="`dirname $PDF`/${FILE_NAME}"
if [ ! -e $TEMP_DIR ]; then
mkdir -p $TEMP_DIR;
fi
pdftotext $PDF "${TEMP_DIR}/${FILE_NAME}.txt"
pdfimages $PDF "${TEMP_DIR}/${FILE_NAME}"
if [ $CONVERTER = 'mogrify' ]; then
mogrify -format jpg ${TEMP_DIR}/*.ppm
find ${TEMP_DIR}/ -name "*.ppm" -exec rm {} \;
else
for PIC in ${TEMP_DIR}/*.ppm
do
pnmtojpeg "${PIC}" > "${PIC/%ppm/jpg}"
rm $PIC
done
fi |
#!/bin/bash
if [ $# -lt 1 ]; then
echo "Usage: `basename $0` file.pdf"
exit 1;
fi
type -P pdftotext &>/dev/null || { echo "I require pdftotext but it's not installed. Aborting." >&2; exit 1; }
type -P pdfimages &>/dev/null || { echo "I require pdfimages but it's not installed. Aborting." >&2; exit 1; }
if type -P mogrify >/dev/null; then
CONVERTER="mogrify"
else
type -P pnmtojpeg &>/dev/null || { echo "I require the mogrify or pnmtojpeg but none of them is not installed. Aborting." >&2; exit 1; }
CONVERTER="pnmtojpeg"
fi
PDF=$1
FILE_NAME=`basename ${PDF%.*}`
TEMP_DIR="`dirname $PDF`/${FILE_NAME}"
if [ ! -e $TEMP_DIR ]; then
mkdir -p $TEMP_DIR;
fi
pdftotext $PDF "${TEMP_DIR}/${FILE_NAME}.txt"
pdfimages $PDF "${TEMP_DIR}/${FILE_NAME}"
if [ $CONVERTER = 'mogrify' ]; then
mogrify -format jpg ${TEMP_DIR}/*.ppm
find ${TEMP_DIR}/ -name "*.ppm" -exec rm {} \;
else
for PIC in ${TEMP_DIR}/*.ppm
do
pnmtojpeg "${PIC}" > "${PIC/%ppm/jpg}"
rm $PIC
done
fi
UWAGA!!! Użycie „type -P” wymaga skorzystania konkretnie z powłoki „bash” gdyż w „sh” program „type” nie ma opcji „-P” i traktuje ją jak ścieżkę do pliku co kończy się komunikatem błędu (-P: not found). Dlatego pomimo, że plik dalej nazywa się extractpdf.sh to zamiast „#!/bin/sh” należy wpisać „#!/bin/bash”.
To oczywiście nie wyczerpuje naszych możliwości. Zaproponowane przeze mnie narzędzie to niezbędne minimum. Stworzenie tego skryptu kosztowało mnie trochę czasu ale jest to praca jednorazowa. Podobnie miałem ze skryptem do generowania miniatur za to obecnie stale mam go w swoim arsenale i wierzcie mi, że suma sumarum zaoszczędził mi już naprawdę wiele czasu.