chore: inicializacao agente auto-melhoria + nova-self-improver + .learnings/ + MEMORY.md
- Adiciona .learnings/ completo (LEARNINGS, ERRORS, FEATURE_REQUESTS, PATTERN_COUNTER)
- Cria MEMORY.md, SESSION-STATE.md, USER.md template
- Cria memory/2026-05-19.md (log diario)
- cria IDENTITY.md (Pulse ⚡)
- Atualiza AGENTS.md, SOUL.md, TOOLS.md com regras de auto-melhoria
- Instala nova-self-improver v1.0.0 via clawhub
- Skills totais: 6 instaladas
This commit is contained in:
@@ -0,0 +1,520 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
###############################################################################
|
||||
# vision - Image Processing Toolkit
|
||||
# Version: 3.0.0
|
||||
# Author: BytesAgain
|
||||
#
|
||||
# Commands: resize, crop, convert, optimize, info, watermark
|
||||
# Requires: ImageMagick (convert/identify/mogrify commands)
|
||||
###############################################################################
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
JSON_OUTPUT=false
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Utilities
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
die() { echo "ERROR: $*" >&2; exit 1; }
|
||||
|
||||
log() { echo "[vision] $*" >&2; }
|
||||
|
||||
check_imagemagick() {
|
||||
if ! command -v convert &>/dev/null && ! command -v magick &>/dev/null; then
|
||||
die "ImageMagick is required but not installed. Install with: apt install imagemagick / brew install imagemagick"
|
||||
fi
|
||||
}
|
||||
|
||||
# Wrapper to handle both ImageMagick 6 (convert) and 7 (magick)
|
||||
im_convert() {
|
||||
if command -v magick &>/dev/null; then
|
||||
magick "$@"
|
||||
else
|
||||
convert "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
im_identify() {
|
||||
if command -v magick &>/dev/null; then
|
||||
magick identify "$@"
|
||||
else
|
||||
identify "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
parse_global_flags() {
|
||||
local args=()
|
||||
for arg in "$@"; do
|
||||
if [[ "$arg" == "--json" ]]; then
|
||||
JSON_OUTPUT=true
|
||||
else
|
||||
args+=("$arg")
|
||||
fi
|
||||
done
|
||||
REMAINING_ARGS=("${args[@]+"${args[@]}"}")
|
||||
}
|
||||
|
||||
get_extension() {
|
||||
local filename="$1"
|
||||
echo "${filename##*.}" | tr '[:upper:]' '[:lower:]'
|
||||
}
|
||||
|
||||
get_basename() {
|
||||
local filename="$1"
|
||||
local base
|
||||
base=$(basename "$filename")
|
||||
echo "${base%.*}"
|
||||
}
|
||||
|
||||
get_dirname() {
|
||||
dirname "$1"
|
||||
}
|
||||
|
||||
auto_output_name() {
|
||||
local input="$1"
|
||||
local suffix="$2"
|
||||
local ext="${3:-$(get_extension "$input")}"
|
||||
local dir
|
||||
dir=$(get_dirname "$input")
|
||||
local base
|
||||
base=$(get_basename "$input")
|
||||
echo "${dir}/${base}_${suffix}.${ext}"
|
||||
}
|
||||
|
||||
validate_input() {
|
||||
local input="$1"
|
||||
[[ -n "$input" ]] || die "No input file specified. Use --input"
|
||||
[[ -f "$input" ]] || die "File not found: $input"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# cmd_help - List all commands
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
cmd_help() {
|
||||
cat <<'EOF'
|
||||
vision - Image Processing Toolkit
|
||||
|
||||
Usage: bash script.sh <command> [options]
|
||||
|
||||
Commands:
|
||||
resize Resize image to dimensions or percentage
|
||||
crop Crop image to a region
|
||||
convert Convert between png, jpg, webp formats
|
||||
optimize Compress image to reduce file size
|
||||
info Read EXIF and image metadata
|
||||
watermark Add text watermark to image
|
||||
help Show this help message
|
||||
|
||||
Common options:
|
||||
--input Input image file (required for all commands)
|
||||
--output Output file path (auto-generated if omitted)
|
||||
--json JSON output for info command
|
||||
|
||||
Requires: ImageMagick (apt install imagemagick)
|
||||
|
||||
Examples:
|
||||
bash script.sh resize --input photo.jpg --width 800
|
||||
bash script.sh convert --input photo.png --to webp
|
||||
bash script.sh info --input photo.jpg --json
|
||||
EOF
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# cmd_resize - Resize image
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
cmd_resize() {
|
||||
check_imagemagick
|
||||
|
||||
local input="" output="" width="" height="" percent=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--input) shift; input="$1" ;;
|
||||
--output) shift; output="$1" ;;
|
||||
--width) shift; width="$1" ;;
|
||||
--height) shift; height="$1" ;;
|
||||
--percent) shift; percent="$1" ;;
|
||||
*) die "Unknown option for resize: $1" ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
validate_input "$input"
|
||||
|
||||
[[ -n "$output" ]] || output=$(auto_output_name "$input" "resized")
|
||||
|
||||
local geometry=""
|
||||
if [[ -n "$percent" ]]; then
|
||||
geometry="${percent}%"
|
||||
elif [[ -n "$width" && -n "$height" ]]; then
|
||||
geometry="${width}x${height}!"
|
||||
elif [[ -n "$width" ]]; then
|
||||
geometry="${width}x"
|
||||
elif [[ -n "$height" ]]; then
|
||||
geometry="x${height}"
|
||||
else
|
||||
die "resize requires --width, --height, or --percent"
|
||||
fi
|
||||
|
||||
im_convert "$input" -resize "$geometry" "$output"
|
||||
|
||||
# Report results
|
||||
local orig_size new_size
|
||||
orig_size=$(stat -c%s "$input" 2>/dev/null || stat -f%z "$input")
|
||||
new_size=$(stat -c%s "$output" 2>/dev/null || stat -f%z "$output")
|
||||
|
||||
local orig_dims new_dims
|
||||
orig_dims=$(im_identify -format "%wx%h" "$input")
|
||||
new_dims=$(im_identify -format "%wx%h" "$output")
|
||||
|
||||
echo "Resized: $input → $output"
|
||||
echo " Original: ${orig_dims} ($(( orig_size / 1024 )) KB)"
|
||||
echo " Resized: ${new_dims} ($(( new_size / 1024 )) KB)"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# cmd_crop - Crop image
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
cmd_crop() {
|
||||
check_imagemagick
|
||||
|
||||
local input="" output="" width="" height="" x="0" y="0" gravity=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--input) shift; input="$1" ;;
|
||||
--output) shift; output="$1" ;;
|
||||
--width) shift; width="$1" ;;
|
||||
--height) shift; height="$1" ;;
|
||||
--x) shift; x="$1" ;;
|
||||
--y) shift; y="$1" ;;
|
||||
--gravity) shift; gravity="$1" ;;
|
||||
*) die "Unknown option for crop: $1" ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
validate_input "$input"
|
||||
[[ -n "$width" ]] || die "crop requires --width"
|
||||
[[ -n "$height" ]] || die "crop requires --height"
|
||||
[[ -n "$output" ]] || output=$(auto_output_name "$input" "cropped")
|
||||
|
||||
if [[ -n "$gravity" ]]; then
|
||||
im_convert "$input" -gravity "$gravity" -crop "${width}x${height}+0+0" +repage "$output"
|
||||
else
|
||||
im_convert "$input" -crop "${width}x${height}+${x}+${y}" +repage "$output"
|
||||
fi
|
||||
|
||||
local new_dims
|
||||
new_dims=$(im_identify -format "%wx%h" "$output")
|
||||
|
||||
echo "Cropped: $input → $output"
|
||||
echo " Region: ${width}x${height}+${x}+${y}"
|
||||
echo " Result: ${new_dims}"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# cmd_convert - Format conversion
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
cmd_convert() {
|
||||
check_imagemagick
|
||||
|
||||
local input="" output="" to="" quality=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--input) shift; input="$1" ;;
|
||||
--output) shift; output="$1" ;;
|
||||
--to) shift; to="$1" ;;
|
||||
--quality) shift; quality="$1" ;;
|
||||
*) die "Unknown option for convert: $1" ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
validate_input "$input"
|
||||
[[ -n "$to" ]] || die "convert requires --to (png, jpg, webp)"
|
||||
|
||||
# Normalize format name
|
||||
case "$to" in
|
||||
jpeg) to="jpg" ;;
|
||||
esac
|
||||
|
||||
[[ "$to" =~ ^(png|jpg|webp)$ ]] || die "Supported formats: png, jpg, webp"
|
||||
|
||||
if [[ -z "$output" ]]; then
|
||||
local dir base
|
||||
dir=$(get_dirname "$input")
|
||||
base=$(get_basename "$input")
|
||||
output="${dir}/${base}.${to}"
|
||||
fi
|
||||
|
||||
local cmd_args=("$input")
|
||||
[[ -n "$quality" ]] && cmd_args+=(-quality "$quality")
|
||||
cmd_args+=("$output")
|
||||
|
||||
im_convert "${cmd_args[@]}"
|
||||
|
||||
local orig_size new_size
|
||||
orig_size=$(stat -c%s "$input" 2>/dev/null || stat -f%z "$input")
|
||||
new_size=$(stat -c%s "$output" 2>/dev/null || stat -f%z "$output")
|
||||
local orig_ext
|
||||
orig_ext=$(get_extension "$input")
|
||||
|
||||
echo "Converted: $input ($orig_ext) → $output ($to)"
|
||||
echo " Original: $(( orig_size / 1024 )) KB"
|
||||
echo " Output: $(( new_size / 1024 )) KB"
|
||||
|
||||
local ratio
|
||||
ratio=$(awk "BEGIN {printf \"%.1f\", $new_size * 100 / $orig_size}")
|
||||
echo " Size: ${ratio}% of original"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# cmd_optimize - Compress image
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
cmd_optimize() {
|
||||
check_imagemagick
|
||||
|
||||
local input="" output="" quality="85"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--input) shift; input="$1" ;;
|
||||
--output) shift; output="$1" ;;
|
||||
--quality) shift; quality="$1" ;;
|
||||
*) die "Unknown option for optimize: $1" ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
validate_input "$input"
|
||||
[[ -n "$output" ]] || output=$(auto_output_name "$input" "optimized")
|
||||
|
||||
local ext
|
||||
ext=$(get_extension "$input")
|
||||
|
||||
local orig_size
|
||||
orig_size=$(stat -c%s "$input" 2>/dev/null || stat -f%z "$input")
|
||||
|
||||
case "$ext" in
|
||||
jpg|jpeg)
|
||||
im_convert "$input" -quality "$quality" -sampling-factor 4:2:0 -strip \
|
||||
-interlace JPEG "$output"
|
||||
;;
|
||||
png)
|
||||
im_convert "$input" -quality "$quality" -strip -define png:compression-level=9 "$output"
|
||||
;;
|
||||
webp)
|
||||
im_convert "$input" -quality "$quality" -define webp:method=6 "$output"
|
||||
;;
|
||||
*)
|
||||
im_convert "$input" -quality "$quality" -strip "$output"
|
||||
;;
|
||||
esac
|
||||
|
||||
local new_size
|
||||
new_size=$(stat -c%s "$output" 2>/dev/null || stat -f%z "$output")
|
||||
|
||||
local saved=$((orig_size - new_size))
|
||||
local ratio
|
||||
ratio=$(awk "BEGIN {printf \"%.1f\", $new_size * 100 / $orig_size}")
|
||||
|
||||
echo "Optimized: $input → $output"
|
||||
echo " Original: $(( orig_size / 1024 )) KB"
|
||||
echo " Output: $(( new_size / 1024 )) KB"
|
||||
echo " Saved: $(( saved / 1024 )) KB (${ratio}% of original)"
|
||||
echo " Quality: $quality"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# cmd_info - Read EXIF and metadata
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
cmd_info() {
|
||||
check_imagemagick
|
||||
|
||||
local input=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--input) shift; input="$1" ;;
|
||||
*) die "Unknown option for info: $1" ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
validate_input "$input"
|
||||
|
||||
local format width height colorspace depth filesize
|
||||
format=$(im_identify -format "%m" "$input" 2>/dev/null | head -1)
|
||||
width=$(im_identify -format "%w" "$input" 2>/dev/null | head -1)
|
||||
height=$(im_identify -format "%h" "$input" 2>/dev/null | head -1)
|
||||
colorspace=$(im_identify -format "%[colorspace]" "$input" 2>/dev/null | head -1)
|
||||
depth=$(im_identify -format "%z" "$input" 2>/dev/null | head -1)
|
||||
filesize=$(stat -c%s "$input" 2>/dev/null || stat -f%z "$input")
|
||||
|
||||
# Try to get EXIF data
|
||||
local exif_make="" exif_model="" exif_date="" exif_exposure="" exif_iso="" exif_focal=""
|
||||
if command -v exiftool &>/dev/null; then
|
||||
exif_make=$(exiftool -Make -s3 "$input" 2>/dev/null || true)
|
||||
exif_model=$(exiftool -Model -s3 "$input" 2>/dev/null || true)
|
||||
exif_date=$(exiftool -DateTimeOriginal -s3 "$input" 2>/dev/null || true)
|
||||
exif_exposure=$(exiftool -ExposureTime -s3 "$input" 2>/dev/null || true)
|
||||
exif_iso=$(exiftool -ISO -s3 "$input" 2>/dev/null || true)
|
||||
exif_focal=$(exiftool -FocalLength -s3 "$input" 2>/dev/null || true)
|
||||
else
|
||||
# Fallback: try ImageMagick verbose output
|
||||
local verbose
|
||||
verbose=$(im_identify -verbose "$input" 2>/dev/null || true)
|
||||
exif_make=$(echo "$verbose" | grep -i "exif:Make:" | head -1 | sed 's/.*: *//' || true)
|
||||
exif_model=$(echo "$verbose" | grep -i "exif:Model:" | head -1 | sed 's/.*: *//' || true)
|
||||
exif_date=$(echo "$verbose" | grep -i "exif:DateTimeOriginal:" | head -1 | sed 's/.*: *//' || true)
|
||||
exif_exposure=$(echo "$verbose" | grep -i "exif:ExposureTime:" | head -1 | sed 's/.*: *//' || true)
|
||||
exif_iso=$(echo "$verbose" | grep -i "exif:ISOSpeedRatings:" | head -1 | sed 's/.*: *//' || true)
|
||||
exif_focal=$(echo "$verbose" | grep -i "exif:FocalLength:" | head -1 | sed 's/.*: *//' || true)
|
||||
fi
|
||||
|
||||
local filesize_kb=$(( filesize / 1024 ))
|
||||
local filesize_mb=""
|
||||
[[ $filesize -gt 1048576 ]] && filesize_mb=" ($(awk "BEGIN {printf \"%.1f\", $filesize / 1048576}") MB)"
|
||||
|
||||
if [[ "$JSON_OUTPUT" == true ]]; then
|
||||
printf '{'
|
||||
printf '"file":"%s",' "$(basename "$input")"
|
||||
printf '"format":"%s",' "$format"
|
||||
printf '"width":%s,' "$width"
|
||||
printf '"height":%s,' "$height"
|
||||
printf '"colorspace":"%s",' "$colorspace"
|
||||
printf '"depth":%s,' "$depth"
|
||||
printf '"filesize":%s,' "$filesize"
|
||||
printf '"filesize_kb":%s,' "$filesize_kb"
|
||||
printf '"exif":{'
|
||||
printf '"make":"%s",' "${exif_make:-}"
|
||||
printf '"model":"%s",' "${exif_model:-}"
|
||||
printf '"date":"%s",' "${exif_date:-}"
|
||||
printf '"exposure":"%s",' "${exif_exposure:-}"
|
||||
printf '"iso":"%s",' "${exif_iso:-}"
|
||||
printf '"focal_length":"%s"' "${exif_focal:-}"
|
||||
printf '}}\n'
|
||||
else
|
||||
echo "=== Image Info ==="
|
||||
echo ""
|
||||
echo "File: $(basename "$input")"
|
||||
echo "Format: $format"
|
||||
echo "Dimensions: ${width}x${height}"
|
||||
echo "Color space: $colorspace"
|
||||
echo "Bit depth: $depth"
|
||||
echo "File size: ${filesize_kb} KB${filesize_mb}"
|
||||
echo ""
|
||||
|
||||
if [[ -n "$exif_make" || -n "$exif_model" || -n "$exif_date" ]]; then
|
||||
echo "EXIF Data:"
|
||||
[[ -n "$exif_make" ]] && echo " Camera make: $exif_make"
|
||||
[[ -n "$exif_model" ]] && echo " Camera model: $exif_model"
|
||||
[[ -n "$exif_date" ]] && echo " Date taken: $exif_date"
|
||||
[[ -n "$exif_exposure" ]] && echo " Exposure: $exif_exposure"
|
||||
[[ -n "$exif_iso" ]] && echo " ISO: $exif_iso"
|
||||
[[ -n "$exif_focal" ]] && echo " Focal length: $exif_focal"
|
||||
else
|
||||
echo "EXIF Data: (none found)"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# cmd_watermark - Add text watermark
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
cmd_watermark() {
|
||||
check_imagemagick
|
||||
|
||||
local input="" output="" text="" position="southeast" opacity="50" size="24" color="white"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--input) shift; input="$1" ;;
|
||||
--output) shift; output="$1" ;;
|
||||
--text) shift; text="$1" ;;
|
||||
--position) shift; position="$1" ;;
|
||||
--opacity) shift; opacity="$1" ;;
|
||||
--size) shift; size="$1" ;;
|
||||
--color) shift; color="$1" ;;
|
||||
*) die "Unknown option for watermark: $1" ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
validate_input "$input"
|
||||
[[ -n "$text" ]] || die "watermark requires --text"
|
||||
[[ -n "$output" ]] || output=$(auto_output_name "$input" "watermarked")
|
||||
|
||||
# Map position to ImageMagick gravity
|
||||
local gravity
|
||||
case "$position" in
|
||||
northwest|nw) gravity="NorthWest" ;;
|
||||
north|n) gravity="North" ;;
|
||||
northeast|ne) gravity="NorthEast" ;;
|
||||
west|w) gravity="West" ;;
|
||||
center|c) gravity="Center" ;;
|
||||
east|e) gravity="East" ;;
|
||||
southwest|sw) gravity="SouthWest" ;;
|
||||
south|s) gravity="South" ;;
|
||||
southeast|se) gravity="SouthEast" ;;
|
||||
*) gravity="SouthEast" ;;
|
||||
esac
|
||||
|
||||
# Calculate dissolve value (ImageMagick uses 0-100)
|
||||
local dissolve="$opacity"
|
||||
|
||||
im_convert "$input" \
|
||||
\( -size "$(im_identify -format '%w' "$input")x$(im_identify -format '%h' "$input")" xc:none \
|
||||
-gravity "$gravity" \
|
||||
-fill "$color" \
|
||||
-pointsize "$size" \
|
||||
-annotate +10+10 "$text" \) \
|
||||
-gravity "$gravity" \
|
||||
-compose dissolve -define "compose:args=${dissolve}" \
|
||||
-composite "$output"
|
||||
|
||||
echo "Watermark added: $input → $output"
|
||||
echo " Text: \"$text\""
|
||||
echo " Position: $position ($gravity)"
|
||||
echo " Opacity: ${opacity}%"
|
||||
echo " Size: ${size}pt"
|
||||
echo " Color: $color"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Main dispatch
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
main() {
|
||||
[[ $# -ge 1 ]] || { cmd_help; exit 0; }
|
||||
|
||||
local command="$1"
|
||||
shift
|
||||
|
||||
parse_global_flags "$@"
|
||||
set -- "${REMAINING_ARGS[@]+"${REMAINING_ARGS[@]}"}"
|
||||
|
||||
case "$command" in
|
||||
resize) cmd_resize "$@" ;;
|
||||
crop) cmd_crop "$@" ;;
|
||||
convert) cmd_convert "$@" ;;
|
||||
optimize) cmd_optimize "$@" ;;
|
||||
info) cmd_info "$@" ;;
|
||||
watermark) cmd_watermark "$@" ;;
|
||||
help) cmd_help ;;
|
||||
*) die "Unknown command: $command. Run 'help' for usage." ;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user