blog

当前位置:首页>文章中心>blog
一个批量转换图片到avif的脚本
blog 2026-10-05 0 阅读

一个批量转换图片到avif的脚本

小泥吧 小泥吧科技 2026-10-05

脚本:

#!/bin/bash

# ============================================================
#   默认参数
# ============================================================
INPUT_DIR=""
OUTPUT_DIR=""
FORMATS="jpg,jpeg,png,webp,gif,tiff,bmp"
QUALITY=50
PARALLEL=1
LOG_FILE=""
RECURSIVE=0
DRY_RUN=0
MAX_SIZE_MB=200
REPORT_FILE="avif_report.md"
RETRY_FILE="avif_retry.list"

# ============================================================
#   帮助信息
# ============================================================
usage() {
    echo "用法: $0 -i 输入目录 [-o 输出目录] [-f 格式列表] [-q 压缩率]"
    echo "          [--parallel N] [--log file] [--recursive] [--dry-run]"
    echo "          [--max-size MB] [--report file]"
    exit 1
}

# ============================================================
#   参数解析
# ============================================================
while [[ $# -gt 0 ]]; do
    case "$1" in
        -i) INPUT_DIR="$2"; shift 2 ;;
        -o) OUTPUT_DIR="$2"; shift 2 ;;
        -f) FORMATS="$2"; shift 2 ;;
        -q) QUALITY="$2"; shift 2 ;;
        --parallel) PARALLEL="$2"; shift 2 ;;
        --log) LOG_FILE="$2"; shift 2 ;;
        --recursive) RECURSIVE=1; shift ;;
        --dry-run) DRY_RUN=1; shift ;;
        --max-size) MAX_SIZE_MB="$2"; shift 2 ;;
        --report) REPORT_FILE="$2"; shift 2 ;;
        *) usage ;;
    esac
done

# ============================================================
#   自动安装依赖
# ============================================================
install_dependencies() {
    echo "???? 正在检测依赖..."

    if command -v magick >/dev/null 2>&1; then
        echo "✔ 已找到 ImageMagick(magick)"
        CONVERTER="magick"
        return
    fi

    if command -v avifenc >/dev/null 2>&1; then
        echo "✔ 已找到 avifenc"
        CONVERTER="avifenc"
        return
    fi

    echo "⚠ 未找到 magick 或 avifenc,开始自动安装 ImageMagick..."

    # 检测系统类型
    if [[ -f /etc/debian_version ]]; then
        echo "???? 检测到 Debian/Ubuntu 系统,正在安装..."
        sudo apt update && sudo apt install -y imagemagick
    elif [[ -f /etc/redhat-release ]]; then
        echo "???? 检测到 CentOS/RHEL 系统,正在安装..."
        sudo yum install -y epel-release
        sudo yum install -y ImageMagick
    elif [[ -f /etc/arch-release ]]; then
        echo "???? 检测到 Arch Linux 系统,正在安装..."
        sudo pacman -Sy --noconfirm imagemagick
    elif [[ "$(uname)" == "Darwin" ]]; then
        echo "???? 检测到 macOS,正在安装..."
        brew install imagemagick
    else
        echo "❌ 无法识别系统类型,请手动安装 ImageMagick"
        exit 1
    fi

    # 再次检测
    if command -v magick >/dev/null 2>&1; then
        echo "✔ ImageMagick 安装成功"
        CONVERTER="magick"
    else
        echo "❌ ImageMagick 安装失败,请手动安装"
        exit 1
    fi
}

install_dependencies

# ============================================================
#   参数检查
# ============================================================
if [[ -z "$INPUT_DIR" ]]; then
    echo "❌ 必须指定输入目录"
    usage
fi

if [[ ! -d "$INPUT_DIR" ]]; then
    echo "❌ 输入目录不存在: $INPUT_DIR"
    exit 1
fi

if [[ -z "$OUTPUT_DIR" ]]; then
    OUTPUT_DIR="$INPUT_DIR/avif"
fi

mkdir -p "$OUTPUT_DIR"

echo "???? 输入目录: $INPUT_DIR"
echo "???? 输出目录: $OUTPUT_DIR"
echo "???? 压缩率: $QUALITY"
echo "???? 使用转换工具: $CONVERTER"

