FFmpeg: FAPA (Frame-Averaged Pixel Array)


Preamble: When I create a blog-post about a film, I will often include a cryptic looking pixelated image somewhere in the body of the post. When possible, I will create one of these images for every film I watch. I create them as a type of 'fingerprint', showing overall tonality and temporal dynamics of the film's visuals.

The image contains all frames in a given film. Each pixel represents the average colour of its particular frame. This colour is calculated by doing no more than scaling the frame to dimensions of '1x1' in a FFmpeg 'scale' filter. The frames [pixels] are then tiled into a single image of suitable dimensions.

The example video is taken from 'Summer in February (2013)' and shows a scene involving tropospheric lightening near the end of the film. The section of the 'pixel array' image relating to this scene has been highlighted and magnified. The contrast in lighting between frames means each frame can be clearly discerned as the video plays, even without the aid of the arrow.



The Bash script outputs basic information before and while processing. The process will take a reasonable length of time to finish. The version here uses two instances of FFmpeg to process the video. This is so progress feedback is displayed during execution. A simple single instance alternative is included in the 'Notes' section of the script, as well as ideas for showing progress while using this version. The script has not been updated since its initial creation and can probably be improved upon.

#!/bin/bash
################################################################################
# Create a 'Frame-Averaged Pixel Array' of a given video. Works by reducing
# each frame to a single pixel, and appending all frames into single image.
# - Takes: $1=Filename [$2=width]
# - Requires: ffmpeg + ffprobe
#   ver. 1.1 - 10th November, 2015
# source: https://oioiiooixiii.blogspot.com
###############################################################################

width="${2:-640}" # If no width given, set as 640
duration="$(ffprobe "$1" 2>&1 \
            | grep Duration \
            | awk  '{ print $2 }')"
seconds="$(echo $duration \
           | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }' \
           | cut -d '.' -f 1)"
fps="$(ffprobe "$1" 2>&1 \
       | sed -n 's/.*, \(.*\) fps,.*/\1/p' \
       | awk '{printf("%d\n",$1 + 0.5)}')"
frames="$(( seconds*fps ))"
height="$(( frames/width ))"
filters="tile=${width}x${height}"

clear
printf "$(pwd)/$1
___Duration: ${duration::-1}
____Seconds: $seconds
________FPS: $fps
_____Frames: $frames
_____Height: $height
____Filters: $filters\n"

# First instance of FFmpeg traverses the frames, the second concatenates them.
ffmpeg \
   -y \
   -i "$1" \
   -vf "scale=1:1" \
   -c:v png \
   -f image2pipe pipe:1 \
   -loglevel quiet \
   -stats \
| ffmpeg \
    -y \
    -i pipe:0 \
    -vf "$filters" \
    -loglevel quiet \
    "${1%.*}_$width".png

################################ NOTES #######################################

# Single line solution, but doesn't show progress
# ffmpeg -i "$1" -frames 1 -vf "$filters" "${1%.*}".png -y
# filters="scale=1:1,tile=${width}x${height}" # Used with single line version
# View ingest progress using: pv "$1" | piped to ffmpeg
download: video2pixarray.sh

[Note: I have struggled with giving a name to this process since I created the script, and have left it as the first thing I thought of. Perhaps others whom have creating something similar have better names for it.]

film review: https://oioiiooixiii.blogspot.com/2017/11/summer-in-february-2013.html

ANSI to HTML: Incorporating 'ansi2htm.sh', 'tiv', 'bat', 'GNU source-highlight', 'bash-drawille'

'tiv' [Terminal Image Viewer] with 'ansi2html.sh'
- Reproduce raster image in HTML unicode characters.


script -q /dev/null -c "tiv image.jpg" | ansi2html.sh > image.html
# output 'pre' tags refined with 'line-height' and 'font-size' styling 
N.B. Due to tag limits set for blog post content, this is only a screen capture representing the result. The actual html representation is demonstrated here: https://oioiiooixiii.blogspot.com/p/ansi2html.html


'bat', with 'ansi2html.sh'
- 'cat'-like application with additional syntax formatting and colouring.
   1 #!/bin/bash
   2 # An example Bash script
   3 # Version: 2018.08.19.19.33.05
   4
   5 function main() # An example function
   6 {
   7    local sentence="Hello, World!"
   8    for (( i=0;i<"${1:-1}";i++ ))
   9    {
  10       echo "$sentence"
  11    }
  12 }
  13 main "$@"
  14 exit

bat -n --color always --theme "1337" example.sh \
| ansi2html.sh --bg=dark > example.html

