#!/bin/bash
#
# divide_vert [options] image  multi_image
#
# Divide an image horizontally into rows of images consisting of alternating
# images of variable colors (interesting parts) and images of a single solid
# color (seperating gaps) that when appended together vertically will
# re-produce the original image.
#
# Options...
#    -i            Ignore the uninteresting 'gaps' between the rows.
#    -b color      Use this color as background (for fuzz match)
#    -f fuzz       percentage threshold for background match
#
# Examples...
#
# Expand the row spacing of some text by 4 pixels (must be a multiple of two)
#
#  magick -size 50x caption:'This is a word wrapped line of text' miff:- |\
#    divide_vert - miff:- | magick - -splice 0x2 -append  gap_expansion.png
#
# This will remove all gaps between lines of text...
#
#  magick -size 50x caption:'This is a word wrapped line of text' miff:- |\
#    divide_vert -i - miff:- | magick - -append  gaps-removed.png
#
# Replace all gaps by a fixed amount (5 pixels),
# though this is not a good idea for normal text images.
#
#  magick -size 50x caption:'This is a word wrapped line of text' miff:- |\
#    divide_vert -i - miff:- |\
#      magick - -splice 0x5 -append \
#              -gravity south -splice 0x5  gaps_replaced.png
#
#
# You can also specify a specific color for the background 'gap'
#
#  magick -size 20x256 gradient: miff:- |\
#    divide_vert -b grey30 - miff:- |\
#      magick identify -format "%h " -
#  178 1 77
#
# Note how only one row exactly matched the given background color
#
# Or with a fuzzy match of a specific background color
#
#  magick -size 20x256 gradient: miff:- |\
#    divide_vert -b grey50 -f 25% - miff:- |\
#      magick identify -format "%h " -
#  115 127 14
#
# And now about 50% (both sides of 25%) matched the given background
# to produce a 127 pixel divider gap.
#
# FUTURE:
#   * Specify a minimum 'gap' size, to allow 'paragraph/word' seperation
#   * Optionally divide the 'gap' equally bettween each 'interesting' row That
#     is every image contains 'interesting' parts, surrounded by some 'blank'
#     of 'gap' spacing.
#   * Save images with 'virtual (page) offsets' to preserve their location.
#     The result will be a collection of 'layer' images rather than 'simple'
#     rows.  such 'layer' images will then allow you to separate an image
#     first vertically by 'row', then horizontally by 'column' producing
#     a exploded layed image of either individual characters or words.
#     It will also let you do automated  "GIF animation splitting".
#
# SPEEDUP
#   If your input image uses a white background one way of speeding up this
#   process is to simply compress (-scale) the image directory down to a
#   single column.  Any pixel that remains white will then represent a blank
#   row of pixels.  That would be a major speed increase, but only for
#   images with a pure-white (or pure-black) background.
#
###
#
# Anthony Thyssen    25 June 2007     A.Thyssen_AT_griffith.edu.au
#
PROGNAME=`type $0 | awk '{print $3}'`  # search for executable on path
PROGDIR=`dirname $PROGNAME`            # extract directory of program
PROGNAME=`basename $PROGNAME`          # base name of program
Usage() {                              # output the script comments as docs
  echo >&2 "$PROGNAME:" "$@"
  sed >&2 -n '/^###/q; /^#/!q; s/^#//; s/^ //; 3s/^/Usage: /; 2,$ p' \
          "$PROGDIR/$PROGNAME"
  exit 10;
}

while [  $# -gt 0 ]; do
  case "$1" in
  --help|--doc*) Usage ;;

  -i) IGNORE_GAPS=true ;;           # ignore blank gap images.
  -b) shift;  bg_color="$1" ;;      # gaps are only this color.
  -f) shift;  fuzz="-fuzz $1" ;;    # fuzz factor for background

  -)  break ;;                      # STDIN end of user options
  --) shift; break ;;               # end of user options
  -*) Usage "Unknown option \"$1\"" ;;
  *)  break ;;                      # end of user options
  esac
  shift   # next option
done

