Advertisement
rhowaldt

moarsaic-v2

Jun 28th, 2015
357
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 6.25 KB | None | 0 0
  1. #!/bin/bash
  2. #
  3. # STFU/GTFO license:
  4. # this program is provided without guarantee and any "support" will be given at my own discretion.
  5. # if it breaks or does not do what you want, fix it yourself.
  6. #
  7. # a script for building a screen-size tile-mosaic-thingy out of colours extracted from an image.
  8. # by rhowaldt
  9. #
  10. # depends: xdpyinfo, imagemagick
  11. #
  12. # TODO: create flags for
  13. # --filter # send output through filter (separate script)
  14.  
  15.  
  16. #FUNCTIONS AND SHIT
  17.  
  18. usage()
  19. {
  20. cat << EOF
  21. usage: $0 -i [IMAGE] ([options])
  22.  
  23. This script makes a mosaic of your image.
  24.  
  25. OPTIONS:
  26.    -h Show this message.
  27.    -i [IMAGE] The image that will be used for the conversion.
  28.    -d [DIVISOR] A number that is used to calculate the amount of tiles. Default is 8.
  29.    -r [SIZE] Resize image to SIZE (width) before processing. Smaller=faster, yet gives less vibrant colours. Default is off.
  30.    -v After processing, open original and result in feh side-by-side.
  31.    -c [AMOUNT]  Amount of colours to extract from original. Default is 16.
  32.    -o [FILENAME] The filename to save the image to. Default is moarsaic-result.png.
  33.    -s STFU (Silencio). Warning: Will not prompt for huge amounts of tiles!
  34.    -f [FILTER] Send output through filter FILTER (N/A).
  35. EOF
  36. }
  37.  
  38. #VARIABLES AND SUCH
  39.  
  40. x="x" # this is pathetic, but who cares?
  41. MAXTILES=1000 # the amount of tiles needed to receive a prompt
  42.  
  43. OPT_IMAGE=
  44. OPT_DIVISOR=8
  45. OPT_RESIZE=0
  46. OPT_VIEW=0
  47. OPT_COLOURS=16
  48. OPT_OUTPUT="moarsaic-result.png"
  49. OPT_SILENT=0
  50. OPT_FILTER=0
  51.  
  52. while getopts "hi:d:r:vc:o:sf:" opt
  53. do
  54.     case $opt in
  55.         h) usage >&2; exit;;
  56.         i) OPT_IMAGE="$OPTARG";;
  57.         d) OPT_DIVISOR=$OPTARG;;
  58.       r)    OPT_RESIZE="$OPTARG";;
  59.        v) OPT_VIEW=1;;
  60.        c) OPT_COLOURS="$OPTARG";;
  61.        o) OPT_OUTPUT="$OPTARG";;
  62.        s) OPT_SILENT=1;;
  63.        f) OPT_FILTER=1;;
  64.       \?) echo "Invalid option: -$OPTARG" >&2; exit 1;;
  65.       :) echo "Option -$OPTARG requires an argument." >&2; exit 1;;
  66.     esac
  67. done
  68.  
  69. #THE WORKINGS
  70.  
  71. # 1. wanna know how many tiles
  72. read RES_X RES_Y <<<$(xdpyinfo | grep dimensions | awk '{print $2}' | awk -Fx '{print $1, $2}') # determine screen resolution: thanksss http://superuser.com/questions/418699
  73.  
  74. SMALLEST=$(( RES_X < RES_Y ? RES_X : RES_Y )) #find the smallest side
  75. if [[ $SMALLEST -eq $RES_X ]]; then
  76.    TILESIZE_X=$(( SMALLEST/OPT_DIVISOR )) #make sure still X=X
  77.    TILESIZE_Y=$TILESIZE_X # make them square
  78. else [[ $SMALLEST -eq $RES_Y ]]
  79.    TILESIZE_Y=$(( SMALLEST/OPT_DIVISOR ))
  80.    TILESIZE_X=$TILESIZE_Y
  81. fi
  82. TILES_X=$(( ( RES_X/TILESIZE_X ) + 1 )) #the amount of tiles along one side will always be 1 greater than the amount that fits - for now
  83. TILES_Y=$(( ( RES_Y/TILESIZE_Y ) + 1 )) #because what happens when it fits exactly...
  84. TILES=$(( TILES_X * TILES_Y ))
  85.  
  86. IMGDIM=$(identify "$OPT_IMAGE" | awk '{ print $3 }')
  87.  
  88. if [ $OPT_SILENT == 0 ]
  89. then
  90.     echo
  91.     echo "* * * * * M O A R S A I C * * * * *"
  92.     echo
  93.     echo "Image: $OPT_IMAGE ($IMGDIM)"
  94.     echo "Screen Resolution: $RES_X$x$RES_Y"
  95.     echo "Tilesize: $TILESIZE_X$x$TILESIZE_Y"
  96.     echo "Tiles: $TILES ($TILES_X$x$TILES_Y)"
  97.     echo
  98.  
  99.     # make sure you really want to hang your terminal
  100.     if [ "$TILES" -ge "$MAXTILES" ]
  101.     then
  102.         while true; do
  103.             read -p "Mate, this will create $TILES tiles. That's quite a lot. Proceed? " yn
  104.             case $yn in
  105.                 [Yy]* ) echo "Splendid Superninja, let'ssssssss do it!"; echo; break;;
  106.                 [Nn]* ) echo "Baibai."; exit;;
  107.                 * ) echo "Answer yes or no. It's not that difficult. Let's try again."; echo;;
  108.             esac
  109.         done
  110.     fi
  111. fi
  112. # 2. create a colour palette from the temporary image
  113.  
  114. # resize the image to save loads on speed with large wallpapers etc
  115. if [ $OPT_RESIZE != 0 ]
  116. then
  117.     [ $OPT_SILENT == 0 ] && echo "Resizing image to a width of $OPT_RESIZE..."
  118.     convert "$OPT_IMAGE" -resize $OPT_RESIZE tmp_image.png
  119.     WORK_IMAGE=tmp_image.png
  120. else
  121.     WORK_IMAGE="$OPT_IMAGE"
  122. fi
  123.  
  124. [ $OPT_SILENT == 0 ] && echo "Creating colour palette for $OPT_COLOURS colours..."
  125. PALETTE=$(convert "$WORK_IMAGE" -colors $OPT_COLOURS -format "%c" histogram:info:)
  126. [ -e tmp_image.png ] && rm tmp_image.png # check for tmp_image and remove if found
  127. HEXLIST=$(echo "$PALETTE" | sed 's/^.*\#\(.*\) srgb.*/\1/g') #grab just the numbers
  128. COL=("0" "8" "1" "9" "2" "A" "3" "B" "4" "C" "5" "D" "6" "E" "7" "F"); #these numbers need to be added to the front of the previous
  129. q=0
  130.  
  131. declare -a COLOURS
  132.  
  133. while read line; do
  134.       COLOURS=("${COLOURS[@]}" "$line"); #concatenate the shit.
  135.       let q=q+1
  136. done <<< "$HEXLIST"
  137.  
  138. # 3. get enough colours to fill all the tiles
  139. # pick randomly from the 16-colour list, removing each pick until none are left. repeat until all tiles are filled.
  140. declare -a COLOURTILES
  141. while [[ ${#COLOURTILES[@]} -lt $TILES ]] #check whether we are at $TILES yet.
  142. do
  143.    for index in `shuf --input-range=0-$(( ${#COLOURS[*]} - 1 )) | head -${TILES}`
  144.     do
  145.         COLOURTILES=("${COLOURTILES[@]}" "${COLOURS[$index]}")
  146.     done
  147. done
  148.  
  149. # 4. build a tile-mosaic-thingy out of the colours
  150. [ $OPT_SILENT == 0 ] && echo "Grab the lube in eager anticipation. Placing colours..."
  151. [ $OPT_SILENT == 0 ] && echo
  152.  
  153. # convert into imagemagick xc-tags (xc:#222222) and arrange in grid through append+/-
  154. COLLINE="(" # the line with the colour setup
  155. xcount=1
  156. ycount=1
  157. for (( i=0; i<${#COLOURTILES[@]}; i++ ))
  158. do
  159.     # echo "ycount: $ycount - xcount: $xcount" #debug for correct iteration
  160.     if [ $ycount -lt $TILES_Y ]
  161.     then
  162.         if [ $xcount -lt $TILES_X ]
  163.             then
  164.             COLLINE+=" xc:#${COLOURTILES[i]}"
  165.             xcount=$((xcount + 1))
  166.         else
  167.             COLLINE+=" xc:#${COLOURTILES[i]} +append ) -append ("
  168.             xcount=1
  169.             ycount=$((ycount + 1))
  170.         fi
  171.        
  172.     else # final row, final column
  173.        
  174.         if [ $xcount -lt $TILES_X ]
  175.             then
  176.             COLLINE+=" xc:#${COLOURTILES[i]}"
  177.             xcount=$((xcount + 1))
  178.         else # final colour
  179.             COLLINE+=" xc:#${COLOURTILES[i]} +append ) -append"
  180.             break
  181.         fi
  182.     fi
  183. done
  184.  
  185. # echo "$COLLINE" # debug for correct imagemagick syntax
  186.  
  187. convert $COLLINE -filter point -resize "$RES_X$x$RES_Y"\! $OPT_OUTPUT
  188.  
  189. # open original and result in feh side-by-side
  190. if [ "$OPT_VIEW" == 1 ]
  191. then
  192.     feh -m -H 410 -W 800 -E 400 -y 400 $OPT_IMAGE $OPT_OUTPUT
  193. fi
  194.  
  195. # Slight preparation for the filter-future:
  196. [ $OPT_SILENT == 0 ] && [ $OPT_FILTER == 1 ] && echo "Sorry, no filters yet."
  197.  
  198. [ $OPT_SILENT == 0 ] && echo
  199. [ $OPT_SILENT == 0 ] && echo "C'est fini. Saved as $OPT_OUTPUT"
  200.  
  201. exit
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement