#!/bin/bash # blurryCircles (or rays) wallpaper maker # needs: imagemagick, scrot or maim/slop, # schemer2 (https://github.com/thefryscorer/schemer2), # pngcrush (optional) # bash 4.3 # brex 2018 # license: WTFPL – Do What the **** You Want to Public License # benchmark start START=$(date +%s.%N) # rays else circles if [ "$1" == "rays" ] || [ "$1" == "r" ]; then rays="true" # rays or circles fi # config general where="$HOME/Pictures/blurryCircles" w="1920" h="1200" maxBright="240" # 220 minBright="60" # 50 howmany="12" # how many variations to render out parallel="4" # How many in parallel maim="true" # use maim instead of scrot (and you should) scanlines="true" # scanline fx, use scanlinesSrc as alpha image if true scanlinesSrc="http://cdn.scrot.moe/images/2018/04/03/stripesNegative3.png" # ^ this one needs internet, if that makes you nervous, copy the image to your hd and adjust this path. noise="true" # add some random noise noiseAmount="0.07" # noise amount vignette="true" # vignette (slow) vignetteBlur="150" # softness pngcrush="NOTtrue" # optimize/reduce size of output png images # config randomness beingRandom () { # circles circlesSize=$((500 + RANDOM % 1420)) circlesOpacity=$((1 + RANDOM % 5)) circlesSizeVariance=$((100 + RANDOM % 200)) threshold=$((1 + RANDOM % 50)) # rays angle=$((5 + RANDOM % 40)) # between 5 and 45 degrees } # config rays rayMul="3" # (3) ray oversampler multiplier when rayCrop or rayRotatePost are false # ^ reducing this will drastically increase render speed and decrease quality raysSize="22" # Size of rays in output image (default 16) raysSizeVariance="12" # Maximum variance in rays size (default 8) # either random rotate in post rayRotatePost="true" # random rotation of ray image in post (very slow due to large oversampling) rayRotateMul="6" # ray oversampler when rayRotatePost is true, note that numbers > 5 are extremely slow # or crop mode rayCrop="NOTtrue" # move center of rays to corner rayCropMul="4" # ray oversampler when rayCrop is true rayCropGravity="SouthWest" # What part to crop # tests mkdir -p "$where" cd "$where" || exit # checks if [ "$maim" = true ] ; then command -v maim >/dev/null 2>&1 || { echo "I need maim, exiting." >&2; exit 1; } command -v slop >/dev/null 2>&1 || { echo "I need slop, exiting." >&2; exit 1; } else command -v scrot >/dev/null 2>&1 || { echo "I need scrot, exiting." >&2; exit 1; } fi command -v schemer2 >/dev/null 2>&1 || { echo "I need schemer2 (https://github.com/thefryscorer/schemer2), exiting." >&2; exit 1; } command -v convert >/dev/null 2>&1 || { echo "I need imagemagick convert, exiting." >&2; exit 1; } command -v mogrify >/dev/null 2>&1 || { echo "I need imagemagick mogrify, exiting." >&2; exit 1; } if [ "$pngcrush" = true ] ; then command -v pngcrush >/dev/null 2>&1 || { echo "I need pngcrush, exiting." >&2; exit 1; } fi # tmp dir http://mywiki.wooledge.org/BashFAQ/062 tmpdir="/tmp/$RANDOM-$$" trap '[ -n "$tmpdir" ] && rm -fr "$tmpdir"' EXIT mkdir -m 700 "$tmpdir" || { echo '!! unable to create a tmpdir' >&2; tmpdir=; exit 1; } # random word dictionary function randomword() { dict="/usr/share/dict/words" shuf -n1 "$dict" | tr -dc '[:alnum:]\n\r' | tr '[:upper:]' '[:lower:]' } word=$(randomword) # where the magic happens action () { # CIRCLES if [ "$rays" != true ] ; then schemer2 -format img::img -in "$tmpdir/$name" -imageOutType circles -circlesBlurred -circlesFilled -circlesOpacity "$circlesOpacity" -circlesSize "$circlesSize" -circlesSizeVariance "$circlesSizeVariance" -minBright "$minBright" -maxBright "$maxBright" -threshold "$threshold" -width "$w" -height "$h" -out "$tmpdir/$n$name" # RAYS else # crop or not to crop if [ "$rayCrop" = true ] ; then rayMul="$rayCropMul" elif [ "$rayRotatePost" = true ] ; then rayMul="$rayRotateMul" fi # upsizing a bit due to aliasing problem schemer2 -format img::img -in "$tmpdir/$name" -imageOutType rays -raysLargeToSmall -raysSize "$raysSize" -raysSizeVariance "$raysSizeVariance" -minBright "$minBright" -maxBright "$maxBright" -threshold "$threshold" -width $(( w * rayMul )) -height $(( h * rayMul )) -out "$tmpdir/$n$name" # -raysLargeToSmall # -raysDistributeEvenly # offset center #mogrify -chop 19%x19% "$tmpdir/$n$name" # 19 is 38/2 (golden percent) if [ "$rayCrop" = true ] ; then mogrify -gravity "$rayCropGravity" -crop 50%x50%+0+0 +repage "$tmpdir/$n$name" #mogrify -crop 99.5%x99.5%+0+0 +repage "$tmpdir/$n$name" elif [ "$rayRotatePost" = true ] ; then # just some rotation (https://stackoverflow.com/questions/29244011/imagemagick-convert-rotate-crop) # angle is defined in beingRandom function ratio=$(convert "$tmpdir/$n$name" -format \ "%[fx:aa=$angle*pi/180; min(w,h)/(w*abs(cos(aa))+h*abs(sin(aa)))]" \ info:) crop="%[fx:floor(w*$ratio)]x%[fx:floor(h*$ratio)]" crop="$crop+%[fx:ceil((w-w*$ratio)/2)]+%[fx:ceil((h-h*$ratio)/2)]" convert "$tmpdir/$n$name" -set option:distort:viewport "$crop" \ +distort SRT "$angle" +repage "$tmpdir/$n$name" fi # scale back down mogrify -resize "$w"x"$h" "$tmpdir/$n$name" fi # https://www.imagemagick.org/discourse-server/viewtopic.php?t=21381 if [ "$noise" = true ] ; then convert "$tmpdir/$n$name" \( -size "$w"x"$h" xc:"gray(50%)" -seed "$circlesSizeVariance" +noise Poisson -modulate 100,0 -channel green -separate +channel \) \ +swap -compose Mathematics -define compose:args="0,1,$noiseAmount,-0.075" -composite "$tmpdir/$n$name" # overwriting itself here fi if [ "$vignette" = true ] ; then convert "$tmpdir/$n$name" \( +clone -fill white -colorize 100 -background "gray(70%)" -vignette 0x"$vignetteBlur" \) \ -compose multiply -composite "$tmpdir/$n$name" fi if [ "$scanlines" = true ] ; then convert "$tmpdir/$n$name" \( "$scanlinesSrc" -resize "$w"x"$h"\! \) -alpha off -compose copy_opacity -composite PNG32:"$tmpdir/$n$name" # overwriting itself here fi if [ "$pngcrush" = true ] ; then pngcrush -ow "$tmpdir/$n$name" &>/dev/null fi mv "$tmpdir/$n$name" "$where/$n$name" } set -x # naming convention name="$word"_$(date +%H%M%^b%d%y).png if [ "$maim" = true ] ; then maim -s -d 0.3 -c '0.1,0.1,0.1,0.3' "$tmpdir/$name" else scrot -s -d 1 "$tmpdir/$name" fi # autolevels of input in circles mode if [ "$rays" != true ] ; then mogrify -auto-level -normalize "$tmpdir/$name" fi # main loop n=0 # while counter c=0 # parallel counter while [[ $n -lt $howmany ]]; do if (( c++ >= parallel )); then wait -n; fi beingRandom action & n=$((n+1)) done wait # beep command -v beepspeakers >/dev/null 2>&1 && beepspeakers 1 # benchmark end END=$(date +%s.%N) DIFF=$(echo "$END - $START" | bc) echo "done in $DIFF seconds"