Personal dotfiles
1#!/bin/bash
2#
3# Developed by Fred Weinhaus 12/30/2015 .......... revised 2/18/20201
4#
5# ------------------------------------------------------------------------------
6#
7# Licensing:
8#
9# Copyright © Fred Weinhaus
10#
11# My scripts are available free of charge for non-commercial use, ONLY.
12#
13# For use of my scripts in commercial (for-profit) environments or
14# non-free applications, please contact me (Fred Weinhaus) for
15# licensing arrangements. My email address is fmw at alink dot net.
16#
17# If you: 1) redistribute, 2) incorporate any of these scripts into other
18# free applications or 3) reprogram them in another scripting language,
19# then you must contact me for permission, especially if the result might
20# be used in a commercial or for-profit environment.
21#
22# My scripts are also subject, in a subordinate manner, to the ImageMagick
23# license, which can be found at: http://www.imagemagick.org/script/license.php
24#
25# ------------------------------------------------------------------------------
26#
27####
28#
29# USAGE: multicrop2 [-c coords] [-b bcolor] [-f fuzzval] [-d discard]
30# [-u unrotate] [-i innertrim] [-e extend] [-m mask] [-t threshold]
31# [-r resize] [-D density] [-S sortval] [-s showstats] [-v vc] infile outfile
32# USAGE: multicrop [-h or -help]
33#
34# OPTIONS:
35#
36# -c coords pixel coordinate to extract background color;
37# may be expressed as gravity value (NorthWest, etc)
38# or as "x,y" value; default is NorthWest=(0,0)
39# -b bcolor background color to use instead of option -c;
40# any valid IM color; default is to use option -c
41# -f fuzzval fuzz value for separating background color; expressed
42# as (integer) percent 0 to 100; default=10
43# -d discard discard any region that has an area smaller than
44# this size; integer>0; default is to keep all
45# -u unrotate unrotate method; choices are 1 for -deskew, 2 for
46# unrotate script and 3 for no unrotate; default=1
47# -i innertrim trims inside the cropped area to an orthogonal rectangle;
48# yes or no; default=no
49# -e extend extend crop on each side in pixels; integer; default=0
50# -m mask mask presentation method; choices are view,
51# save (to file) or output mask only; default
52# is none of the above, just output the images
53# -t threshold threshold on number of objects; aborts if more than
54# threshold number of objects are detected; integer>0;
55# default is no abort and keep all objects.
56# -r resize resize percent to scale the image down; float>0;
57# default is no resizing.
58# -D density density to use when reading a single page of a PDF;
59# integer>0; default is no assigned density
60# -S sortval sort regions by upper left bounding box x,y coordinates
61# rounded to the specified positive integer increment;
62# default is no sorting
63# -s showstats show connected components stats; yes or no; default=no
64# -v keep virtual canvas; default is not to keep virtual canvas;
65# only valid for -u=3 (no unrotate) and for output format that
66# supports virtual canvas such as PNG or TIFF.
67#
68###
69#
70# NAME: MULTICROP2
71#
72# PURPOSE: To crop and unrotate multiple images from a scanned image.
73#
74# DESCRIPTION: MULTICROP2 crops and unrotates multiple images from a scanned image.
75# The images must be well separated so that background color shows between them.
76# The process uses a floodfill technique based upon a seed coordinate and a fuzz
77# value to separate the individual images from the background of the scan.
78# The correct choice of fuzz factor is very important. If too small, the images
79# will not be separate. If too large, parts of the outer area of the image
80# containing similar colors will be lost and the image may be separated into
81# multiple parts. There are two unrotate methods. The first uses the IM deskew
82# function, but is limited to 5 degrees of rotate or less. The second uses my
83# unrotate script. It allows much larger rotations, but will be slower. If
84# using the second method, my unrotate script must be downloaded and installed.
85#
86# IMPORTANT: The images in the scanned file must be well separated in x and y
87# so that their bounding boxes do not overlap. This is especially important
88# if the images have a significant rotation.
89#
90# The output images will be named from the specified outfile and -000, -001,
91# -002 etc, will be appended before the .suffix.
92#
93# Arguments:
94#
95# -c coords ... COORDS is any location within the background (non-image) area
96# for the algorithm to find the background color. It may be specified in terms
97# of gravity parameters (NorthWest, North, NorthEast, East, SouthEast, South,
98# SouthWest or West) or as a pixel coordinate "x,y". The default is the
99# upper left corner = NorthWest = "0,0".
100#
101# -b bcolor ... BCOLOR is the background color to use for flood fill instead
102# of extracting this color from the image. This is useful when an image has
103# no borders so that the sub-images are hard against the edges. The bcolor
104# will be used to put a one pixel border around the image and coords will be
105# set to 0,0. Any valid IM color is allowed. The default is to use option -c.
106#
107# -f fuzzval ... FUZZVAL is the fuzz amount specified as an integer percent
108# value between 0 to 100 (without the % sign). The correct choice of fuzz
109# factor is very important. If too small, the images will not be separate.
110# If too larger, parts of the outer area of the image containing similar
111# colors will be lost and the image may be separated into multiple parts.
112# Typical values are probably between 5 and 20 percent. The default=10.
113# (0 is uniform color)
114#
115# -d discard ... DISCARD any region that has an area smaller than the
116# specified discard size. Values are integer>0. The default is to keep all
117# regions.
118#
119# -u unrotate ... UNROTATE is the unrotation method. Choices are: 1, 2 or 3.
120# The default is unrotate=1, which is fast and uses the IM -deskew function,
121# but is limited to images that are rotated no more than 5 degrees in the scan
122# and generally a light background color. Option unrotate=2 uses my unrotate
123# script. It can handle larger rotations, but is slower. If using the latter
124# method, my unrotate script must be downloaded and also installed so that it
125# is available for this script to use. Option unrotate=3 makes no attempt to
126# unrotate the images.
127#
128# -i innertrim ... INNERTRIM trims inside the cropped area to an orthogonal
129# rectangle. Requires my script, autotrim. The choices are: yes or no.
130# The default=no.
131#
132# -e extend ... EXTEND crop on each side for the output images in pixels.
133# The extended region will come from the background of the image. Values are integers.
134# Positive makes the results larger. Negative makes the results smaller. Positive
135# values are only allowed for unrotate=3 (no unrotation) and innertrim=no. The default=0.
136#
137# -m mask ... MASK provides several options for reviewing the initial mask that
138# is generated by the fuzz value. The choices are: view (display to X11 window),
139# save (to disk) along with the images, or output (without processing the images).
140# The default is to simply process the images without showing or saving the mask.
141# If using the view mode, then processing will stop until the image is closed.
142# But this allows you to then kill the script if the mask is not appropriate.
143# A good approach is to use the output mode repeatedly with various fuzzvals
144# until a reasonable mask is created. Note that the mask must separate the
145# images, but the background can "eat" a little into the images so long as no
146# full edge is lost or the images is split into multiple parts.
147#
148# -t threshold ... THRESHOLD on the number of objects. The script aborts, if
149# more than the threshold number of objects are detected. Value must be
150# integers greater than 0. The default is no abort and keep all objects.
151# To avoid an abort, use the -d discard option.
152#
153# -r resize ... RESIZE amount in percent to scale the image down. Values are floats>0.
154# The default is no resizing. This is useful to improve speed and floodfilling
155# when you have a large image, especially if the background is grainy. Note: do not
156# include the % symbol.
157#
158# -D density ... DENSITY to use when reading a single page of a PDF. Multipage pdf
159# files are not permitted. Values are integers>0. The default is no assigned density.
160#
161# -S sortval ... SORT regions by their upper left bounding box x,y coordinates
162# rounded to the specified positive integer increment. The default is
163# no sorting.
164#
165# -s showstats ... SHOWSTATS shows the connected components statistics.
166# Choices are: yes (y) or no (n). The default=no.
167#
168# -v ... keep VIRTUAL CANVAS. The default is not to keep virtual canvas. This option
169# is only valid for -u=3 (no unrotate) and for output format that supports virtual
170# canvas such as PNG or TIFF.
171#
172# REQUIREMENTS: IM 6.8.9.10 due to the use of -connected-components.
173# If using unrotate method 2, then my script, unrotate, is required.
174# If using innertrim, then my script, autotrim is required.
175#
176# CAVEAT: No guarantee that this script will work on all platforms,
177# nor that trapping of inconsistent parameters is complete and
178# foolproof. Use At Your Own Risk.
179#
180######
181#
182
183# set default values
184coords="" # initial coord for finding background color
185bcolor="" # initial background color
186fuzzval=10 # fuzz amount in percent for making background transparent
187discard="" # discard small regions
188extend=0 # extend the output crop on all sides
189mask="" # view, save, output
190threshold="" # threshold on number of objects; if larger, then abort
191unrotate=1 # 1=deskew 2=unrotate
192innertrim="no" # trim inside cropped area to orthogonal rectangle
193resize="" # resize percent
194density="" # density to use for input PDF
195sortval=""
196showstats="no" # show CCL stats
197vc="no" # keep virtual canvas
198debug="false"
199
200# set directory for temporary files
201dir="." # suggestions are dir="." or dir="/tmp"
202
203# set up functions to report Usage and Usage with Description
204PROGNAME=`type $0 | awk '{print $3}'` # search for executable on path
205PROGDIR=`dirname $PROGNAME` # extract directory of program
206PROGNAME=`basename $PROGNAME` # base name of program
207usage1()
208 {
209 echo >&2 ""
210 echo >&2 "$PROGNAME:" "$@"
211 sed >&2 -e '1,/^####/d; /^###/g; /^#/!q; s/^#//; s/^ //; 4,$p' "$PROGDIR/$PROGNAME"
212 }
213usage2()
214 {
215 echo >&2 ""
216 echo >&2 "$PROGNAME:" "$@"
217 sed >&2 -e '1,/^####/d; /^######/g; /^#/!q; s/^#*//; s/^ //; 4,$p' "$PROGDIR/$PROGNAME"
218 }
219
220# function to report error messages
221errMsg()
222 {
223 echo ""
224 echo $1
225 echo ""
226 usage1
227 exit 1
228 }
229
230# function to test for minus at start of value of second part of option 1 or 2
231checkMinus()
232 {
233 test=`echo "$1" | grep -c '^-.*$'` # returns 1 if match; 0 otherwise
234 [ $test -eq 1 ] && errMsg "$errorMsg"
235 }
236
237# test for correct number of arguments and get values
238if [ $# -eq 0 ]
239 then
240 # help information
241 echo ""
242 usage2
243 exit 0
244elif [ $# -gt 29 ]
245 then
246 errMsg "--- TOO MANY ARGUMENTS WERE PROVIDED ---"
247else
248 while [ $# -gt 0 ]
249 do
250 # get parameters
251 case "$1" in
252 -h|-help) # help information
253 echo ""
254 usage2
255 ;;
256 -f) # fuzzval
257 shift # to get the next parameter
258 # test if parameter starts with minus sign
259 errorMsg="--- INVALID FUZZVAL SPECIFICATION ---"
260 checkMinus "$1"
261 fuzzval=`expr "$1" : '\([0-9]*\)'`
262 [ "$fuzzval" = "" ] && errMsg "--- FUZZVAL=$fuzzval MUST BE A NON-NEGATIVE INTEGER VALUE (with no sign) ---"
263 fuzzvaltestA=`echo "$fuzzval < 0" | bc`
264 fuzzvaltestB=`echo "$fuzzval > 100" | bc`
265 [ $fuzzvaltestA -eq 1 -a $fuzzvaltestB -eq 1 ] && errMsg "--- FUZZVAL=$fuzzval MUST BE A NON-NEGATIVE INTEGER VALUE BETWEEN 0 AND 100 ---"
266 ;;
267 -c) # coords
268 shift # to get the next parameter
269 # test if parameter starts with minus sign
270 errorMsg="--- INVALID COORDS SPECIFICATION ---"
271 checkMinus "$1"
272 coords=$1
273 # further testing done later
274 ;;
275 -b) # bcolor
276 shift # to get the next parameter
277 # test if parameter starts with minus sign
278 errorMsg="--- INVALID BCOLOR SPECIFICATION ---"
279 checkMinus "$1"
280 bcolor=$1
281 ;;
282 -d) # discard
283 shift # to get the next parameter
284 # test if parameter starts with minus sign
285 errorMsg="--- INVALID DISCARD SPECIFICATION ---"
286 checkMinus "$1"
287 discard=`expr "$1" : '\([0-9]*\)'`
288 [ "$discard" = "" ] && errMsg "--- DISCARD=$discard MUST BE A NON-NEGATIVE INTEGER VALUE (with no sign) ---"
289 testA=`echo "$discard < 1" | bc`
290 [ $testA -eq 1 ] && errMsg "--- DISCARD=$discard MUST BE A NON-NEGATIVE INTEGER VALUE GREATER THAN 0 ---"
291 ;;
292 -e) # extend
293 shift # to get the next parameter
294 # test if parameter starts with minus sign
295 errorMsg="--- INVALID EXTEND SPECIFICATION ---"
296 #checkMinus "$1"
297 extend=`expr "$1" : '\([-0-9]*\)'`
298 [ "$extend" = "" ] && errMsg "--- EXTEND=$extend MUST BE AN INTEGER VALUE (with no sign) ---"
299 ;;
300 -u) # unrotate
301 shift # to get the next parameter
302 # test if parameter starts with minus sign
303 errorMsg="--- INVALID UNROTATE SPECIFICATION ---"
304 checkMinus "$1"
305 unrotate=`expr "$1" : '\([0-9]\)'`
306 [ $unrotate -lt 1 -a $unrotate -gt 3 ] && errMsg "--- UNROTATE=$unrotate MUST BE EITHER 1, 2, 3 OR 4 ---"
307 ;;
308 -i) # get innertrim
309 shift # to get the next parameter
310 # test if parameter starts with minus sign
311 errorMsg="--- INVALID INNERTRIM SPECIFICATION ---"
312 checkMinus "$1"
313 innertrim="$1"
314 innertrim=`echo "$innertrim" | tr "[:upper:]" "[:lower:]"`
315 case "$innertrim" in
316 yes|y) innertrim="yes" ;;
317 no|n) innertrim="no" ;;
318 *) errMsg "--- INNERTRIM=$innertrim IS AN INVALID VALUE ---"
319 esac
320 ;;
321 -m) # mask
322 shift # to get the next parameter
323 # test if parameter starts with minus sign
324 errorMsg="--- INVALID MASK SPECIFICATION ---"
325 checkMinus "$1"
326 mask=`echo "$1" | tr "[:upper:]" "[:lower:]"`
327 [ "$mask" != "view" -a "$mask" != "save" -a "$mask" != "output" ] && errMsg "--- MASK=$mask MUST BE EITHER VIEW, SAVE OR OUTPUT ---"
328 ;;
329 -t) # threshold
330 shift # to get the next parameter
331 # test if parameter starts with minus sign
332 errorMsg="--- INVALID THRESHOLD SPECIFICATION ---"
333 checkMinus "$1"
334 threshold=`expr "$1" : '\([0-9]*\)'`
335 [ "$threshold" = "" ] && errMsg "--- THRESHOLD=$threshold MUST BE A NON-NEGATIVE INTEGER VALUE (with no sign) ---"
336 testA=`echo "$threshold < 1" | bc`
337 [ $testA -eq 1 ] && errMsg "--- THRESHOLD=$threshold MUST BE A NON-NEGATIVE INTEGER VALUE GREATER THAN 0 ---"
338 ;;
339 -r) # resize
340 shift # to get the next parameter
341 # test if parameter starts with minus sign
342 errorMsg="--- INVALID RESIZE SPECIFICATION ---"
343 checkMinus "$1"
344 resize=`expr "$1" : '\([.0-9]*\)'`
345 [ "$resize" = "" ] && errMsg "--- RESIZE=$resize MUST BE A NON-NEGATIVE FLOAT VALUE (with no sign) ---"
346 testA=`echo "$resize == 0" | bc`
347 [ $testA -eq 1 ] && errMsg "--- RESIZE=$resize MUST BE A NON-NEGATIVE FLOAT VALUE GREATER THAN 0 ---"
348 ;;
349 -D) # density
350 shift # to get the next parameter
351 # test if parameter starts with minus sign
352 errorMsg="--- INVALID DENSITY SPECIFICATION ---"
353 checkMinus "$1"
354 density=`expr "$1" : '\([0-9]*\)'`
355 [ "$density" = "" ] && errMsg "--- DENSITY=$density MUST BE A NON-NEGATIVE INTEGER VALUE (with no sign) ---"
356 testA=`echo "$density == 0" | bc`
357 [ $testA -eq 1 ] && errMsg "--- DENSITY=$density MUST BE A NON-NEGATIVE INTEGER VALUE GREATER THAN 0 ---"
358 ;;
359 -S) # sortval
360 shift # to get the next parameter
361 # test if parameter starts with minus sign
362 errorMsg="--- INVALID SORTVAL SPECIFICATION ---"
363 checkMinus "$1"
364 sortval=`expr "$1" : '\([0-9]*\)'`
365 testA=`echo "$sortval == 0" | bc`
366 [ $testA -eq 1 ] && errMsg "--- SORTVAL=$sortval MUST BE AN INTEGER VALUE GREATER THAN 0 ---"
367 ;;
368 -s) # showstats
369 shift # to get the next parameter
370 # test if parameter starts with minus sign
371 errorMsg="--- INVALID SHOWSTATS SPECIFICATION ---"
372 checkMinus "$1"
373 showstats=`echo "$1" | tr "[:upper:]" "[:lower:]"`
374 [ "$showstats" != "yes" -a "$showstats" != "no" ] && errMsg "--- SHOWSTATS=$showstats MUST BE EITHER YES OR NO ---"
375 ;;
376 -v) # vc
377 vc="yes"
378 ;;
379 -) # STDIN and end of arguments
380 break
381 ;;
382 -*) # any other - argument
383 errMsg "--- UNKNOWN OPTION ---"
384 ;;
385 *) # end of arguments
386 break
387 ;;
388 esac
389 shift # next option
390 done
391 # get infile and outfile
392 infile="$1"
393 outfile="$2"
394fi
395
396# test if both bcolor and coords specified at the same time
397if [ "$bcolor" != "" -a "$coords" != "" ]; then
398 errMsg "--- BACKGROUND COLOR AND COODINATES CAN NOT BE USED TOGETHER ---"
399elif [ "$bcolor" = "" -a "$coords" = "" ]; then
400 coords="0,0"
401fi
402
403# test that infile provided
404[ "$infile" = "" ] && errMsg "NO INPUT FILE SPECIFIED"
405
406# test that outfile provided
407[ "$outfile" = "" ] && errMsg "NO OUTPUT FILE SPECIFIED"
408
409# test if input is single layer/page/frame
410count=`convert -ping "$infile" -format "%m\n" info: | wc -l`
411[ $count -gt 1 ] && errMsg "--- MULTIPAGE/MULTIFRAME/MULTILAYER IMAGES ARE NOT ALLOWED ---"
412
413if [ "$density" != "" ]; then
414 dproc="-density $density"
415else
416 dproc=""
417fi
418
419# set up temp file
420tmpA1="$dir/multicrop2_1_$$.mpc"
421tmpB1="$dir/multicrop2_1_$$.cache"
422tmpA2="$dir/multicrop2_2_$$.mpc"
423tmpB2="$dir/multicrop2_2_$$.cache"
424tmpA3="$dir/multicrop2_3_$$.miff"
425tmpA4="$dir/multicrop2_4_$$.mpc"
426tmpB4="$dir/multicrop2_4_$$.cache"
427
428trap "rm -f $tmpA1 $tmpB1 $tmpA2 $tmpB2 $tmpA3 $tmpB4 $tmpA4;" 0
429trap "rm -f $tmpA1 $tmpB1 $tmpA2 $tmpB2 $tmpA3 $tmpB4 $tmpA4; exit 1" 1 2 3 15
430#trap "rm -f $tmpA1 $tmpB1 $tmpA2 $tmpB2 $tmpA3; exit 1" ERR
431
432# read the input image into the temp files and test validity.
433if [ "$resize" != "" ]; then
434 convert -quiet $dproc "$infile" +repage "$tmpA4" ||
435 errMsg "--- FILE $infile1 DOES NOT EXIST OR IS NOT AN ORDINARY FILE, NOT READABLE OR HAS ZERO SIZE ---"
436 convert "$tmpA4" -scale $resize% "$tmpA1"
437else
438 convert -quiet $dproc "$infile" +repage "$tmpA1" ||
439 errMsg "--- FILE $infile1 DOES NOT EXIST OR IS NOT AN ORDINARY FILE, NOT READABLE OR HAS ZERO SIZE ---"
440fi
441
442
443# get im_version
444im_version=`convert -list configure | \
445 sed '/^LIB_VERSION_NUMBER */!d; s//,/; s/,/,0/g; s/,0*\([0-9][0-9]\)/\1/g' | head -n 1`
446
447# get output filename and suffix
448outnameArr=(`echo "$outfile" | sed -n 's/^\(.*\)[.]\([^.]*\)$/\1 \2/p'`)
449outname="${outnameArr[0]}"
450suffix="${outnameArr[1]}"
451#echo "outname=$outname"
452#echo "suffix=$suffix"
453
454if [ "$im_version" -ge "07000000" ]; then
455 identifying="magick identify"
456else
457 identifying="identify"
458fi
459
460# get image width and height
461width=`$identifying -ping -format "%w" $tmpA1`
462height=`$identifying -ping -format "%h" $tmpA1`
463
464# test for extend
465test=`convert xc: -format "%[fx:$extend>0?1:0]" info:`
466[ $test -eq 1 -a $unrotate -ne 3 ] && errMsg "--- SIGN FOR EXTEND=$extend MUST BE NEGATIVE ---"
467[ $test -eq 1 -a $unrotate -eq 3 -a "$innertrim" = "yes" ] && errMsg "--- SIGN FOR EXTEND=$extend MUST BE NEGATIVE ---"
468
469# test if coords provided as x,y
470# coords="" if test fails and have other characters such as northwest
471coords1=`expr "$coords" : '\([0-9]*,[0-9]*\)'`
472
473# get color at user specified location
474if [ "$bcolor" != "" ]; then
475 coords="0,0"
476elif [ "$coords1" != "" -a "$resize" != "" ]; then
477 x=`echo "$coords1" | cut -d, -f1`
478 y=`echo "$coords1" | cut -d, -f2`
479 x=`convert xc: -format "%[fx:round($x*$resize/100)]" info:`
480 y=`convert xc: -format "%[fx:round($y*$resize/100)]" info:`
481 coords="$x,$y"
482 bcolor=`convert $tmpA1 -format "%[pixel:u.p{$coords}]" info:`
483elif [ "$coords1" != "" -a "$resize" = "" ]; then
484 x=`echo "$coords1" | cut -d, -f1`
485 y=`echo "$coords1" | cut -d, -f2`
486 # account for pad of 1
487 x=$((x+1))
488 y=$((y+1))
489 coords="$x,$y"
490 bcolor=`convert $tmpA1 -format "%[pixel:u.p{$coords}]" info:`
491elif [ "$coords1" = "" ]; then
492 widthm1=`convert xc: -format "%[fx:$width-1]" info:`
493 heightm1=`convert xc: -format "%[fx:$height-1]" info:`
494 midwidth=`convert xc: -format "%[fx:round(($width-1))/2]" info:`
495 midheight=`convert xc: -format "%[fx:round(($height-1))/2]" info:`
496 coords=`echo "$coords" | tr "[:upper:]" "[:lower:]"`
497 case "$coords" in
498 ''|nw|northwest) coords="0,0" ;;
499 n|north) coords="$midwidth,0" ;;
500 ne|northeast) coords="$widthm1,0" ;;
501 e|east) coords="$widthm1,$midheight" ;;
502 se|southeast) coords="$widthm1,$heightm1" ;;
503 s|south) coords="$midwidth,$heightm1" ;;
504 sw|southwest) coords="0,$heightm1" ;;
505 w|west) coords="0,$midheight" ;;
506 *) errMsg "--- INVALID COORDS ---" ;;
507 esac
508 bcolor=`convert $tmpA1 -format "%[pixel:u.p{$coords}]" info:`
509fi
510#echo "bcolor=$bcolor"
511
512# set up floodfill
513if [ "$im_version" -ge "07000000" ]; then
514 matte_alpha="alpha"
515else
516 matte_alpha="matte"
517fi
518
519# add a border, and flood fill from all edges inward
520convert $tmpA1 -fuzz ${fuzzval}% -fill none \
521 -bordercolor $bcolor -border 1x1 \
522 -draw "$matte_alpha $coords floodfill" \
523 -shave 1x1 -fill white +opaque none \
524 -background black -alpha background -alpha off -type bilevel \
525 $tmpA2
526
527if [ "$mask" = "view" ]; then
528 display $tmpA2
529elif [ "$mask" = "save" ]; then
530 convert $tmpA2 ${outname}_mask.gif
531elif [ "$mask" = "output" ]; then
532 convert $tmpA2 ${outname}_mask.gif
533 exit 0
534fi
535
536# set up for unrotate 1 or 3
537if [ $unrotate -eq 1 ]; then
538 derotate="-background $bcolor -deskew 40%"
539elif [ $unrotate -eq 3 ]; then
540 derotate=""
541fi
542
543# set up discard
544if [ "$discard" != "" ]; then
545 discarding="-define connected-components:area-threshold=$discard"
546else
547 discarding=""
548fi
549
550# process image using connected components labeling
551echo ""
552data=`convert $tmpA2 -precision 15 \
553 -define connected-components:verbose=true \
554 $discarding -connected-components 4 null:`
555[ "$showstats" = "yes" ] && echo "$data"
556
557wwArr=(`echo "$data" | tail -n +2 | tr -cs "0-9.,\(\)\n" " " | awk '{print $2}'`)
558hhArr=(`echo "$data" | tail -n +2 | tr -cs "0-9.,\(\)\n" " " | awk '{print $3}'`)
559xoArr=(`echo "$data" | tail -n +2 | tr -cs "0-9.,\(\)\n" " " | awk '{print $4}'`)
560yoArr=(`echo "$data" | tail -n +2 | tr -cs "0-9.,\(\)\n" " " | awk '{print $5}'`)
561colorArr=(`echo "$data" | tail -n +2 | tr -cs "0-9.,gray\(\)\n" " " | awk '{print $8}'`)
562num=${#wwArr[*]}
563#echo $num
564
565# do sorting if specified
566if [ "$sortval" != "" ]; then
567 # build dataArr and sort it
568 # note new line before last quote so have list for sorting
569 # add rounded points for sorting
570 nearest=$sortval
571 for((i=0; i<num; i++)); do
572 xx=${xoArr[$i]}
573 yy=${yoArr[$i]}
574 xr=`convert xc: -format "%[fx:$nearest*round($xx/$nearest)]" info:`
575 yr=`convert xc: -format "%[fx:$nearest*round($yy/$nearest)]" info:`
576 dataArr[$i]="${wwArr[$i]} ${hhArr[$i]} ${xoArr[$i]} ${yoArr[$i]} ${colorArr[$i]} $xr $yr
577"
578 #echo ${dataArr[$i]}
579 done
580 OLDIFS=$IFS
581 IFS=$'\n'
582 sortArr=(`echo "${dataArr[*]}" | sort -n -k7,7 -k6,6`)
583 IFS=$OLDIFS
584 for((i=0; i<num; i++)); do
585 #echo "${sortArr[$i]}"
586 wwArr[$i]=`echo ${sortArr[$i]} | cut -d\ -f1`
587 hhArr[$i]=`echo ${sortArr[$i]} | cut -d\ -f2`
588 xoArr[$i]=`echo ${sortArr[$i]} | cut -d\ -f3`
589 yoArr[$i]=`echo ${sortArr[$i]} | cut -d\ -f4`
590 colorArr[$i]=`echo ${sortArr[$i]} | cut -d\ -f5`
591 done
592fi
593
594# abort if too many objects
595# subtract 1 for background
596numm1=$((num-1))
597if [ "$threshold" != "" ]; then
598 [ $numm1 -gt $threshold ] && errMsg "--- TOO MANY OBJECTS DETECTED ---"
599fi
600
601if [ "$vc" = "yes" ]; then
602 repaging=""
603else
604 repaging="+repage"
605fi
606#echo "repaging=$repaging;"
607
608echo ""
609k=0
610for ((i=0; i<num; i++)); do
611 color="${colorArr[$i]}"
612 if [ "$color" != "gray(0)" ]; then
613 echo "Processing Image $k"
614 kk=`printf "%03d" "$k"`
615 offx=${xoArr[$i]}
616 offy=${yoArr[$i]}
617 wd=${wwArr[$i]}
618 ht=${hhArr[$i]}
619 if [ "$resize" != "" ]; then
620 wd=`convert xc: -format "%[fx:round($wd*100/$resize)+2*$extend]" info:`
621 ht=`convert xc: -format "%[fx:round($ht*100/$resize)+2*$extend]" info:`
622 offx=`convert xc: -format "%[fx:round($offx*100/$resize)-$extend]" info:`
623 offy=`convert xc: -format "%[fx:round($offy*100/$resize)-$extend]" info:`
624 img=$tmpA4
625 else
626 wd=$((wd+2*extend))
627 ht=$((ht+2*extend))
628 offx=$((offx-extend))
629 offy=$((offy-extend))
630 img=$tmpA1
631 fi
632 echo "Initial Crop Box: ${wd}x${ht}+${offx}+${offy}"
633 echo ""
634 if [ $unrotate -eq 3 ]; then
635 convert $img -crop ${wd}x${ht}+${offx}+${offy} $repaging $tmpA3
636 elif [ $unrotate -eq 1 ]; then
637 convert $img -crop ${wd}x${ht}+${offx}+${offy} +repage $derotate \
638 -bordercolor "$bcolor" -border 2 -fuzz ${fuzzval}% -trim +repage $tmpA3
639 elif [ $unrotate -eq 2 ]; then
640 convert $img -crop ${wd}x${ht}+${offx}+${offy} +repage \
641 -fuzz ${fuzzval}% -trim miff:- | \
642 unrotate -C "$bcolor" -f ${fuzzval}% - $tmpA3
643 fi
644 if [ "$innertrim" = "yes" ]; then
645 mextend=-$extend
646 autotrim -m inner -f $fuzzval -C "$bcolor" -l $mextend -t $mextend \
647 -r $extend -b $extend $tmpA3 ${outname}-${kk}.${suffix}
648 echo ""
649 else
650 convert $tmpA3 ${outname}-${kk}.${suffix}
651 fi
652 k=$((k+1))
653 fi
654done
655echo ""
656
657exit 0
658
659
660