'bash-drawille' with 'ansi2html.sh'
- Convert raster image into Braille type HTML unicode characters.
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⣿⣿⣿⣿⢿⣿⣻⣿⣿⣿⣷⣿⣯⣿⣽⣿⡿⣿⣏⣿⣾⡿⣻⣽⣻⣯⣯⡿⣾⣳⡿⣯⣾⢿⢾⣟⡽⣯⣯⣹⣏⣯⣽⢯⡽⡯⣏⣗⡿⣺⢽⣝⢯⢽⡽⣳⢽⣞⣚⣞⠯⣗⢯⣖⡯⢯⡶⣏⣹⠶⢯⣚⣝⡼⣹⠶⣓⡧⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢿⡿⢿⣝⣟⣟⠯⠻⠝⢑⠹⠋⠹⠺⠿⠿⡿⣿⣝⣿⣟⣾⣻⣯⣽⣿⣽⣻⣽⣻⣿⣾⢿⣟⣿⣾⣻⣷⢿⣷⡿⣟⡽⣾⣷⣯⣹⣽⣹⣏⣟⣺⡷⣗⣻⣗⡷⣺⢽⢷⢽⢽⣝⢶⢽⣺⣹⢭⡯⡽⡽⣓⣞⣗⣞⠶⣏⣹⠾⣞⢭⡼⢧⣓⡽⣞⣱⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⣿⡿⢯⢹⣩⣪⠪⢩⠍⠨⠰⠢⠐⠂⠀⠀⠀⠀⠐⠀⠁⠈⠊⠉⠟⡍⠞⠭⣻⡽⣿⣟⣷⣿⣽⣯⣟⣽⣟⣾⣻⣾⣳⣻⣽⢿⣾⣽⢷⣻⡷⣾⣷⣗⣻⣺⣗⣟⣺⣟⢾⢽⣺⡾⣺⣝⣞⣫⡯⡗⡷⡯⢽⣳⣺⢭⢷⣖⡽⢧⣏⣹⢳⡗⣏⢳⡞⣞⢭⡼⣚⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⣏⡞⣭⠕⢙⡨⠊⡁⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐⠆⠆⡈⠹⢻⢷⢾⡿⢾⢿⣷⢿⣾⣻⣽⣻⣿⢾⣯⣗⣾⣯⣫⣻⡾⣷⣏⣽⣏⣯⣏⣯⢾⡷⡿⣺⢽⣏⣗⢷⣝⣗⢽⣞⣗⣳⣲⡽⣞⠯⣓⣞⢷⣚⢷⣚⢯⣚⣫⢳⣱⢷⢞⢭⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠓⣉⡝⣵⣕⠵⢊⢆⣌⢖⢈⢀⡀⢀⠀⠂⠄⠀⡀⠀⠂⠤⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠅⡀⠀⢪⡍⠏⠩⠝⠼⡻⡾⣽⣻⣽⣻⣟⣯⢷⡿⣯⣟⣝⣽⢷⣽⡷⣽⢷⡷⡯⣽⣺⣹⡷⣳⣳⣝⣟⡾⣺⡯⡶⣝⡾⣏⣏⢽⣺⡽⢭⣞⡞⢭⢷⡭⣳⣓⡽⡶⣏⢧⣫⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⡡⢒⢡⡯⣿⠏⡫⢖⠳⠕⡐⡰⡐⣂⠰⢐⠠⡢⢄⢌⡄⡐⠲⠅⡉⡢⡡⡠⡠⢆⠀⢀⠀⠀⠀⠡⠀⠀⠀⠤⢀⠀⠀⠁⠨⠋⢽⣳⣟⡽⣟⣾⢷⣟⢷⣿⢷⣟⣾⢯⣟⣞⣗⣻⡽⣽⣝⣯⢾⢽⣗⡯⡾⣺⡯⡾⣫⡷⣳⣣⣝⡾⡯⣗⣹⣺⠯⣳⢧⣳⡭⣳⠮⣗⣹⠶⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣻⠫⠔⢊⡚⡔⢕⠋⠡⣐⠆⢃⢔⢲⢊⡡⡩⣔⢦⢕⣕⡼⡭⢖⣅⡪⢕⡵⣏⡺⣪⠶⡵⢕⡕⠸⢣⢖⠦⠈⠈⠠⠀⠀⠀⠀⠢⢠⠀⠀⠈⠫⢾⡿⣷⡿⣯⣳⣿⡾⣯⣫⡷⣟⣾⡷⣟⣺⡷⡷⣗⣯⢽⣹⡷⡾⢯⡯⢽⣝⢷⢯⡽⡝⣫⢯⣜⡾⢽⢳⡧⣏⢯⣚⣹⡼⣹⠶⣫⢳⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⡛⠙⠑⡈⡂⠴⠪⢈⡉⣁⡨⢌⡑⡬⢜⣃⡥⡶⢮⣲⣷⣷⣿⢿⢾⡿⣺⣹⣹⢵⢮⣖⡯⣹⣹⢳⣪⡪⣂⠜⢯⢗⠀⠀⠀⠀⠀⠀⠀⠀⠐⠀⠀⠀⠀⠐⢯⢾⡿⣞⣯⡾⣯⣗⣽⣽⡷⣾⡷⣯⢽⢾⡷⡯⣽⢾⣏⣫⣟⢷⢽⢽⣝⣗⢷⣏⡯⣺⣹⡽⡭⣏⣏⣞⠯⣞⡞⣓⡽⣚⡽⣓⡽⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠢⠐⠈⠑⠑⠐⢐⢐⠂⠒⡌⢑⢌⢞⢕⢕⢪⣾⣯⣿⣿⣿⣿⣿⣿⣿⣳⣿⣾⣺⣻⣞⡽⣽⣽⢺⣺⠽⢼⡣⣆⠱⢎⠜⢂⠤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢺⣷⢯⣻⢷⣟⣟⣹⢾⣟⣾⡷⣯⢽⣏⣯⢽⡷⡯⣽⢷⢾⢯⡯⣺⣫⡯⡾⣝⣗⣗⠯⡯⢽⣹⢼⢽⣺⡼⢽⡽⢭⡭⣳⢳⡞⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⠱⣕⣱⠧⡔⢐⠁⠈⡀⢠⢙⠪⣎⡱⣑⣲⢯⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣾⣿⣻⣟⣝⣗⣛⣗⡮⢞⡳⢞⠵⢮⡪⡔⠙⢆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⢽⣻⡾⣿⡷⣟⣞⢷⣯⢾⡷⢾⡯⣽⣺⣻⣹⡯⣗⣏⡯⡷⣽⢾⣝⣗⢷⣳⢽⣺⣫⢽⡭⡯⣗⡧⣗⣞⡝⣹⢼⢧⣳⠷⣫⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠯⢔⢱⠯⡉⠥⠱⠀⠈⡐⣊⡼⢽⡪⢎⢼⣽⣷⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢾⣻⣫⡷⢷⡽⢭⣍⡗⡵⡩⡳⡪⢕⢃⠨⠈⡂⠐⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢽⡾⣽⢾⣿⡾⣟⢿⣞⣽⢯⡷⣽⣯⢽⣽⣹⣗⡯⢷⡾⢯⢽⡽⣝⢷⢽⣗⣳⡾⣺⣳⡯⣺⣹⠽⣳⣹⣺⢷⣓⢯⢳⡞⣝⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣑⠮⠈⠘⠂⠒⠐⠠⡈⣎⡭⣳⡞⡨⣏⣽⣿⣿⣿⣿⣿⣿⡿⣿⣿⣷⣿⣿⣯⣫⣏⢷⣝⡼⢮⡱⣎⢎⡪⡎⡪⢎⢁⠅⡀⠂⢈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠰⢽⢽⣽⢯⣏⣻⣻⡷⣻⢾⡷⣟⢾⢾⣺⡷⣗⣻⡷⡷⡷⣻⢽⡽⣫⡷⣝⣗⣺⣫⢷⢯⣺⣓⣝⡾⢷⣓⢫⣳⣫⢳⡞⣏⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⡿⣗⣡⠀⠀⠀⡀⠆⠰⣕⡽⠮⣏⡪⣲⣻⣿⡿⣿⣿⣿⣿⣿⣿⣿⢿⣿⣯⢿⡷⡿⣺⡼⡞⣪⣃⢝⣊⡪⠎⡪⠕⡂⢈⢐⢃⡈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢐⠪⡼⣟⣾⢷⣟⣝⡷⣟⡷⣟⢾⢷⣻⣹⡷⣻⢾⣗⣽⣫⣞⣞⢽⣝⢷⢽⣝⣗⣗⢷⡾⣝⢭⡯⣗⣳⡽⢭⡯⣏⡗⣏⣓⡾⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣻⣿⣿⡇⠀⠀⣐⢖⣃⣞⡷⣟⢿⢪⢮⡽⣿⣾⣟⣾⣿⣟⣟⣟⣫⣻⣻⣽⢽⣹⡷⣞⠽⣎⢮⡰⣍⢮⡪⡚⣑⢃⢘⢈⠄⠆⢒⡈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠂⢈⢊⢭⣟⡷⣯⣗⣯⣳⣟⡽⣯⢿⡾⡽⣽⡷⡷⣻⣹⣽⣹⣹⡷⡯⡽⣫⡯⣺⣫⣺⣓⣏⡯⣹⣹⣺⢼⣞⠯⣜⡽⣓⡾⡾⢭⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠇⠀⠀⢑⠨⢾⢾⡿⢽⢝⢼⣽⣻⣯⣿⣷⣿⣿⣟⣿⡿⣽⣳⢿⡷⢽⡽⣹⡼⣣⢝⠮⡼⣣⢕⠎⡰⡘⣂⠍⡂⠡⠔⠰⠰⠘⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐⢎⢼⢽⢷⣟⡯⣻⣽⢾⣗⣽⣟⣺⢷⡷⡷⣯⢽⣺⣺⣹⣹⣗⣟⢾⣺⣫⢽⣝⢽⡭⢷⣫⣺⢼⣗⠯⢯⢯⢳⣳⡭⢷⣓⣞⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡆⠀⠠⠌⠐⢞⣻⣟⡱⣏⣽⣟⣿⣟⣿⢿⣷⣟⣿⣻⣷⡿⣞⣽⣽⣽⣯⢷⣚⢮⣑⢎⡮⢎⢦⡵⡡⡱⠢⡈⢁⠄⢈⢁⠂⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⡪⡯⣿⡾⣟⣞⣽⢾⡯⣽⣯⢽⢾⡷⣯⢽⡽⡽⣻⣝⣫⡯⣗⢷⡽⣝⢷⢽⡯⡾⣗⢷⣏⡯⢽⣺⡽⡝⣗⣏⡗⣏⣞⢭⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡆⡐⢀⢈⡸⢽⣝⣜⡽⣿⣷⣿⣺⣿⡿⣿⡿⣿⣿⢿⣟⣹⢽⣷⡿⣝⡳⣩⠳⢱⡕⢱⡣⢗⡕⠕⡊⢡⢁⠐⡐⡀⠂⠁⡐⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠌⢈⢽⣝⣽⡽⣷⢿⡷⢿⣞⣯⣹⡯⣟⣺⣗⣳⣳⣽⣫⣞⣗⣗⢷⣽⣣⢷⢽⢽⣞⣚⣗⣗⡯⡗⡷⡯⢽⣺⡼⣹⣺⡼⢯⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡢⣇⢆⠢⡡⢞⣚⡾⣽⣻⣿⣽⣿⣟⣻⣞⣗⡷⣺⢳⢝⠰⢺⢳⡗⢕⢍⢊⡢⣱⢪⠕⠎⠔⡰⠨⠆⠅⣈⠂⡈⠀⠐⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⠅⠀⡄⣪⣏⣽⣯⣺⢷⣯⢿⣞⡽⣯⢾⡷⣏⣟⣺⢽⣽⣝⣹⡷⣺⣳⡾⢾⣝⣞⡯⡾⢽⡭⡽⣗⢽⣹⡽⡭⢷⣓⢯⣣⢳⡞⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣗⢞⡪⡪⡪⢞⢭⣻⣽⣿⡷⡽⣯⢿⡯⣻⠾⠣⠣⡐⠂⢸⢖⡈⠀⠈⠡⢉⢢⠅⠊⠲⠮⡁⠀⠀⠐⠀⠐⠄⠂⠁⢀⠂⢀⠂⠄⠠⠀⠀⠀⠀⡀⠀⠀⠀⠀⡂⠰⢬⢾⢷⣯⡯⣻⢿⣞⢾⡿⢾⡷⣗⣟⡾⡷⣻⣝⣺⣹⣹⣗⢽⣝⡷⡾⣽⡝⣫⡯⣳⢽⣞⢯⡽⣳⣹⣹⣗⣞⢳⣺⡽⢧⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣽⡾⣯⢎⢮⠯⡯⢾⣻⣏⣯⣾⡷⡵⢞⠴⠀⠀⠀⠄⠀⠜⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐⠀⠁⠆⠄⢁⠀⠄⠀⠀⠀⠀⡀⠄⢁⠀⠀⠆⠆⢌⡯⣿⢯⣟⣝⣻⡿⢾⡿⣻⢾⣽⣹⡷⣻⢾⡯⣻⣝⢯⡯⡯⡽⣫⡯⡾⣺⢯⣞⡯⡽⣳⣣⣜⡾⢷⣓⣺⡼⢽⣲⢫⣳⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣷⡷⢵⡷⣏⡙⡹⠍⠗⠈⠀⠀⠀⠀⠀⠀⠀⠀⡀⣠⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢂⠂⠅⡀⠐⠈⠀⠈⠐⠀⠀⠀⠁⠀⢀⢄⢥⣲⡿⣽⢿⢾⣟⣾⣷⢷⣯⡷⣯⡷⣯⢽⡯⢾⡷⣝⣯⣝⣗⢽⡽⢷⢾⣫⡯⢽⣝⣗⣺⡽⡝⢫⢷⡾⡝⢷⣓⠯⣗⡗⣏⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣽⣿⡾⢮⠔⠅⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠨⣿⣿⣗⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⢐⠀⠀⠌⠠⠄⠂⠀⠀⠁⠁⠂⢐⠀⠀⠀⠄⠀⠐⢆⡯⡯⣽⡽⣽⢽⡷⣾⢷⣽⢯⣳⣟⢾⡷⣻⢾⣝⣯⣗⣯⢯⢯⣯⢾⢽⣝⡯⡾⡯⡽⡽⣗⢯⣞⣳⡯⣹⣺⣗⣞⠯⣏⢧⣏⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡯⢷⣇⡐⡠⡐⢄⠄⠀⠀⠀⠀⠀⠀⢀⣲⣿⣿⣿⡟⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠂⠐⢀⢂⠨⡂⠰⡀⠁⠀⡀⠀⠀⠀⡁⠀⠀⠀⠀⠀⠄⡲⣻⣺⣳⣷⢽⣯⢾⣺⣹⡯⣽⣟⣺⡷⣟⣽⢾⣏⣟⣏⣗⣟⣺⢾⣏⡯⡾⢽⣝⢽⣝⣺⣣⣳⡽⣺⢽⣳⣓⣺⡼⢯⣲⣫⢳⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢺⣯⣿⣿⣭⢕⠣⠄⠂⠀⠀⢀⢠⣸⣷⣿⣿⣏⡇⢁⠈⢒⠀⠀⠀⠀⠀⠀⠀⢀⠀⠠⢐⠢⠌⡁⠀⠂⠀⠈⠀⠁⠀⡀⠀⢀⠈⠀⠀⠀⣕⢾⢾⡯⡾⣺⣫⣺⣣⣳⢷⣞⣗⡯⡽⣻⣹⣺⣞⢾⡯⣻⣝⣹⡷⡯⡽⣫⣟⢷⢽⡯⡶⣫⡯⣏⣗⡯⣖⣞⡝⣳⣚⢷⣚⢯⣚⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣟⣻⣿⣿⣷⣆⣂⡄⡀⣰⣳⣾⡿⣯⣿⣿⣓⢇⠄⡈⠡⠆⢃⢂⠆⡂⠄⠅⡈⠡⠰⠐⠂⠠⠁⠀⠀⠀⠀⠀⠈⠀⠀⠄⠄⠐⠀⠀⠠⢺⣳⡷⣫⡯⣫⢯⣳⢷⣺⣓⣗⡯⣹⣹⣳⣫⣞⣞⡯⣽⡷⡷⡷⣽⡯⣽⢷⢽⣝⣗⢽⣹⢷⢯⢾⢼⡧⡷⡯⢯⢫⣳⢭⣳⡽⢭⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡭⣎⢫⡽⣿⢿⣿⢿⣧⣽⣷⡯⢿⢿⢾⣿⢽⡳⢮⡃⡀⠈⠀⠀⠖⢎⢔⢆⠆⡂⠁⠄⠠⠄⠀⠈⠀⠄⠀⠀⠀⠀⠐⠅⠀⠁⠐⠀⠀⢠⠯⠾⣺⡯⡾⡾⣺⣹⣹⡾⣝⠽⣳⡗⡯⣞⣺⣚⣗⣝⣗⢽⣺⣞⣗⣗⢷⡾⣺⡯⡾⡯⡾⣫⢷⣏⣏⣺⣹⢭⢯⡯⣏⡧⣏⣹⢺⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣖⡵⣱⢯⡯⣗⣷⣿⡷⢯⠍⠐⣹⢿⣿⢷⣞⠵⡃⠀⠀⠀⠀⠀⠀⢊⡩⢆⡃⠜⡂⠆⠠⠁⠀⠂⠀⠆⠀⠀⠠⠀⠀⠀⠀⢀⢐⠰⢵⢽⣝⣗⢷⢽⢯⣞⣜⣗⠽⣗⣹⣺⣲⡽⢯⣲⢳⣺⢳⢷⣝⣗⡷⣽⢽⣝⡯⡾⣫⡯⣫⢯⢾⢺⡧⡷⣏⣏⣞⠯⡼⡽⣖⡯⢧⣏⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⣎⢳⡞⣗⣗⡯⡾⡎⠑⠁⠀⠠⢽⡹⣋⠽⠎⠕⠈⠀⠀⠀⠀⠀⠀⠀⠐⠁⠈⠁⠠⠈⡈⠀⠐⠠⢀⠀⠀⠀⠈⠀⠀⠁⡂⢱⢦⢵⢳⢷⣗⣺⣫⡯⣺⣹⢽⡭⡽⡾⣳⣓⣳⣚⢷⣓⠷⣏⡧⣏⡭⡯⡾⣺⡯⡽⣫⡯⡾⣺⢽⣝⡽⡾⢯⢽⣳⣚⢯⢯⡾⡭⣖⡽⣧⣯⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⡽⢎⡵⣏⢕⢎⠈⠀⠀⠀⠠⣌⠈⡈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⠈⠂⠀⠀⠀⠀⠀⠀⢨⣪⠽⣺⣣⣳⡽⣞⢯⢯⢯⣺⡼⣺⢽⡭⢯⣞⢭⡭⢯⡽⢭⢯⢳⣹⡲⢯⣚⣏⣏⡯⡾⣺⣫⡾⣺⣺⣫⢫⡯⣗⣳⢭⡯⣗⣺⢽⢺⣹⠽⡼⡽⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢮⢪⢗⠢⡃⠐⠁⠀⠀⢀⢼⢾⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠌⠀⠀⠀⠀⠀⢜⢷⣫⢭⡯⡽⣗⡯⣖⣞⣺⢯⣣⡯⢧⣫⢳⡞⣏⣹⢼⢧⣫⢗⡾⣓⡯⢳⡞⣲⡽⢽⣞⣗⢷⣺⣓⣝⣞⣳⡽⡗⡯⣏⣗⡧⣗⡯⢧⡽⢯⢳⡞⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣝⠰⡂⢈⠀⠀⠀⠨⢵⡷⡷⣽⣑⠄⠀⠀⠀⠀⠄⡀⠰⠂⢀⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⡉⠓⣝⡾⡯⣏⣞⠯⢷⣣⡽⡭⣞⡝⢯⣓⢯⢳⣞⠽⡼⢧⢳⡞⣞⢭⢯⣚⣝⢼⣺⢯⢯⢽⣫⢯⣗⣳⢯⢽⢾⢼⣹⣹⣚⡾⣳⣞⢳⣺⡯⢧⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡔⡡⠥⠀⠀⠀⡁⠂⠸⡹⣹⢻⣞⢆⠰⠄⠀⠂⠈⠐⠀⠀⠈⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣽⡧⠀⠘⢝⣺⢼⣹⣺⢭⢷⣹⢺⣞⠽⣞⡭⣏⡳⢗⣝⡳⡞⣏⡼⣹⠶⣍⣳⠶⡯⢧⣳⡽⣝⢾⢺⣺⢯⢭⢯⣏⣏⢯⣖⡾⡭⣖⡯⢽⣲⢫⣳⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣏⡒⢁⢂⣖⠂⠀⠀⠠⣀⣀⡈⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⣿⣿⡇⠀⠀⠸⣳⢧⣗⢯⣓⢯⢳⣺⠽⡼⢧⣏⡵⢧⣫⣓⡧⣫⢳⢧⣹⡼⢞⠽⡼⣹⠾⣜⡾⡯⣏⡗⣗⡯⢽⣺⢼⣺⢽⣜⡽⣹⡼⣞⠽⡼⢽⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡆⠐⢱⢎⢂⠀⢀⢴⡭⣹⢳⡹⡫⡛⠕⠀⠀⠐⠀⠐⠀⠀⠄⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐⣽⣿⣿⣷⠀⠀⠀⠀⠧⣫⢳⣳⢯⣚⣓⡽⡭⣳⠶⣏⣹⢖⡭⣳⡼⢧⣓⡵⡳⡞⣏⢳⣹⠾⣗⣺⣚⣗⡯⢽⣗⣺⢯⢳⢯⣲⡭⢷⣳⣚⣓⡽⢳⡞⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⣿⣿⣿⣄⠌⡑⠅⢸⡾⢷⢯⢞⡌⠌⡠⡈⠌⡀⠀⠀⠀⠀⠀⠀⡁⠠⠐⠀⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢴⣿⣿⣿⣷⠀⠀⠀⠀⠀⠀⠯⢧⣞⢭⡭⣳⠽⣜⡞⣕⣏⢳⡞⣕⡵⡞⡭⡞⡳⢧⡹⣜⢞⣹⣓⣞⡽⡭⣗⣺⣖⡽⡧⣷⠯⣳⣧⣯⣞⢭⣳⣿⣏⣽⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⡿⠗⠆⠐⠡⢪⢯⣽⣹⣷⣹⣯⣚⢎⡦⢆⢣⣂⢀⠂⠠⠰⠂⡀⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⡓⠀⠀⠀⠀⠀⠀⠀⠀⠐⠫⡝⡲⢯⡹⡼⢞⡼⢮⣓⢧⡹⣎⣣⠯⡵⢞⡹⣎⢧⠯⣞⣞⠯⣗⣯⣶⣳⣷⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠻⠛⠋⠁⠁⠀⠀⠀⠀⠀⠀⠀⢪⢹⣫⣟⢽⡾⢫⢯⡺⡕⠯⡳⠮⡰⢂⠂⠈⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⠙⠳⠮⣍⡞⡭⡞⣱⢫⣣⠽⢼⡹⢎⡵⡝⣖⢯⢽⣽⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠻⠟⠉⠉⠀⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣍⠥⡪⢓⡫⡸⢝⢊⡪⠎⠣⠚⠂⠑⠁⠀⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣿⣿⣿⣿⣿⡋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠓⠱⠋⢜⢧⡳⢞⡳⣩⠯⡼⣿⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠛⠛⠁⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⡇⠀⠀⠀⡈⡐⠑⠄⢁⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠑⢝⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠃⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣇⠀⠀⠀⠀⠂⡂⢁⠨⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⣾⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏⠁⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣬⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠨⢂⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣻⢿⣹⠶⢏⡽⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀
⣿⣿⣿⣿⣿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣿⣿⡿⣿⣿⣿⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣿⣿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠈⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣤⣿⣿⣿⣿⣿⣿⣿⣿⣗⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣲⣿⣿⣿⣿⣿⣿⣿⢿⢺⢭⣓⢧⢯⡹⡵⡞⣏⡳⣧⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣻⣿⣿⣿⣿⣿⣿⣿⣷⣿⣿⣿⣿⣟⣿⣿⣿⣿⣿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⣿⣿⣿⣿⣿⣿⣿⡫⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⡽⢞⣍⣳⢳⢭⢝⡼⡞⣹⠶⣏⣿⣿⣿⣿⣿⣿⣿⣿⠀
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣻⣿⣿⣿⣿⣿⣾⣿⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⢿⣿⣿⣿⣿⣿⣹⣖⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣺⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣞⢭⠶⣏⢧⠯⢯⣚⡵⢧⣫⣿⣿⣽⣿⣿⣿⣿⣿⣿⠀
⣿⣿⣿⣷⣿⣿⣿⣿⣿⣿⣷⣿⣿⣿⣿⣿⣿⣿⣿⣯⣿⣿⣾⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠛⣿⣿⣿⣿⣿⣿⣀⠕⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣻⢳⣿⣽⣽⣿⣿⣿⣿⡟⣍⣳⣯⣿⣿⣿⣿⣿⠀
⣿⣽⣿⣿⣯⣿⣿⣷⣿⣻⣿⣿⣿⣿⣿⣽⣯⣿⣿⣿⣿⣯⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⢼⣾⠎⣿⣿⣿⣿⣽⡪⣒⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠓⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣿⣿⣿⣿⢯⠽⣟⡼⡝⣶⣷⣿⣿⣿⣿⣿⠀
⣿⣿⣾⣿⣿⣿⣷⣿⣿⣿⢿⣿⢿⣿⣿⢿⣻⣿⣿⣯⣿⣽⣿⠟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡸⣯⣽⣿⣻⣿⣹⣿⣿⣿⡕⡆⡀⠀⠠⠀⠂⢠⣼⣻⠽⣜⡝⡪⠜⡸⠟⢿⣿⣿⣿⣟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀
⢿⣿⣿⣻⣻⣿⣿⣿⣟⣿⣟⣿⣿⡿⣿⣿⣿⢿⣿⣿⢿⣿⠟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣷⣿⣿⣿⣿⣿⡔⠔⠄⢀⣵⡿⣺⣓⡯⡣⣃⢕⢕⢎⢔⢕⡻⢙⢛⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀
⣿⣿⣿⣟⣟⣿⣟⣿⣿⣿⣻⣿⡿⣿⣿⣿⣾⣿⣷⣿⣿⡽⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⡂⠸⣿⣷⣷⡯⡳⢕⢪⢮⣵⣺⣾⡾⣮⣧⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀
convert-image.sh | ansi2html.sh > braille.html
# output 'pre' tags refined with 'line-height' and 'font-size' styling 