[ $# -ne 2 ] && Usage "Invalid number of Arguments"

input="$1"  # Read from this IM input file format, may be a pipe
output="$2" # Write to this IM input file format, may be a pipe

if [ "X$bg_color" != "X" ]; then
  bg_color=`magick xc:"$bg_color" -depth 16 -alpha on \
              -format '%[pixel:s]' info: `
  [ "X$bg_color" = "X" ] && Usage "Invalid Background Color"
fi

tmpdir=`mktemp -d "${TMPDIR:-/tmp}/$PROGNAME-XXXXXXXXXX"` ||
  { echo >&2 "$PROGNAME: Unable to create temporary directory"; exit 10;}
trap 'rm -rf "$tmpdir"' 0   # remove when finished (on end or exit)
trap 'exit 2' 1 2 3 15

# -----------------------------------------------------------------

# Read input image, once only as it may be pipelines, 
# save a MPC copy of it.   Return the height of that image.
height=`magick "$input" +gravity +repage \
                -format '%[fx:u.h-1]' -identify \
                $tmpdir/original.mpc`

# Extract information on each row.
# Then extract the number of colors, and first color from each row!
if [ "X$bg_color" = "X" ]; then
  magick $tmpdir/original.mpc -crop 0x1 \
          -format '%k %[pixel:s]\n' info:$tmpdir/image_data
else
  # Same but first simplify any near background to the background color
  magick $tmpdir/original.mpc -alpha set -channel RGBA \
          $fuzz -fill "$bg_color" -opaque "$bg_color" \
          -crop 0x1 -depth 16 -alpha on \
          -format '%k %[pixel:s]\n' info:$tmpdir/image_data
fi

exec <$tmpdir/image_data     # read from this data as STDIN (for main loop)

x=0  top=$x                  # read the values for row 0
count=0                      # the number of divisions found in the file
read top_cnum top_color      # get the color count, and first pixel color

#echo "bg_color = $bg_color"
#echo "Row: $x $top_cnum $top_color"

# if the color of top row is NOT the given background color it is not a gap
[ "X$bg_color" != "X" -a "$top_color" != "$bg_color" ] && top_cnum=2

# Divide the image basied on the number of colors (or change in gap color)
while x=`expr $x + 1`; read cnum color; do
  #echo "Row: $x $cnum $color"

  # If color is NOT the bg_color, this row is not a gap row!
  [ "X$bg_color" != "X" -a "$color" != "$bg_color" ] && cnum=2
  if [ $top_cnum -eq 1 -a \( $cnum -ne 1 -o "$top_color" != "$color" \) ] ||
     [ $top_cnum -ne 1 -a $cnum -eq 1 ]; then
    # We found the end of a variable image or single color 'blank' gap
    if [ $top_cnum -ne 1 -o ! "$IGNORE_GAPS" ]; then
      # Save this division from the original image
      h=`expr $x - $top`   # height of region
      file=`printf "$tmpdir/divisions_%06d.mpc" $count`  # save the division
      magick $tmpdir/original.mpc -crop 0x$h+0+$top +repage $file
      count=`expr $count + 1`  # we found this many divisions.

      # debug
      echo "division $count: top $top height $h"
      #magick $file x:
    fi
    # set things up for the next area to be divided
    top=$x  top_cnum=$cnum  top_color="$color"
  fi
done

if [ $count -ne 0 ]; then
  # Extract the final split (if wanted)
  if [ $top_cnum -ne 1 -o ! "$IGNORE_GAPS" ]; then
    # save the last division that is present in the original image
    h=`expr $height + 1 - $top`   # height of region
    file=`printf "$tmpdir/divisions_%06d.mpc" $count`
    magick $tmpdir/original.mpc -crop 0x$h+0+$top +repage $file
  fi
  #count=`expr $count + 1`
  #echo >&2 "split_horiz: Found $count divisions"

  # Debug
  #magick $tmpdir/divisions_*.mpc \
  #        -background red -splice 0x1+0+0 -append x:

  # output the parts that were saved, if any!
  if  ls -d $tmpdir/divisions_*.mpc >/dev/null 2>/dev/null;  then
    # Output all the divisions as a posible multi-image file
    magick $tmpdir/divisions_*.mpc "$output"
  else
    # No divisions were found! presumably we are ignoring gaps!
    # This should be imposible, so ouput the 'null' error image
    magick null: "$output"
  fi
else
  # No divisions were found, so just output image (via magick again)
  if [ $top_cnum -ne 1 -o ! "$IGNORE_GAPS" ]; then
    magick $tmpdir/original.mpc "$output"
  else
    # image is blank, BUT we were asked to not output blank images!
    # This is imposible, so ouput the 'null' error image
    magick null: "$output"
  fi
fi

