pics2photodoc.sh

A script that creates a »slideshow« in PDF/A format, from a directory of numbered and named images.

Requires:

  • convert imagemagick
  • gs ghostscript

The script sorts the image sequence according to their respective number at the beginning of the file name, and uses the rest of the file names to create a clickable »table of content« (PDF bookmarks). All images will be resized to fit inside a given rectangle, at the given resolution.

Numbering and naming of the files should follow a pattern like

  • 100 Title A.jpg
  • 200 Title B.jpg
  • 300 Title C.jpg

Hint: Using steps of e.g. 100 makes reordering, or later addition of more images easier.

How to call it:

pics2photodoc.sh [-t title] [-d dpi] [-q imageQuality] [-i inputDir] [-o outputFile] [-l maxLongSideMillimeters] [-l maxShortSideMillimeters]

E.g., using the default values:

pics2photodoc.sh -t "Photo Documentation" -d 150 -q 90 -i . -o photodocumentation -s 210 -l 297
To download this script, first hover with your mouse over the listing below and press »Open code in new window«. Copying and pasting the colored and formatted listing below, as-is, won’t work.
#!/bin/bash

dpi=150
input_dir=.
output_file=photodocumentation
max_short_mm=210
max_long_mm=297
title="Photo Documentation"
image_quality=90

while getopts ":d:i:l:o:s:t:q:" opt; do
  case $opt in
    d) dpi="$OPTARG"
    ;;
    i) input_dir="$OPTARG"
    ;;
    l) max_long_mm="$OPTARG"
    ;;
    o) output_file="$OPTARG"
    ;;
    s) max_short_mm="$OPTARG"
    ;;
    t) title="$OPTARG"
    ;;
    q) image_quality="$OPTARG"
    ;;
    \?) echo "Invalid option -$OPTARG" >&2
    echo "Usage:" >&2
    echo "$(basename $0) [-t title] [-d dpi] [-q imageQuality] [-i inputDir] [-o outputFile] [-l maxLongSideMillimeters] [-l maxShortSideMillimeters]"
    echo
    echo "Examples:"
    echo "$(basename $0)"
    echo "$(basename $0) -t \"$title\" -d $dpi -q $image_quality -i $input_dir -o $output_file -s $max_short_mm -l $max_long_mm"
    exit 1
    ;;
  esac
done
shift $((OPTIND-1))

echo "Executing: $(basename $0) -t \"$title\" -d $dpi -q $image_quality -i $input_dir -o $output_file -s $max_short_mm -l $max_long_mm"

TMP_DIR=$(mktemp -d /tmp/tmpdir.XXXXXXXXXXXX)
PDFMARK_FILE="$TMP_DIR/pdfmark.txt"
PHOTO_LIST="$TMP_DIR/photolist"

# Calculate maximum image size in Pixels
MAX_SHORT_PX=$(bc<<<"scale=5;$max_short_mm * 10 / 254 * $dpi + 1/2")
MAX_SHORT_PX=${MAX_SHORT_PX%.*}
MAX_LONG_PX=$(bc<<<"scale=5;$max_long_mm * 10 / 254 * $dpi + 1/2")
MAX_LONG_PX=${MAX_LONG_PX%.*}

echo
echo Output at $dpi dpi. Image sizes will be confined to ${MAX_SHORT_PX}x${MAX_LONG_PX}.

# Scale images and create pdfmark file for bookmarks
echo
echo "[ /Title ($title)" >> "$PDFMARK_FILE"
echo "/Creator ($(basename $0))" >> "$PDFMARK_FILE"
echo "/Subject ()" >> "$PDFMARK_FILE"
echo "/Keywords ()" >> "$PDFMARK_FILE"
echo "/DOCINFO pdfmark" >> "$PDFMARK_FILE"

echo "[ /PageMode /FullScreen" >> "$PDFMARK_FILE"
echo "/DOCVIEW pdfmark" >> "$PDFMARK_FILE"

echo "[ /Title ($title)" >> "$PDFMARK_FILE"
echo "/Page 1" >> "$PDFMARK_FILE"
echo "/View [/Fit]" >> "$PDFMARK_FILE"
echo "/OUT pdfmark" >> "$PDFMARK_FILE"


find "$input_dir" -iname "*.jpg" -o -iname "*.png" -type f | sort --version-sort > $PHOTO_LIST
cat $PHOTO_LIST
page_counter=1
while IFS= read -r image; do
    imageName=$(echo $(basename "$image") | cut -f 1 -d '.')
    imageNameUnnumbered=$(echo "$imageName" | sed 's/^[0-9]* //g')
    sequence_number=$(printf %06d $page_counter)

    echo
    echo Processing image $sequence_number\: $image...

    echo Adding \"$imageNameUnnumbered\" as PDF bookmark title...
    echo "[ /Title ($imageNameUnnumbered)" >> "$PDFMARK_FILE"
    echo "/Page $page_counter" >> "$PDFMARK_FILE"
    echo "/OUT pdfmark" >> "$PDFMARK_FILE"

    aspect=convert "$image" -format "%[fx:w/h]" info:
    isLandscape=convert xc: -format "%[fx:$aspect>=1?1:0]" info:

    if [ $isLandscape -eq 0 ]; then
        echo Resizing portrait image...
        convert "$image" -resize "${MAX_SHORT_PX}x${MAX_LONG_PX}" -quality $image_quality "$TMP_DIR/$sequence_number".jpg
    else
        echo Resizing landscape image...
        convert "$image" -resize "${MAX_LONG_PX}x${MAX_SHORT_PX}" -quality $image_quality "$TMP_DIR/$sequence_number".jpg
    fi
    echo Adjusting dpi...
    convert -units PixelsPerInch "$TMP_DIR/$sequence_number".jpg -density $dpi "$TMP_DIR/N$sequence_number".jpg

    ((page_counter++))
done < $PHOTO_LIST


echo
echo Combining all images into a single PDF...
output_file_no_bookmarks="$output_file-nobookmarks"

shopt -s nullglob
# Note: ImageMagick does NOT produce a valid PDF/A file, as it claims. This will be corrected by gs, in the next step.
convert "$TMP_DIR"/N*.jpg -density $dpi pdfa:"$output_file_no_bookmarks".pdf

echo Adding bookmarks...
gs -o "$output_file".pdf -dPDFA=2 -dPDFACompatibilityPolicy=1 -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -sColorConversionStrategy=UseDeviceIndependentColor "$output_file_no_bookmarks".pdf "$PDFMARK_FILE"

echo
echo Deleting temporary files...
rm "$output_file_no_bookmarks".pdf
rm -rf "$TMP_DIR"

echo
echo Finished, see $output_file.pdf

Image Credits:
Papirus icon for Terminal (modified) | GNU General Public License, version 3

Licensing:
This content is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
For your attributions to us please use the word »tuxwise«, and the link https://tuxwise.net.