GNU 'source-highlight'
- Print source files [e.g. Bash scripts] with colour syntax highlighting.
01: #!/bin/bash
02: # An example Bash script
03: # Version: 2018.08.19.19.33.05
04:
05: function main() # An example function
06: {
07:    local sentence="Hello, World!"
08:    for (( i=0;i<"${1:-1}";i++ ))
09:    {
10:       echo "$sentence"
11:    }
12: }
13: main "$@"
14: exit
source-highlight -n -f html -i example.sh -o example.html

ansi2html: https://github.com/ralphbean/ansi2html
tiv: https://github.com/stefanhaustein/TerminalImageViewer
bat: https://github.com/sharkdp/bat
GNU source-highlite: https://www.gnu.org/software/src-highlite/
bash-drawille: https://github.com/mydzor/bash-drawille
additional info: https://oioiiooixiii.blogspot.com/2018/03/bash-seven-applications-designed-to.html
image source: (CC BY 2.0) https://www.flickr.com/photos/usdagov/20190061980
image source: http://www.thejournal.ie/readme/vincent-brown-eighth-amendment-yes-vote-4026621-May2018/

Bash: Create a cacophony of voices with 'Mimic' text-to-speech



A somewhat grotesque and macabre presentation of 'Mimic's text-to-speech functionality. The concept arising after recently trying out 'Mimic's features and capabilities. As a short review; I believe 'Mimic's main strengths lie in its speed and ease of execution on the command line, similar to that of 'espeak'. Other more featured text-to-speech solutions can be slow and cumbersome to initiate.

