Update docs, various fixes.
[dja/scandal.git] / scan2pages.sh
index 995c5a6..dbd66ee 100755 (executable)
@@ -2,68 +2,56 @@
 
 function usage {
 cat >&2 << __EOF__ 
-Usage: $0 [-vfpsmut] [-d depth] pdffile outdir
+Usage: $0 [-vfpsmutb] [-D DPI] [-d depth] [-F format] pdffile outdir
 Convert pdffile - a pdf of scanned facing pages - to a set of images in outdir,
 each with only one page.
 OPTIONS:
        -v: Be verbose.
-       -d depth: Use given depth. Default is 1. Unpaper can only handle up to 8.
-       -D dpi: Use given DPI. Colour scans on library scanners are usually 300, bw 400. 
-       -s: skip masking/trimming. Overrides -m.
-       -f: Forceably redo everything.
-       -p: Forceably redo pdf conversion. Implies options below, equivalent to -f.
-       -m: Forceably redo masking/trimming and other preprocessing. Impiles options below.
-       -u: Forceably redo unpaper processing. Implies option below. IGNORED
-       -t: Forceably redo final trimming and cleaning. IGNORED
+       -d depth: Use given depth. Default is 1 for black and white, 8 for colour/gray.
+               Unpaper can only handle up to 8.
+       -D dpi: Use given DPI. Colour scans on library scanners are usually 300, bw 400.
+       -e extension: use the output format signified by the extension. Default is png
+       -b: Optimize for BeBook One.
+       -1: each physical page contains one logical page
+       -2: each physical page contains two logical pages
+               (neither specified: try to figure it out)
 __EOF__
 }
 
-## Setup and utilities ##
-# Mac OS X doesn't have seq. It has jot instead.
-Linux_seq="seq"
-Darwin_seq="jot -"
-if [[ $(uname) == "Darwin" ]]; then my_seq=$Darwin_seq;
-else my_seq=$Linux_seq;
-fi;
 
+## Setup and utilities ##
+source $(dirname $0)/my_seq.sh
 
 ## Process flags ##
-forcepdf=
-forcemask=
-forceunpaper=
-forceclean=
 convertflags=
 unpaperflags=
-depthflags="-depth 1"
+depthset=
+depth=
 dpi=
 skipmask=
 verbose=
-while getopts 'vd:sfpmuc' OPTION
+extension="png"
+bebook=
+logperphys=
+while getopts 'vd:D:e:b12' OPTION
 do
        case $OPTION in
        v)      verbose=1
                convertflags="$convertflags -verbose"
                unpaperflags="$unpaperflags -v --time"
                ;;
-       d)      depthflags="-depth $OPTARG"
+       d)      depth="$OPTARG"
                ;;
        D)      dpi=$OPTARG
                ;;
-       s)      skipmask=1;
-               ;;
-       f)      forcepdf=1; forcemask=1; forceunpaper=1; forceclean=1
+       e)      extension="$OPTARG"
                ;;
-       p)      forcepdf=1; forcemask=1; forceunpaper=1; forceclean=1
+       b)      bebook=1
                ;;
-       m)      forcemask=1; forceunpaper=1; forceclean=1
+       1)      logperphys=1
                ;;
-       u)      forceunpaper=1; forceclean=1
+       2)      logperphys=2
                ;;
-       t)      forceclean=1
-               ;;
-#      b)      bflag=1
-#              bval="$OPTARG"
-#              ;;
        ?)      usage
                exit 2
                ;;
