testsAndMisc/linux_configuration/scripts/utils/gif_to_square.sh
Krzysztof kuhy Rudnicki 3ebb97b283 chore: optimize pre-commit, remove tracked binaries, fix lint issues
- Move slow hooks (mypy, pylint, bandit, pytest, prettier) to pre-push stage
- Remove redundant autoflake (ruff covers F401/F841)
- Fix shellcheck OOM by batching files with xargs -n 40
- Remove tracked .o, .wav, .pyc binaries from git
- Move pomodoro wav files to ../testsAndMisc_binaries/ with symlinks
- Add *.o, *.so, *.a to .gitignore
- Refactor hltb._pick_best_hltb_entry to fix C901/PLR0911/SIM102
- Fix SC2034 warnings in gif_to_square.sh and upgrade.sh
- Add disk_cleanup_check.sh script
- Various test and code improvements across screen_locker,
  steam_backlog_enforcer, word_frequency, moviepy_showcase
2026-04-10 18:48:37 +02:00

153 lines
4.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# Pad a GIF to a square with transparent background, centered.
# Useful for making Slack emojis from rectangular GIFs.
# Usage: gif_to_square.sh <input.gif> [output.gif] [background]
set -euo pipefail
# Source common library for shared functions
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
# shellcheck source=../lib/common.sh
source "$SCRIPT_DIR/../lib/common.sh"
# Default background color (transparent)
DEFAULT_BG="none"
# Function to display usage
usage() {
cat << EOF
Usage: $0 <input.gif> [output.gif] [background]
Arguments:
input.gif Path to the input GIF file (required)
output.gif Path to the output GIF file (default: <input>_square.gif)
background Background color for padding (default: ${DEFAULT_BG})
Use "none" for transparent, or any color name/hex
Examples:
$0 emoji.gif
$0 emoji.gif square_emoji.gif
$0 emoji.gif square_emoji.gif white
$0 emoji.gif square_emoji.gif "#FF0000"
Note: Requires ImageMagick (magick or convert command)
Slack emoji max size: 128x128 pixels, 256KB
EOF
exit 1
}
# Install ImageMagick if missing
if ! command -v magick &> /dev/null && ! command -v convert &> /dev/null; then
echo "ImageMagick not found. Installing..."
if command -v pacman &> /dev/null; then
sudo pacman -S --noconfirm imagemagick
elif command -v apt-get &> /dev/null; then
sudo apt-get update && sudo apt-get install -y imagemagick
else
echo "Error: Could not detect package manager. Install ImageMagick manually."
exit 1
fi
fi
require_imagemagick || exit 1
# Set up identify command (IM7: magick identify, IM6: identify)
if [[ ${MAGICK_CMD} == "magick" ]]; then
IDENTIFY_CMD="magick identify"
else
IDENTIFY_CMD="identify"
fi
# Parse arguments
if [[ $# -lt 1 ]]; then
echo "Error: Missing required argument <input.gif>"
usage
fi
INPUT_GIF="$1"
OUTPUT_GIF="${2:-}"
BACKGROUND="${3:-${DEFAULT_BG}}" # Reserved for future padding mode
export BACKGROUND
# Validate input file exists
if [[ ! -f ${INPUT_GIF} ]]; then
echo "Error: Input file '${INPUT_GIF}' does not exist."
exit 1
fi
# Validate it's a GIF
MIME_TYPE=$(file --mime-type -b "${INPUT_GIF}")
if [[ ${MIME_TYPE} != "image/gif" ]]; then
echo "Error: '${INPUT_GIF}' is not a GIF file (detected: ${MIME_TYPE})"
exit 1
fi
# Generate output filename if not provided
if [[ -z ${OUTPUT_GIF} ]]; then
OUTPUT_GIF=$(generate_output_filename "${INPUT_GIF}" "_square")
fi
# Get dimensions of the first frame
DIMENSIONS=$(${IDENTIFY_CMD} -format "%wx%h" "${INPUT_GIF}[0]")
WIDTH="${DIMENSIONS%x*}"
HEIGHT="${DIMENSIONS#*x}"
echo "Input: ${INPUT_GIF}"
echo "Dimensions: ${WIDTH}x${HEIGHT}"
if [[ ${WIDTH} -eq ${HEIGHT} ]]; then
echo "Image is already square. Copying to output."
cp "${INPUT_GIF}" "${OUTPUT_GIF}"
else
# Stretch to square using the larger dimension
if [[ ${WIDTH} -gt ${HEIGHT} ]]; then
SIDE=${WIDTH}
else
SIDE=${HEIGHT}
fi
echo "Stretching to ${SIDE}x${SIDE}..."
"${MAGICK_CMD}" "${INPUT_GIF}" \
-coalesce \
-resize "${SIDE}x${SIDE}!" \
-layers Optimize \
"${OUTPUT_GIF}"
fi
if [[ -f ${OUTPUT_GIF} ]]; then
OUT_DIMENSIONS=$(${IDENTIFY_CMD} -format "%wx%h" "${OUTPUT_GIF}[0]")
INPUT_SIZE=$(du -h "${INPUT_GIF}" | cut -f1)
OUTPUT_SIZE=$(du -h "${OUTPUT_GIF}" | cut -f1)
echo "✓ Successfully created square GIF"
echo "Output: ${OUTPUT_GIF} (${OUT_DIMENSIONS})"
echo "Input size: ${INPUT_SIZE}"
echo "Output size: ${OUTPUT_SIZE}"
# Auto-shrink if over Slack's 128KB emoji limit (target 124KB for safety margin)
MAX_BYTES=126976
OUTPUT_BYTES=$(stat -c%s "${OUTPUT_GIF}" 2>/dev/null || stat -f%z "${OUTPUT_GIF}" 2>/dev/null)
if [[ ${OUTPUT_BYTES} -gt ${MAX_BYTES} ]]; then
echo ""
echo "Output is over 128KB (${OUTPUT_BYTES} bytes). Auto-shrinking for Slack..."
CURRENT_SIDE=$(${IDENTIFY_CMD} -format "%w" "${OUTPUT_GIF}[0]")
while [[ ${OUTPUT_BYTES} -gt ${MAX_BYTES} && ${CURRENT_SIDE} -gt 16 ]]; do
# Reduce by ~25% each iteration
CURRENT_SIDE=$(( CURRENT_SIDE * 75 / 100 ))
echo " Trying ${CURRENT_SIDE}x${CURRENT_SIDE}..."
"${MAGICK_CMD}" "${OUTPUT_GIF}" \
-coalesce \
-resize "${CURRENT_SIDE}x${CURRENT_SIDE}!" \
-layers Optimize \
"${OUTPUT_GIF}"
OUTPUT_BYTES=$(stat -c%s "${OUTPUT_GIF}" 2>/dev/null || stat -f%z "${OUTPUT_GIF}" 2>/dev/null)
done
OUTPUT_SIZE=$(du -h "${OUTPUT_GIF}" | cut -f1)
echo "✓ Shrunk to ${CURRENT_SIDE}x${CURRENT_SIDE} (${OUTPUT_SIZE}, ${OUTPUT_BYTES} bytes)"
fi
else
echo "✗ Error: Failed to create output file"
exit 1
fi