N.B. In the video, there are an unfortunate number of artifacts in the audio. These only manifest in PulseAudio stream recording and are not present while monitoring the audio in real-time.

#!/bin/bash
# (GNU bash, version 4.4.19(1)-release)
#
# Create a cacophony of 'Mimic' text-to-speech voices, using words found in the
# system's 'words' file. Note: The concept can be applied to any text-to-speech
# software and, as such, a rudimentary function using 'espeak' is included.
# (Mimic info: https://mycroft.ai/documentation/mimic/)
# - Optional parameters: '$1' number of words - '$2' Number of voices
#
# Version: 2018.08.11.15.54.15
# Source: https://oioiiooixiii.blogspot.com

function randWords() # RETURNS PUNCTUATED LIST OF WORDS FROM SYSTEM DICTIONARY
{
   shuf </usr/share/dict/words \
   | head -"$1" \
   | awk 1 ORS='. '
}

function randNum() # RETURNS RANDOM NUMBER BETWEEN '$1' and '$2'
{
   shuf -i "$1"-"$2" -n 1
}

function randVoice() # RETURNS NAME OF RANDOM MIMIC VOICE
{
   local voices=("ap" "slt" "kal" "awb" "kal16" "rms")
   printf "${voices[$(randNum 0 ${#voices[@]})]}"
}