# ============================================================
#   日志函数
# ============================================================
log() {
    [[ -n "$LOG_FILE" ]] && echo "$(date '+%F %T') $1" >> "$LOG_FILE"
}

# ============================================================
#   查找文件
# ============================================================
IFS=',' read -ra EXT_LIST  "$REPORT_FILE"
echo "| 原文件 | 原大小 | AVIF大小 | 压缩率 | 状态 |" >> "$REPORT_FILE"
echo "|--------|--------|----------|--------|--------|" >> "$REPORT_FILE"

# ============================================================
#   转换函数
# ============================================================
convert_one() {
    local img="$1"
    local filename=$(basename "$img")
    local output="$OUTPUT_DIR/${filename%.*}.avif"

    if [[ -f "$output" ]]; then
        echo "⏭ 跳过已存在: $output"
        log "skip $img"
        return
    fi

    local size_mb=$(du -m "$img" | cut -f1)
    if (( size_mb > MAX_SIZE_MB )); then
        echo "⚠️ 跳过过大文件 ($size_mb MB): $img"
        log "too_large $img"
        return
    fi

    if [[ $DRY_RUN -eq 1 ]]; then
        echo "???? 将转换: $img → $output"
        return
    fi

    echo "➡️ 转换: $img → $output"
    log "convert $img"

    local before_size=$(du -h "$img" | cut -f1)

    if [[ "$CONVERTER" == "magick" ]]; then
        magick "$img" -quality "$QUALITY" "$output"
    else
        avifenc --min 0 --max "$QUALITY" "$img" "$output"
    fi

    if [[ $? -ne 0 ]]; then
        echo "❌ 转换失败: $img"
        log "fail $img"
        echo "$img" >> "$RETRY_FILE"
        echo "| $filename | $before_size | - | - | ❌失败 |" >> "$REPORT_FILE"
        return
    fi

    local after_size=$(du -h "$output" | cut -f1)
    local before_k=$(du -k "$img" | cut -f1)
    local after_k=$(du -k "$output" | cut -f1)
    local ratio=$(( 100 * after_k / before_k ))

    echo "| $filename | $before_size | $after_size | ${ratio}% | ✅成功 |" >> "$REPORT_FILE"
}

export -f convert_one
export OUTPUT_DIR QUALITY CONVERTER LOG_FILE DRY_RUN MAX_SIZE_MB REPORT_FILE RETRY_FILE

# ============================================================
#   并行执行 + 进度条
# ============================================================
count=0
printf "%s\n" "${FILES[@]}" | xargs -I {} -P "$PARALLEL" bash -c 'convert_one "$@"' _ {} | while read -r line; do
    count=$((count + 1))
    percent=$((count * 100 / TOTAL))
    echo -ne "进度: $percent% ($count/$TOTAL)\r"
    echo "$line"
done

echo ""
echo "✅ 全部完成"
log "done"

echo "???? 转换报告已生成: $REPORT_FILE"
[[ -f "$RETRY_FILE" ]] && echo "⚠️ 有失败的文件,重试列表: $RETRY_FILE"


???? **使用说明(完整文档)**


## 1. 基本用法


bash


```

./convert_to_avif.sh -i ./images

```


## 2. 指定输出目录


bash


```

./convert_to_avif.sh -i ./images -o ./output_avif

```


## 3. 指定格式


bash


```

./convert_to_avif.sh -i ./images -f jpg,png,webp

```


## 4. 指定压缩率


bash


```

./convert_to_avif.sh -i ./images -q 60

```


## 5. 并行转换(提高速度)


bash


```

./convert_to_avif.sh -i ./images --parallel 4

```


## 6. 递归扫描子目录


bash


```

./convert_to_avif.sh -i ./images --recursive

```


## 7. 记录日志


bash


```

./convert_to_avif.sh -i ./images --log convert.log

```


## 8. dry-run(仅查看将转换哪些文件)


bash


```

./convert_to_avif.sh -i ./images --dry-run

```


## 9. 限制最大文件大小(避免处理超大图)


bash


```

./convert_to_avif.sh -i ./images --max-size 100

```


## 10. 指定报告文件名


bash


```

./convert_to_avif.sh -i ./images --report my_report.md


相关标签:

发表评论:

评论记录:

未查询到任何数据!
QQ咨询
回电话
回拨通话

我们稍后回拨您的电话

座机请加区号

微信联系
微信扫一扫
微信二维码

扫码加微信