#!/bin/bash maxSearchTries=40 PATH=$PATH:$(dirname "$0") # Check for required programs before starting requiredPrograms=( "concatenateImages" "convert" "expr" ) requiredOk=1 for prg in "${requiredPrograms[@]}"; do path=$(which $prg) if [[ "" == "$path" ]]; then requiredOk=0 echo "ERROR: Required program '$prg' not found" >&2 fi done if [[ $requiredOk -eq 0 ]]; then echo " Please provide those programs in order to use this script" >&2 exit 2 fi # General help that is shown whenever the script cannot be run because the user # did not provide sufficient parameters function showHelp { cmd=$(basename "$0") echo "" echo " -----===== $cmd =====-----" echo "" echo " \"$cmd --of=OUTFILE sf=SEARCHFOLDER [OPTIONAL PARAMETERS] RES1 RES2 [RES3 [...]]\"" echo "" echo "Concatenates the images in the given order and writes the result to the file" echo "specified by --of" echo "" echo "Obligatory parameters:" echo " --of= The out-file, meaning the file to write the concatenated image " echo " to. This file will be overwritten without notice." echo " --sf= The folder to search in for images." echo " RES[1-x] The resolution of the Desktops for which the background should" echo " be created from left to right. The RES-parameters must have the" echo " form of WIDTHxHEIGHT (e.g. '1280x1024'). There have to be at least" echo " two RES-parameters" echo "" echo "Optional parameters:" echo " --mode= The mode for choosing the images. Possible values:" echo " exact - For every resolution an image with exactly the given" echo " size is used. No resizing of images." echo " exact2 - Like exact, but needs a preordered search-folder. Use the" echo " orderImagesByResolution script to order it. (Faster)" echo " down - Uses images that are at least as big as the given size" echo " and resizes bigger images. This might lead to images being" echo " cropped because they have a differnt ratio." echo " any - Resizes any picture to the given resolution. This might" echo " look bad if you have for example a 24\" monitor and some" echo " 640x480 images in the search-folder" echo " Default: exact" echo " --background= The color of the background if the pictures do not have the same" echo " size. (default: black)" echo " --same Use the same image for all resolutions. Only works with mode 'down'" echo " or 'any'" echo " --align= Vertical alignment of images that are smaller that the biggest " echo " image given" echo " --verbose Output additional information" echo "" echo "Example: " echo " \"$cmd --of=bg.png --sf=Pictures/OrderedWallpapers 1920x1200 1280x1024\"" echo "" echo "Exit-Codes:" echo " 0 - Everything is fine" echo " 1 - Wrong parameters" echo " 3 - Not enough RES-parameters" echo " 4 - No subfolder for given resolution in search-folder" echo " 5 - Unknown mode" echo " 6 - RES-pramatemer has wrong format." echo " 7 - Incompatible parameters used" echo " 8 - No matching image found after $maxSearchTries tries" echo " 11 - Image concatenating failed (concatenateImages error)" echo " 23 - I am watching you." echo " 42 - Please state the question." echo " 99 - The requested feature is not (yet) implemented" echo "" } # Used to output certain information only in verbose-mode function echoIfVerbose { if [[ $verbose -eq 1 ]]; then echo $@ fi } # initializing variables exitStatus=0 concatParams="" searchFolder="" outFile="" mode="exact" resolutions=() verbose=0 hidden=0 same=0 # Analyze given parameters for param in "$@"; do knownParam=0 if [[ "${param:0:5}" == "--of=" ]]; then knownParam=1 outFile="${param:5}" fi if [[ "${param:0:5}" == "--sf=" ]]; then knownParam=1 searchFolder=${param:5} # All directories should end with an "/" to prevent problems with the # path later on if [[ "/" != ${searchFolder: -1} ]]; then searchFolder="$searchFolder/" fi fi if [[ "${param:0:7}" == "--mode=" ]]; then knownParam=1 mode=${param:7} # All directories should end with an "/" to prevent problems with the # path later on if [[ "/" != ${searchFolder: -1} ]]; then searchFolder="$searchFolder/" fi fi if [[ "${param:0:2}" != "--" ]]; then knownParam=1 match=$(expr match "$param" '\([0-9]*x[0-9]*\)') if [[ "$match" != "$param" ]]; then echo "ERROR: RES-pramatemer format must be WIDTHxHEIGHT (e.g. '1024x768'): '$param'" >&2 exitStatus=6 fi resolutions[${#resolutions[*]}]=$param fi if [[ "${param:0:9}" == "--verbose" ]]; then knownParam=1 verbose=1 fi if [[ "${param:0:8}" == "--hidden" ]]; then knownParam=1 hidden=1 fi if [[ "${param:0:6}" == "--same" ]]; then knownParam=1 same=1 fi # Parameters handed down to the used program if [[ "${param:0:8}" == "--align=" || "${param:0:13}" == "--background=" ]]; then knownParam=1 concatParams="$concatParams $param" fi # Check for unknown parameters # Has to be at the end of this loop if [[ $knownParam -eq 0 ]]; then echo "ERROR: Unknown Parameter '$param'" >&2 exitStatus=4 fi done if [[ "$outFile" == "" ]]; then echo "ERROR: Obligatory Parameters not given" >&2 echo " Please provide an out-file (of) parameters" >&2 exitStatus=1 fi if [[ "$searchFolder" == "" ]]; then echo "ERROR: No search folder given" >&2 echo " Please provide a folder to search for images" >&2 exitStatus=1 fi if [[ ${#resolutions[@]} -lt 2 ]]; then echo "ERROR: Not enough RES-parameters given" >&2 echo " Please provide at least two image resolutions" >&2 exitStatus=3 fi if [[ "$mode" != "exact" && "$mode" != "exact2" && "$mode" != "down" && "$mode" != "any" ]]; then echo "ERROR: Unknown mode" >&2 echo " Please use 'exact', 'exact2', 'down' or 'any'" >&2 exitStatus=5 fi if [[ "$mode" == "exact" && $same -ne 0 ]]; then echo "ERROR: --same cannot be used with mode 'exact'" >&2 echo " Please use mode 'down' or 'any' or leave out --same" >&2 exitStatus=7 fi if [[ "$mode" == "exact2" && $same -ne 0 ]]; then echo "ERROR: --same cannot be used with mode 'exact'" >&2 echo " Please use mode 'down' or 'any' or leave out --same" >&2 exitStatus=7 fi if [[ $exitStatus -ne 0 ]]; then ## Code for debugging parameters #echo "Parameters received:" #x=0 #while [[ "$1" != "" ]]; do # let "x = $x + 1" # echo "$x: $1" # shift #done showHelp exit $exitStatus fi # $IFS must be set to newline so a space is not interpreted as separator for # the files returned by the find-command IFS=$'\n' sourceImages=() deleteImages=() lastImage="" fileWidth=0 fileHeight=0 # Find all files if [[ $hidden -eq 1 ]]; then files=$(find "$searchFolder" -type f) else files=$(find "$searchFolder" \( ! -regex '.*/\..*' \) -type f) fi fileArray=() for filePath in $files; do fileArray[${#fileArray[*]}]=$filePath done for res in "${resolutions[@]}"; do #Todo: Find source images if [[ "$mode" == "exact" ]]; then # Mode: Only exact images will be used width=$(expr match "$res" '\([0-9]*\)x') height=$(expr match "$res" '.*x\([0-9]*\)') fileWidth=0 fileHeight=0 echoIfVerbose "Searching for Picture >= $res..." x=0 while [[ $width -ne $fileWidth || $height -ne $fileHeight ]]; do image=${fileArray[$RANDOM % ${#fileArray[*]}]} pictureSize=$(identify -format "%wx%h" "$image") fileWidth=$(expr match "$pictureSize" '\([0-9]*\)x') fileHeight=$(expr match "$pictureSize" '.*x\([0-9]*\)') echoIfVerbose " ...$pictureSize" let "x = x + 1" if [[ $x -gt $maxSearchTries ]]; then echo "ERROR: Did not find suitable image after $maxSearchTries tries." >&2 echo " Please make sure there are enough $res images in the search-folder" >&2 echo " Or use 'exact2' mode with preordered search-folder" >&2 exit 8 fi done echoIfVerbose "done." numImg=${#deleteImages[*]} echoIfVerbose "Using picture: '$image'" tmpImage="$outFile.$numImg.tmp.png" convert "$image" -resize "$res^" -gravity center -extent "$res" -quality 10 "$tmpImage" #"-quality 10" is specifically for .png deleteImages[$numImg]=$tmpImage sourceImages[$numImg]=$tmpImage fi if [[ "$mode" == "exact2" ]]; then # Mode: Exact imagesize in preordered folder subFolder="$searchFolder$res" if [[ -d "$subFolder" ]]; then resimages=() # Find all files if [[ $hidden -eq 1 ]]; then files=$(find "$searchFolder$res/" -type f) else files=$(find "$searchFolder$res/" \( ! -regex '.*/\..*' \) -type f) fi fileArray=() for filePath in $files; do fileArray[${#fileArray[*]}]=$filePath done image=${fileArray[$RANDOM % ${#fileArray[*]}]} echoIfVerbose "Using picture: '$image'" sourceImages[${#sourceImages[*]}]=$image else echo "ERROR: No subfolder in search-folder for resolution '$res'" >&2 echo " The search-folder must have subfolders named after the resolution" >&2 echo " of the images inside. In this case: '$subFolder'" >&2 exit 4 fi fi if [[ "$mode" == "down" && $same -eq 1 ]]; then width=$(expr match "$res" '\([0-9]*\)x') height=$(expr match "$res" '.*x\([0-9]*\)') if [[ $same -eq 0 || "$lastImage" == "" || $width -gt $fileWidth || $height -gt $fileHeight ]]; then echoIfVerbose "Searching for Picture >= $res..." x=0 while [[ $width -gt $fileWidth || $height -gt $fileHeight ]]; do image=${fileArray[$RANDOM % ${#fileArray[*]}]} pictureSize=$(identify -format "%wx%h" "$image") fileWidth=$(expr match "$pictureSize" '\([0-9]*\)x') fileHeight=$(expr match "$pictureSize" '.*x\([0-9]*\)') echoIfVerbose " ...$pictureSize" let "x = x + 1" if [[ $x -gt $maxSearchTries ]]; then echo "ERROR: Did not find suitable image after $maxSearchTries tries." >&2 echo " Please make sure there are enough $res images in the search-folder" >&2 echo " Or use 'exact2' mode with preordered search-folder" >&2 exit 8 fi done echoIfVerbose "done." fi # continued outside the resolution for-loop fi if [[ "$mode" == "down" && $same -eq 0 ]]; then # Mode: Only bigger images will be resized to the given resolution width=$(expr match "$res" '\([0-9]*\)x') height=$(expr match "$res" '.*x\([0-9]*\)') fileWidth=0 fileHeight=0 echoIfVerbose "Searching for Picture >= $res..." x=0 while [[ $width -gt $fileWidth || $height -gt $fileHeight ]]; do image=${fileArray[$RANDOM % ${#fileArray[*]}]} pictureSize=$(identify -format "%wx%h" "$image") fileWidth=$(expr match "$pictureSize" '\([0-9]*\)x') fileHeight=$(expr match "$pictureSize" '.*x\([0-9]*\)') echoIfVerbose " ...$pictureSize" let "x = x + 1" if [[ $x -gt $maxSearchTries ]]; then echo "ERROR: Did not find suitable image after $maxSearchTries tries." >&2 echo " Please make sure there are enough $res images in the search-folder" >&2 echo " Or use 'exact2' mode with preordered search-folder" >&2 exit 8 fi done echoIfVerbose "done." numImg=${#deleteImages[*]} echoIfVerbose "Using picture: '$image'" tmpImage="$outFile.$numImg.tmp.png" convert "$image" -resize "$res^" -gravity center -extent "$res" -quality 10 "$tmpImage" #"-quality 10" is specifically for .png deleteImages[$numImg]=$tmpImage sourceImages[$numImg]=$tmpImage fi if [[ "$mode" == "any" ]]; then # Mode: Any image will be resized to the given resolution if [[ $same -eq 0 || "$lastImage" == "" ]]; then image=${fileArray[$RANDOM % ${#fileArray[*]}]} lastImage="$image" fi numImg=${#deleteImages[*]} echoIfVerbose "Using picture: '$image'" tmpImage="$outFile.$numImg.tmp.png" convert "$image" -resize "$res^" -gravity center -extent "$res" -quality 10 "$tmpImage" #"-quality 10" is specifically for .png deleteImages[$numImg]=$tmpImage sourceImages[$numImg]=$tmpImage fi done # continuing special case mode 'down' and --same from inside the loop if [[ "$mode" == "down" && $same -eq 1 ]]; then for res in "${resolutions[@]}"; do numImg=${#deleteImages[*]} echoIfVerbose "Using picture: '$image'" tmpImage="$outFile.$numImg.tmp.png" convert "$image" -resize "$res^" -gravity center -extent "$res" -quality 10 "$tmpImage" #"-quality 10" is specifically for .png deleteImages[$numImg]=$tmpImage sourceImages[$numImg]=$tmpImage done fi concatenateImages "${sourceImages[@]}" --of="$outFile" $concatParams status=$? if [[ $status -ne 0 ]]; then echo "ERROR: concatenateImages has failed to concatenate the images. Exit status: $status " >&2 exit 11 fi if [[ ${#deleteImages[*]} -gt 0 ]]; then rm "${deleteImages[@]}" fi