function mimicSpeak() # INVOKES 'MIMIC' APPLICATION
{
   mimic \
      -voice "$(randVoice)" \
      --setf int_f0_target_mean="$(randNum 20 180)" \
      --setf duration_stretch="$(randNum 1 12)" \
      <<<"$1"
}

function espeakAlt() # INVOKES 'ESPEAK' ALTERNATIVE
{
   espeak \
      -p "$(randNum 1 200)" \
      -s "$(randNum 1 100)" \
      "$1"
}

function main()
{
   clear

   for (( i=0;i<"${2:-5}";i++  ))
   {
      local sentence="$(randWords "${1:-5}")"
      echo "$sentence"
      mimicSpeak "$sentence" &
      #espeakAlt "$sentence" &
   }
}

main "$@"
exit

#### NOTES: One line concept

# shuf </usr/share/dict/british-english \
# | head -5 \
# | sed ':a;N;$!ba;s/\n/. /g' \
# | tee > \
#   (
#       mimic \
#          -voice slt \
#          --setf int_f0_target_mean=50 \
#          --setf duration_stretch=16 \
#   )
download: mimic-cacophony.sh

Brutal Doom: Stablised




Zandronum window stablised using default 'VidStab' stablisation settings via FFmpeg.

related: https://oioiiooixiii.blogspot.com/2016/09/ffmpeg-video-stabilisation-using.html
more info: https://doomwiki.org/wiki/Project_Brutality