@@ -78,21 +66,15 @@ if [[ $# != 2 ]]; then
        exit 2
 fi
 
-file=$1
-dir=$2
+scanfile=$1
+outdir=$2
 
 filedir=$(dirname $1)
 base=$(basename $1 .pdf)
 
 # make the output dir
-mkdir -p $dir
+mkdir -p $outdir
 
-# figure out the number of pages
-dscname=$dir/${base}.dsc
-pdf2dsc $file $dscname || exit 1
-pages=$(awk '$1 ~ "%%Pages" {print $2}' $dscname)
-echo "Got $pages page(s)."
-rm $dscname
 
 # guess at DPI, unless it's been set
 # the scans do not seem to accurately reflect their resolution.
@@ -101,7 +83,7 @@ if [[ "$dpi" = "" ]]; then
        # 2 for b/w, and the scanner seems to default to 400 dpi for that
        # 256 for greyscale, which has to be selected manually (so I'm assuming 300 for no good reason)
        # 31564 for colour, which defaults to 300
-       if [[ $( convert $file[0] -format "%k" info: || exit 1 ) == 2 ]]; then
+       if [[ $( convert $scanfile[0] -format "%k" info: || exit 1 ) == 2 ]]; then
                dpi=400;
        else
                dpi=300
@@ -111,48 +93,132 @@ if [[ "$dpi" = "" ]]; then
        fi
 fi
 
+# guess at depth, unless it's been set
+if [[ "$depth" = "" ]]; then
+       if [[ $( convert $scanfile[0] -format "%k" info: || exit 1 ) == 2 ]]; then
+               depth=1;
+       else
+               depth=8
+       fi
+       if [[ $verbose == 1 ]]; then
+               echo "Depth guessed at $depth."
+       fi
+fi
+
+# figure out the number of pages
+dscname=$outdir/${base}.dsc
+pdf2dsc $scanfile $dscname || exit 1
+pages=$(awk '$1 ~ "%%Pages" {print $2}' $dscname)
+echo "Got $pages page(s)."
+rm $dscname
+
 # process pages 1 by 1 to avoid convert gobbling all the memory
-for pg in `$my_seq 1 $pages`; do
-       echo "Processing page $pg."
+for scanpgnum in `$my_seq 1 $pages`; do
+       echo "Processing page $scanpgnum."
        
-       pgn=$(printf '%03d' $pg)
+       scanpgnum=$(printf '%03d' $scanpgnum)
        
        # convert from pdf
-       origpnm=$dir/pg-${pgn}.pnm
-       if [[ ! $([ -e $origpnm ]) || $forcepdf ]]; then
-               convert $convertflags $depthflags -density $dpi $file[$(expr $pg - 1)] \
-                       $origpnm || exit 1
+       scanpg=$outdir/scanpg-${scanpgnum}.png
+       if [ ! -e $scanpg ]; then
+               convert $convertflags -depth $depth -density $dpi $scanfile[$(expr $scanpgnum - 1)] \
+                       $scanpg || exit 1
        fi;
        
-       # preprocess it!
-       preppnm=$dir/pg-pp-${pgn}.pnm
-       if [[ ! $skipmask && ( ! $([ -e $preppnm ]) || $forcemask ) ]]; then
+done;
+
+# do ocr binarise
+[ -e $outdir/scanpgs ] && rm -r $outdir/scanpgs
+ocropus book2pages $outdir/scanpgs $outdir/scanpg-*.png || exit 1
+
+for scanpgnum in  `$my_seq 1 $pages`; do
+
+       binscanpg=$outdir/scanpgs/$(printf '%04d' $scanpgnum).bin.png
+       scanpgnum=$(printf '%03d' $scanpgnum)
+       scanpg=$outdir/scanpg-${scanpgnum}.png
+
+       # preprocess scanned page
+       cleanscanpg=$outdir/scanpg-clean-${scanpgnum}.pnm
+       if [ ! -e $cleanscanpg ]; then
                # create mask: 
                # ... downscale, blur,
-               convert $convertflags -resize 25% -depth 8 -blur 10 $origpnm $dir/pg-mask-${pgn}.pnm ||exit 1
+               convert $convertflags -resize 10% -depth 8 -blur 10 -median 2 $scanpg $outdir/scanpg-mask-${scanpgnum}.png ||exit 1
 
                # ... get crop co-ords. They're off by ~2 as I don't know how to
                # properly correct for the border.
-               cropcords=$(convert -border 1x1 -bordercolor '#000' -resize 400% -trim -fuzz 90% -format "%wx%h%O" $dir/pg-mask-${pgn}.pnm info: || exit 1)
+               cropcords=$(convert -border 1x1 -bordercolor '#000' -resize 1000% -trim -fuzz 90% -format "%wx%h%O" $outdir/scanpg-mask-${scanpgnum}.png info: || exit 1)
                
                # ... crop and despeckle? the final pre-prepared image
-               convert $convertflags -crop $cropcords $origpnm $preppnm || exit 1
-       elif [[ $skipmask ]]; then
-               cp $origpnm $preppnm
+               convert $convertflags -crop $cropcords $binscanpg  $cleanscanpg || exit 1
        fi;
        
-       #unpaper it
-       #names go a bit funny here
-       #also, ignore flags starting here
-       unppnm=$dir/upg-${pgn}-%01d.pnm
-       unpaper $unpaperflags --layout double --overwrite --no-blackfilter -ni 10 -op 2 $preppnm $unppnm || exit 1
-
-       # final convert and clean
-       convert $convertflags $dir/upg-${pgn}-?.pnm $dir/upg-${pgn}-%01d.tiff || exit 1
+       # check it hasn't mostly disappeared - e.g. if the scan was all black
+       # (e.g. forgot to put the book down when you first hit scan)
+       if [[ $(convert  $cleanscanpg -format '%[fx:s.w*s.h>1000]' info:) = "0" ]]; then
+               [[ $verbose == 1 ]] && echo "Discarding pg ${scanpgnum}: not enough remains after masking."
+               continue; 
+       fi;
        
+       #unpaper it
+       physpgbase=$outdir/physpg-${scanpgnum}
+       if [ ! -e ${physpgbase}-1.pnm ] || [ ! -e ${physpgbase}-2.pnm ]; then
+               unpaper $unpaperflags --layout double --overwrite -ni 10 -op 2 $cleanscanpg ${physpgbase}-%01d.pnm || exit 1
+       fi;
        
+       for physpgnum in $($my_seq 1 2); do
+               echo Processing physical page ${physpgnum}.
+               
+               physpg=${physpgbase}-${physpgnum}.pnm #$physpgbase has $outdir/ already
+               
+               cleanphyspg=$outdir/physpg-clean-${scanpgnum}-${physpgnum}.pnm
+               
+               if [ ! -e $cleanphyspg ]; then
+                       # remask and retrim. FIXME: may throw off 2page detection
+                       convert $convertflags -resize 10% -depth 8 -gamma 0.01 -median 2 $physpg $outdir/physpg-mask-${scanpgnum}-${physpgnum}.png ||exit 1
+
+                       # Trim #-border 1x1 -bordercolor '#fff' -trim -fuzz 30% 
+                       cropcords=$(convert -trim -fuzz 90%\
+                        -resize 1000% -format "%wx%h%O" $outdir/physpg-mask-${scanpgnum}-${physpgnum}.png info: || exit 1)
+               
+                       # ... crop and despeckle? the final pre-prepared image
+                       convert $convertflags -crop $cropcords $physpg $cleanphyspg || exit 1
+               fi;
+               
+               #detect if the page is 2-up
+
+               if [[ $logperphys == 2 ]] || ( [[ $logperphys != 1 ]] && $(dirname $0)/detect2pages.sh ${cleanphyspg} ${scanpgnum} ${physpgnum} ); then
+                       if [[ $verbose == 1 ]]; then
+                               echo "Resplitting physical page ${physpgnum}."
+                       fi
+                       unpaper $unpaperflags --pre-rotate 90 --layout double --overwrite \
+                        -op 2 --no-blackfilter --no-grayfilter --no-noisefilter \
+                        --no-blurfilter $cleanphyspg $outdir/logpg-${scanpgnum}-${physpgnum}-%01d.pnm || exit 1
+               else
+                       cp $cleanphyspg $outdir/logpg-${scanpgnum}-${physpgnum}-1.pnm
+               fi;
+
+               #prepare for ocr
+               convert $convertflags $outdir/logpg-${scanpgnum}-${physpgnum}-?.pnm $outdir/logpg-${scanpgnum}-${physpgnum}-%01d.png || exit 1
+
+               #final convert and clean w/ bebook optimisation
+               if [[ $bebook ]]; then
+                       convert $convertflags $outdir/logpg-${scanpgnum}-${physpgnum}-?.pnm -trim -fuzz 80% -resize 1200x1600 $outdir/final-${scanpgnum}-${physpgnum}-%01d.${extension} || exit 1
+               else
+                       convert $convertflags $outdir/logpg-${scanpgnum}-${physpgnum}-?.pnm $outdir/final-${scanpgnum}-${physpgnum}-%01d.${extension} || exit 1
+               fi
+
+       done;
+
 done
 
-mkdir $dir/pages
-mv $dir/upg-*.tiff $dir/pages
+#try full ocr
+rm -rf $outdir/logpgs
+ocropus book2pages $outdir/logpgs $outdir/logpg-*.png
+ocropus pages2lines $outdir/logpgs
+ocropus lines2fsts $outdir/logpgs
+ocropus fsts2bestpaths $outdir/logpgs
+ocropus buildhtml $outdir/logpgs > $outdir/out.html
+
+mkdir -p $outdir/pages
+mv $outdir/final-*.${extension} $outdir/pages
        

UCC git Repository :: git.ucc.asn.au