平时写markdown笔记,通常会有一些截图在里边,原始图片很大,很占用空间,有必要给它们瘦身一下,注意了是尽可能无损瘦身,即分辨率不变,最大程度保留清晰度,同时减少文件大小。Linux里边提供了很多现成的工具,
在Linux命令行中,有几种方法可以压缩图片。下面是5种常用的方法:
1. 使用ImageMagick:ImageMagick是一个功能强大的命令行工具,可以处理图片。要压缩图片,首先需要安装ImageMagick。在安装完成后,可以运行以下命令来压缩图片:
“`bash
convert input.jpg -quality 80 output.jpg
“`
这个命令将把input.jpg图片压缩为80%的质量,并将压缩后的图片保存为output.jpg。
2. 使用OptiPNG:OptiPNG是一个专门用来压缩PNG格式图片的工具。要使用OptiPNG,需要先安装该工具,然后可以运行以下命令来压缩PNG图片:
“`bash
optipng -o7 input.png
“`
这个命令将使用最高级别的优化来压缩input.png图片。
3. 使用JPEGoptim:JPEGoptim是一个用于压缩JPEG格式图片的工具。要使用JPEGoptim,需要先安装该工具,然后可以运行以下命令来压缩JPEG图片:
“`bash
jpegoptim –max=80 input.jpg
“`
这个命令将把input.jpg图片的质量压缩到最大80%。
4. 使用Guetzli:Guetzli是一个Google开发的用于压缩JPEG图片的工具,它可以在保持可接受质量的前提下更进一步地减小图片文件的大小。要使用Guetzli,需要先下载并安装该工具,然后可以运行以下命令来压缩JPEG图片:
“`bash
guetzli –quality 85 input.jpg output.jpg
“`
这个命令将使用85%的质量压缩input.jpg图片,并将压缩后的图片保存为output.jpg。
5. 使用pngquant:pngquant是一个用于压缩PNG格式图片的工具,它采用了一种独特的无损压缩算法。要使用pngquant,需要先安装该工具,然后可以运行以下命令来压缩图片:
“`bash
pngquant –quality=65-80 input.png -o output.png
“`
这个命令将把input.png图片的质量压缩到65-80%之间,并将压缩后的图片保存为output.png。
这些方法提供了在Linux命令行中压缩图片的不同选项,您可以根据需要选择适合您的情况的方法。
经过使用,感觉jpegoptim、pngquant最给力,效果也不错,所以使用它们制作一个脚本来批量压缩图片,这样我们的markdown笔记就会占用空间小很多。
视频演示:【Shell脚本基础-练习04】批量压缩图片bash脚本_哔哩哔哩_bilibili
脚本:
=> root @ redis1: ~/jiaoben-hub/04-image-compress-tool-------------------------------------------------- main (✓)
➜ cat image_compress_tool.sh
#!/bin/bash
#
#******************************************************************************************
#Author: QianSong
#QQ: xxxxxxxxxx
#Date: 2024-09-05
#FileName: image_compress_tool.sh
#URL: https://github.com
#Description: The test script
#Copyright (C): QianSong 2024 All rights reserved
#******************************************************************************************
#######################################
# 打印使用方法
# Globals:
# none
# Arguments:
# none
# Outputs:
# none
# Returns:
# none
#######################################
function print_usage() {
echo "用法:bash $0 [选项] [选项值]"
echo ""
echo "选项:"
echo " -s, --source-dir 源目录"
echo " -d, --dest-dir 目标目录"
echo " -t, --type 图片格式[png , jpg]"
echo " -h, --help 输出此帮助信息并退出"
}
#######################################
# 初始化全局变量
# Globals:
# ${source_dir}、${dest_dir}、${image_type}
# Arguments:
# none
# Outputs:
# none
# Returns:
# none
#######################################
function init_global_vars() {
#work genarl var
source_dir=""
dest_dir=""
image_type=""
#color
hei_color="\033[1;30m"
hong_color="\033[1;31m"
lv_color="\033[1;32m"
huang_color="\033[1;33m"
lan_color="\033[1;34m"
zi_color="\033[1;35m"
tianlan_color="\033[1;36m"
bai_color="\033[1;37m"
normal_color="\033[0m"
}
#######################################
# 获取用户传入的脚本参数,并作相应处理
# Globals:
# ${source_dir}、${dest_dir}、${image_type}
# Arguments:
# "$@"
# Outputs:
# none
# Returns:
# none
#######################################
function get_user_option_paramater() {
if [ $# -eq 0 ]; then
print_usage
exit 0
fi
local opts
opts="$(getopt -q -o s:,d:,t:,h -l source-dir:,dest-dir:,type:,help -- "$@")"
if [ $? -ne 0 ]; then
print_usage
exit 1
fi
eval set -- "${opts}"
while true; do
case "$1" in
-s | --source-dir)
local regexp1="^\/"
local danger_exp1="^\/+$"
local trim_space1
trim_space1="$(echo "$2" | awk '{gsub(/ /,"",$0); print $0}')"
if [[ "$2" =~ ${regexp1} ]] && [[ ! "${trim_space1}" =~ ${danger_exp1} ]] && [ -d "$2" ]; then
source_dir="$2"
else
echo -e "${hong_color}Bad option ${bai_color}$1 $2 ${zi_color}No such dir ${bai_color}$2 ${zi_color}Or dir can not be ${bai_color}\"/\"${normal_color}"
exit 1
fi
shift 2
;;
-d | --dest-dir)
local regexp2="^\/"
local danger_exp2="^\/+$"
local trim_space2
trim_space2="$(echo "$2" | awk '{gsub(/ /,"",$0); print $0}')"
if [[ "$2" =~ ${regexp2} ]] && [[ ! "${trim_space2}" =~ ${danger_exp2} ]] && [ -d "$2" ]; then
dest_dir="$2"
else
echo -e "${hong_color}Bad option ${bai_color}$1 $2 ${zi_color}No such dir ${bai_color}$2 ${zi_color}Or dir can not be ${bai_color}\"/\"${normal_color}"
exit 1
fi
shift 2
;;
-t | --type)
local regexp3="^jpg$|^png$"
if [[ "$2" =~ ${regexp3} ]]; then
image_type="$2"
else
echo -e "${hong_color}Bad option ${bai_color}$1 $2 ${zi_color}Image type only one of png and jpg${normal_color}"
exit 1
fi
shift 2
;;
-h | --help)
print_usage
shift 1
exit 0
;;
--)
shift 1
break
;;
*)
echo -e "${hong_color}Internal error${normal_color}"
exit 1
;;
esac
done
}
#######################################
# 图片压缩函数
# Globals:
# none
# Arguments:
# none
# Outputs:
# none
# Returns:
# none
#######################################
function convert_image() {
check_valication_to_work
local tools=(
"pngquant"
"jpegoptim"
)
if ! check_tools "${tools[@]}"; then
echo -e "${hong_color}Error: ${bai_color}tools not install...${normal_color}"
IFS=$' \t\n'
local item
for item in "${uninstall_tools[@]}"; do
echo -e "${item}"
done
exit 2
fi
case "${image_type}" in
"png")
compress_image "png"
;;
"jpg")
compress_image "jpg"
;;
*)
echo -e "${hong_color}Internal error${normal_color}"
exit 1
;;
esac
}
#######################################
# 图片压缩
# Globals:
# none
# Arguments:
# $1: 传入图片格式png 、jpg
# Outputs:
# none
# Returns:
# none
#######################################
function compress_image() {
local file_total
if [ "$1" == "png" ]; then
file_total="$(find "${source_dir}" -maxdepth 1 -name "*.png" | wc -l)"
elif [ "$1" == "jpg" ]; then
file_total="$(find "${source_dir}" -maxdepth 1 -name "*.jp*g" | wc -l)"
fi
if [ "${file_total}" -eq 0 ]; then
echo -e "${hong_color}源目录不存在 ${bai_color}${1}${hong_color} 类型文件,无法继续...${normal_color}"
exit 1
fi
#确保清空目标目录
rm -rf "${dest_dir:?}"/* >/dev/null 2>&1
local file_name item
if [ "$1" == "png" ]; then
while IFS= read -r -d '' item; do
file_name="$(basename "${item}")"
pngquant -v --force --quality 50-60 "${item}" -o "${dest_dir:?}/${file_name:?}"
done < <(find "${source_dir}" -maxdepth 1 -name "*.png" -print0)
elif [ "$1" == "jpg" ]; then
while IFS= read -r -d '' item; do
file_name="$(basename "${item}")"
jpegoptim --max=50 --verbose -o --dest="${dest_dir:?}" "${item}"
done < <(find "${source_dir}" -maxdepth 1 -name "*.jp*g" -print0)
fi
echo
print_logo
echo
echo -e "${lv_color}压缩完成,前往 ${bai_color}${dest_dir}${lv_color} 查看...${normal_color}"
}
#######################################
# LOGO
# Globals:
# none
# Arguments:
# none
# Outputs:
# none
# Returns:
# none
#######################################
function print_logo() {
echo -e "${zi_color}▜▘▞▀▖▙▗▌▞▀▖▛▀▘ ▞▀▖▞▀▖▙▗▌▛▀▖▛▀▖▛▀▘▞▀▖▞▀▖${normal_color}"
echo -e "${zi_color}▐ ▙▄▌▌▘▌▌▄▖▙▄ ▌ ▌ ▌▌▘▌▙▄▘▙▄▘▙▄ ▚▄ ▚▄${normal_color}"
echo -e "${zi_color}▐ ▌ ▌▌ ▌▌ ▌▌ ▌ ▖▌ ▌▌ ▌▌ ▌▚ ▌ ▖ ▌▖ ▌${normal_color}"
echo -e "${zi_color}▀▘▘ ▘▘ ▘▝▀ ▀▀▘▀▀▀▝▀ ▝▀ ▘ ▘▘ ▘ ▘▀▀▘▝▀ ▝▀${normal_color}"
}
#######################################
# 检查必须得图片处理工具
# Globals:
# ${uninstall_tools[@]}
# Arguments:
# $1: 传入一个数组,包含工具集
# Outputs:
# none
# Returns:
# 0: 表示工具集完整可以进行脚本
# 1: 表示缺少工具集不能继续脚本
#######################################
function check_tools() {
uninstall_tools=()
IFS=$' \t\n'
local item
for item in "$@"; do
if type "${item}" >/dev/null 2>&1; then
true
else
uninstall_tools+=("${item}")
fi
done
if [ "${#uninstall_tools[@]}" -eq 0 ]; then
return 0
else
return 1
fi
}
#######################################
# 验证参数健全性,不全的参数将导致脚本退出
# Globals:
# none
# Arguments:
# none
# Outputs:
# none
# Returns:
# none
#######################################
function check_valication_to_work() {
if [ -z "${source_dir}" ]; then
echo -e "${hong_color}Error: ${bai_color}please define image source directory...${normal_color}"
exit 1
elif [ -z "${dest_dir}" ]; then
echo -e "${hong_color}Error: ${bai_color}please define image dest directory...${normal_color}"
exit 2
elif [ -z "${image_type}" ]; then
echo -e "${hong_color}Error: ${bai_color}please define image type png/jpg...${normal_color}"
exit 3
fi
}
#######################################
# 脚本的入口,程序执行的起点函数main
# Globals:
# none
# Arguments:
# "$@"
# Outputs:
# none
# Returns:
# none
#######################################
function main() {
init_global_vars
get_user_option_paramater "$@"
convert_image
}
main "$@"
=> root @ redis1: ~/jiaoben-hub/04-image-compress-tool-------------------------------------------------- main (✓)
➜