Russia needs to get its act together

An image comparing two news stories. On the top left: 19-year-old mass-shotting killer Nikolas Cruz being arrested on the ground. The ground is replaced with the american flag and the image of an AR-15 assault rifle is included. Underneath are the stats: 'AMERICAN TEEN, SPORTING EQUIPMENT, AMERICAN HIGH SCHOOL, 17 DEAD'. On the top right-hand side of the image: A silly-looking Владимир Путин (Vladimir Putin) stands in front of St. Basil's Cathedral. In his hand, an open tin-can with noxious green fumes emanating from it. THe tin-can has warning symbols and 'NOVICHOK' labels. At the bottom of the can in hand writing are the words: '100% cyka blyat!'. Underneath are the stats: 'RUSSIAN FEDERATION,MILITARY GRADE NERVE AGENT, ENGLISH PARK BENCH, 0 DEAD.'

While our American friends show how it's really just child's play, Vova, with his persistent love of Rube Goldberg mechanics, makes himself look like a really bad Bond villain...

James Bond: "Do you expect me to talk?"
Bond villain: "Haha no Mr. Bond, I expect you suffer a suspicious, but recoverable, ailment in a public place, using an easily traceable substance, in the middle of the most tense geopolitical situation since the Cold War, weeks before my country hosts the FIFA World Cup."

context: https://en.wikipedia.org/wiki/Sergei_Skripal
context: https://en.wikipedia.org/wiki/Stoneman_Douglas_High_School_shooting


A silly-looking Владимир Путин (Vladimir Putin) stands in front of St. Basil's Cathedral. In his hand, an open tin-can with noxious green fumes emanating from it. THe tin-can has warning symbols and 'NOVICHOK' labels. At the bottom of the can in hand writing are the words: '100% cyka blyat!'

FFmpeg: Colour animation from macroblock motion-vectors



The animation is created from styling the macroblock motion vectors, as displayed by FFmpeg, rather than by manipulating the actual video content. The blocks of colour are created by stacking 'dilation' filters on the motion-vector layer. Before being dilated, the colouring of the arrows is extracted from the original video by 'colorkey' overlay. Based on an earlier filtergraph experiments.¹

#!/bin/bash 
# Generate stylised animation from video macroblock motion vectors, 
# and present in a side-by-side comparison with original video. 
# version: 2018.03.28.21.08.16 
# source: https://oioiiooixiii.blogspot.com 

cropSize="640:ih:480:0" # Adjust area and dimensions of interest

ffplay \
   -flags2 +export_mvs \
   -i "$1" \
   -vf \
      "
         split [original][vectors];
         [vectors] codecview=mv=pf+bf+bb,
                   crop=$cropSize [vectors];
         [original] crop=$cropSize,
                    split=3 [original][original1][original2];
         [vectors][original2] blend=all_mode=difference128,
                              eq=contrast=7:brightness=-0.3,
                              split [vectors][vectors1];
         [vectors1] colorkey=0xFFFFFF:0.9:0.2 [vectors1];
         [original1][vectors1] overlay,
                               smartblur,
                               dilation,dilation,dilation,dilation,dilation,
                               eq=contrast=1.4:brightness=-0.09 [pixels];
         [vectors][original][pixels] hstack=inputs=3
      "



¹ see also: https://oioiiooixiii.blogspot.com/2016/09/ffmpeg-create-video-composite-of.html
source video: りりあ (LILIA)https://www.youtube.com/watch?v=U1DFzSlNkV8 (used without permission) m(_ _)m

Bash: Seven[+] applications designed to display images in a terminal



UPDATE: 22nd November, 2019
Added version that uses 'mpv'. Details at bottom of blog-post

Personal notes on seven programs that provide some ability to display images in a POSIX terminal interface [bash environment specifically]. This is in no way an exhaustive list, nor does it claim to highlight the best applications available. These are merely notes made recently while investigating a solution for such a task.

source image: '"Michael Gehlert" by Harald Peter' http://piqs.de/fotos/192320.html

Review: Winter Olympics 2018

High above the Olympic village, dastardly Vova Putin flies upon his diabolical meldonium powered Dope Rocket™, sprinkling athletes with his dope juice. - February 26, 2018

The 'Games' this year seemed a bit dull and uninspiring. Perhaps that is just my own perception though. Perhaps there weren't enough Time magazine covers with barbed wire Olympic rings, stories about weird toilets, warnings of 'Black Widows' blowing up planes with toothpaste bombs, or comparisons to the 1936 Berlin Games with premonitions of homosexuals being exterminated, to heighten my attention and excitement. The only bit of drama came from the ever persistent 'Russian Doping Scandal' story.

'Doping' seems to mean a lot of things these days. If you rub the wrong boil ointment on your arse, it's classed as 'doping'. It doesn't mean unusual amounts of asthma medication, or Japanese figure skaters winning gold medals 'doped' up on pain killers though.* Sport is filled with the dopes: the athletes, the officials, the journalists.¹

I liked the pre-recorded 'drones' section of the opening ceremony. Although what I missed was the outrage and accusations of 'State media censorship' when they switched to it, like there was when a back-up recording was used in the 2014 Sochi Games after there was a malfunction in the most important image of the Games: The appearance of the Olympic rings. That meant there was no similar 'feel-good' moment in the closing ceremony, like in Sochi when the organisers mocked themselves over the malfunctioning Olympic rings and the West collectively gasped: 'oh my goodness, Russians must be human too?'.

I thought it very nice that the USA sent vice-president Pence to the games, to sit next to the DPRK representative. The DPRK; the most sanctioned country in the world; the country, we're told, who might blow up the planet at any moment! The USA were unable to send anyone to Sochi though, because "Russia".²

There was no snow in the Republic of Korea, so they manufactured it all. Again [like a broken record]: Four years ago, we heard complaint, ridicule, and mockery, about how the Sochi snow wasn't 'real snow' and how embarrassing it was to have to put it there artificially.³

