#!/usr/bin/env bash set -euo pipefail shopt -s nullglob nocaseglob convert_one() { local src="$1" if [[ ! -f "$src" ]]; then echo "ERROR: file not found: $src" return 1 fi local base="${src%.*}" local dst="${base}.jpg" local tmp="${base}.tmp.jpg" echo "Converting: $src" # Convert HEIC -> JPEG if ! magick "$src" \ -auto-orient \ -quality 100 \ -sampling-factor 4:4:4 \ "jpg:$tmp"; then echo "ERROR: conversion failed: $src" rm -f "$tmp" return 1 fi # Verify JPEG exists and is not empty if [[ ! -s "$tmp" ]]; then echo "ERROR: output JPEG is empty: $tmp" rm -f "$tmp" return 1 fi echo "Copying metadata..." # Copy all metadata from HEIC if ! exiftool \ -overwrite_original \ -TagsFromFile "$src" \ -all:all \ -unsafe \ "$tmp" >/dev/null; then echo "ERROR: metadata copy failed: $src" rm -f "$tmp" return 1 fi # Preserve filesystem timestamps touch -r "$src" "$tmp" # Replace existing JPEG atomically mv -f "$tmp" "$dst" # Final verification if [[ ! -s "$dst" ]]; then echo "ERROR: final JPEG missing: $dst" return 1 fi # Delete original only after success rm -f "$src" echo "Done: $dst" echo "Removed: $src" } if [[ $# -gt 0 ]]; then convert_one "$1" else files=( *.heic *.HEIC ) if [[ ${#files[@]} -eq 0 ]]; then echo "No HEIC files found." exit 0 fi for f in "${files[@]}"; do convert_one "$f" done fi