Alpine skiing: Not bad. Personally, it was a bit of a flop due the German women's team not doing so well. More importantly, their racesuit was the worst I've ever seen (and we thought the 'go faster stripes' of Sochi were bad!). Highlights: Poor American performance; Super-G race where Ester Ledecká pipped Anna [Fenninger] Veith for the gold medal.

All in all, a lackluster Games; very utilitarian. Russia didn't exist; America and China results were woeful.

* http://the-japan-news.com/news/article/0004254098

¹ I find the whole topic of "drug" use in sport difficult to resolve. Humans are electro-chemical machines, we exist in, and are, chemistry. We can't be measured like the length of a ski, or number of bullets in the magazine of a biathlon rifle. "Drugs" seem like an intangible thing to track without some level of hypocrisy. As an example, there's already a potent stimulant that's classed as uncontrollable: Trimethylxanthine, aka, caffeine. Maybe its legal status is helped by the fact that all these sporting events are sponsored by caffeinated beverages.

² "the 1980's are now calling to ask for their foreign policy back" - Barack Obama.

³ How much energy was used to generate this snow? We'll be lambasted with Global Warming warnings, and how traditionally snowy areas are now snowless due to rising temperatures, meanwhile we'll burn up the planet to put snow back into these places. It seems like a downward spiral.

"Snow" pic.twitter.com/l9G7ZqyF2G

— OIOIIOOIXIII (@oioiiooixiii) February 15, 2018

⁴ How uninspired do you have to be to write "Germany" in faux Hangul script and stick it down the front of a racesuit 4 times. This is truly their worst. The blank one in 2010 was sublime in comparison. pic.twitter.com/rwuG1a8yOK

— OIOIIOOIXIII (@oioiiooixiii) February 18, 2018

see also: https://oioiiooixiii.blogspot.com/search/label/Sochi%202014

ImageMagick: Reversible Image Masking for lossy image formats



A demonstration of an image masking procedure using ImageMagick, presented as a Bash script. The concept is to obfuscate an image such that it becomes meaningless to the observer (human or machine) but that can be easily recovered using the correct steps. Since it is based on visual alterations rather than altering the file itself, it does not suffer from informational corruption if the image is resaved and/or resized.

In its current form, it's deemed as weakly cryptographic. It could be reversed via brute force study of patterns and edges (as was seen with VideoCrypt, the analogue video encryption used with satellite television¹). Image masking is an old idea that may still have some value today. Further notes are found within the bash script below.
#!/bin/bash
# Demo implementation of reversible image obfuscation for lossy file formats 
# (jpeg), based on ImageMagick[6] command chains.
#
# USAGE: imageMask.sh ['hide'/'recover'] ['image']
#        (Images cropped to multiples of 64 in this implementation.)
#
# * See 'NOTES' at bottom of script for further information and ideas.
#
# N.B. Regarding cryptography: reversible by brute force, edge-analysis ,etc.
# Designed for privacy from casual scanning (human/machine). Inspired by
# previously developed image masking systems: (GMask, JMask, VideoCrypt, etc.)
#
# Source: https://oioiiooixiii.blogspot.com
# Version: 2018.02.19.05.02.27

function obsfucate() # Takes: 'filename', 'width', and 'height'
{
   local width="$2" height="$3"
   
   # Crop into 64x64 blocks, rotate 90 degrees, and negate 1/4.
   # Tile blocks in reversed image orientation (Height x Width).
   # Crop into 16x16 blocks, rotate 90 degrees, and negative 1/4.
   # Tile blocks in reversed image orientation (Height x Width).
   # One extra 'rotate' at end to return to original orientation.
   
   convert "$1" -crop 64x64 -rotate 90  \
      \( +repage -region 32x32+0+0 -negate \) miff:- \
   | montage miff:- -mode concatenate \
      -tile "$((height/64))"x"$((width/64))" miff:- \
   | convert miff:- -crop 16x16 -rotate 90 \
      \( +repage -region 8x8+0+0 -negate \)  miff:- \
   | montage miff:- -mode concatenate \
      -tile "$((height/16))"x"$((width/16))" miff:- \
   | convert miff:- -rotate 90 ${1%.*}_HIDDEN.jpg
   
}

function deobfuscate() # Takes: 'filename', 'width', and 'height'
{
   local width="$3" height="$2"
   # width,height values swapped, 270 rotate to match 'obfuscate' re-orientation
   
   convert "$1" -rotate 270 -crop 64x64 -rotate 270 \
      \( +repage -region 32x32+0+32 -negate \) miff:- \
   | montage miff:- -mode concatenate \
      -tile "$((height/64))"x"$((width/64))"  miff:- \
   | convert miff:- -crop 16x16 -rotate 270 \
      \( +repage -region 8x8+8+8 -negate \) miff:- \
   | montage miff:- -mode concatenate \
      -tile "$((height/16))"x"$((width/16))" ${1%.*}_RECOVERED.jpg
}

function main()
{
   local width="$(identify -format "%w" "$2")"
   local height="$(identify -format "%h" "$2")"    

   # Crude method of making the image dimensions multiples of 64
   if [[ "$((width%64))" -gt 0 || "$((height%64))" -gt 0 ]]
   then
      local width="$(((width/64)*64))"
      local height="$(((height/64)*64))"
      convert "$2" -crop "$width"x"$height"+0+0 +repage "${2%.*}_CROPPED.png"
      local filename="${2%.*}_CROPPED.png"
   fi

   [[ "$1" == "hide" ]] && obsfucate "${filename:-$2}" "$width" "$height"
   [[ "$1" == "recover" ]] && deobfuscate "${filename:-$2}" "$width" "$height"
}

main "$@"
exit

### NOTES ###################################################################

# The command chain 'algorithm' demonstrated here, is just one particular way of
# rearranging an image, using rotation, negation, and altering aspect ratios. 
# More complex chaining as well as extra measures will result in more obscurity.
# Saving files at interim stage and reordering blocks allows for greater 
# manipulation and security (e.g. unique block ordering based on pass phrases). 
#
# Advantages and uses: survives rescaling and re-compression, with minimal 
# additional losses due to principles of DCT quantisation. It allows for images 
# to be stored on-line using public/private 'cloud' services that destroy 
# cryptographic information by rescaling/compressing the image. Reversible via 
# alternate means (e.g. Python PIL etc.) if software becomes unavailable. 
# Cons: Relatively slow, cumbersome, non-dynamic way to browse images.
#
# A side-effect of the procedure is the removal of EXIF information from the 
# image, thus no need for including the '-strip' argument such was desired.
download: imageMask.sh




To show the differences created when the image is resaved [with heavy compression] while in a state of obfuscation, the following was completed: The image was masked and saved as a jpeg with quality set to '25'. The original image was also saved as a jpeg with quality set to '25'. Both of these images were 'differenced' with the original, and the result of each were 'differenced' with each other. This image was then normailised for clarity. N.B. "Difference" does not imply quality loss but variance in compression artifacting.

Below left: Differences between original and image that underwent obfuscation then deobfuscation.
Below right: Differences [normalised] between heavily compressed images, as mentioned above.



more info: http://gmask.awardspace.info/
see also: http://oioiiooixiii.blogspot.com/2014/03/a-novel-approach-to-encrypting-images.html
related: http://oioiiooixiii.blogspot.com/2014/11/illegal-pixels.html
related: https://oioiiooixiii.blogspot.com/2015/05/creating-two-images-from-one-set-of.html
related: https://oioiiooixiii.blogspot.com/2015/06/gimpmask-encrypting-all-or-part-of-image.html
image source: c⃠  https://images.nasa.gov/details-201409250001HQ.html
image source: c⃠  https://commons.wikimedia.org/wiki/File:Moscow,_Krasnaya_Square,_Sunset.jpg

¹ http://www.cl.cam.ac.uk/~mgk25/tv-crypt/image-processing/antisky.html
¹ http://www.techmind.org/vdc/
¹ https://guru.multimedia.cx/decrypting-videocrypt/

Letters to the Neighbors: "Lawnmower Cat"

Dear Sir,

It is with great regret to inform you that I believe I have killed your cat by accident yesterday evening. I am dreadfully sorry about this. It happened when I was reversing my ride-on lawnmower out of my garage to get better access to the blades underneath which needed sharpening. I believe the recent humid weather has had an extreme blunting effect on mild steel. I think I will attempt to temper the metal the next time they need sharpening, lowering their need for maintenance, and thus, creating fewer chances to inadvertently dispatch neighborhood creatures.

Until yesterday I was not aware that you even owned a cat, but upon close inspection of the cat's remains, it bares an uncanny resemblance to your good self, so I am without doubt to the identity of its owner. I would be delighted to return the cat's body to you at your soonest convenience. If you would rather deal with the remains on your own, you can find them in the ditch, next to Frank Tanner's gate (to the left had side). You can't miss it, it's just behind a clump of nettles (I also marked the spot with an old choc-ice wrapper I saw lying around).

The cat's body was in quite good condition the last time I saw it and I'm sure if you retrieved it quickly it will still be good enough to have it stuffed. By co-incidence, my wife's cousin is a very well trained taxidermist and if you wish I can give you his number. I will, of course, ask for you to receive a modest discount (it is the least I can do).

Again, I am very sorry about all this. Rest assured your cat did not suffer at all during the incident. I was very quick to dispatch it with a nearby length of garden hose when I saw its face trapped under one of my wheels.

If there is anything else I can help you with, please let me know!

Kind regards,
George Chaversmith.

published previously

Rough notes on moving Tumblr blog to Blogger (including rehosting images and maintaining source links)

The following are some very rough notes on moving a blog from Tumblr to Blogger, including rehosting images and preserving source links. They are presented in a fashion for personal use, but may provide help to others. They make use of Bash and GNU tools. The generic procedures as documented in links below work perfectly fine, and should provide satisfactory results for most people.
how-to #1: http://www.analyticsforfun.com/2014/04/how-to-move-your-blog-from-tumblr-to.html
how-to #2: https://yourbusiness.azcentral.com/import-tumblr-blogger-10881.html
The procedures in those links leave the images hosted on Tumblr, and also strip the 'source' URLs to content from each post. The bash snippets included here successfully fix these issues, with only a few potential flaws that can be easily cleaned up manually. It would have been more proper to create the XML files from scratch, or at least manipulate the resultant XML objects directly. This was something contemplated during but was abandoned for simple Bash (sed et al.). Some alternate XML manipulation instructions are listed below

ImageMagick: Bidirectional repeated liquid-rescale (content aware scaling)



The use of heavy seam carving (liquid rescale/content aware scaling) in images and video has been well expressed on the internet over the past 10 years¹. The concept of repeated "bidirectional" seam carving has been demonstrated here numerous times in the past².

The concept of bidirectional carving is to resize the image only slightly, and return it to its original dimensions. If this is done repeatedly many times (hundreds or thousands of iterations) the image will continue to corrupt and evolve in novel ways. A simple bash script used for automating the process is presented below.
#!/bin/bash

# Repeated bidirectional 'seam carving' on image. (Requires ImageMagick).
#  - Arguments: filename, iterations, size difference, quality, milestones.
#  - See 'NOTES' at bottom of script for further details
# ver: 2017.11.15.13.07.17
# source: https://oioiiooixiii.blogspot.com

function main()
{   
   # Make duplicate file for working on
   [ "$4" == "png" ] \
      && ext="png" \
      && quality="" \
      || quality="-format jpg -quality $4"
   filename="${1}_lqr-i$2-s$3-q$4.${ext:-jpg}"
   convert "$1" $quality "$filename"
   
   # Set up scaling variables
   originalRes="$(identify $1 | cut -d' ' -f3)"
   pix="$3"
   altRes="$(( $(cut -dx -f1 <<<$originalRes)+pix ))x\
           $(( $(cut -dx -f2 <<<$originalRes)+pix ))"

   #main loop
   for ((i=0;i<"$2";i++)) 
   {
      clear
      printf "FILE: $filename\nFRAMES: $((frame))\nITERATION: $((i+1))\n"
      printf "* Scaling to alt. resolution '${altRes//[[:space:]]/}'\n"
      mogrify -liquid-rescale "$altRes!" $quality "$filename"
      printf "* Scaling to original resolution '$originalRes'\n"
      mogrify -liquid-rescale "$originalRes!" $quality "$filename" 
      
      # Create a new image at milestone interval, if set
      [ ! -z "$5" ] && ! (( $i % $5 )) \
         && cp "$filename" "$((frame++))_$filename"
   }
}

main "$@"
exit

### NOTES ######################################################################
# $1=filename - Name/location of image.
# $2=iterations - The total number of desired resizes.
# $3=size difference - Amount of pixels to scale by (positive or negative).
# $4=quality - Set desired jpeg quality or 'png' (compression causes entropy).
# $5=milestones - Create new file at specified interval, capturing current state
# Possible script improvement: File i/o location in ram drive /dev/shm/ etc.
download: imageMagick_bidirectional-seam-carve.sh



The process can develop numerous types of effect, depending on the attributes given. Shapes can become angular, or rudimentary. Sections of the image can begin to develop seams that tear and germinate. Eventually, most images cascade down into a mess of chaos that never resolves.

The example above demonstrates some of the effects different arguments used in the script can have on an image, though it is in no way exhaustive, nor shows the extremities of the effect. For a more extreme example, see the video below. The starting image size was 960x408, and the arguments given at run-time were: 10,000 iterations, size reduction of 100 pixels, jpeg quality of 90, and every frame saved.


¹ info: http://knowyourmeme.com/memes/content-aware-scaling
² related: https://oioiiooixiii.blogspot.com/search/label/Seam%20Carving
source video: https://en.wikipedia.org/wiki/The_Doctor_and_the_Devils