--- aliases: tags: - maturity/🌱 date: 2024-09-05 zero-link: - "[[../../meta/zero/00 Π‘Π½ΠΈΠΏΠ΅Ρ‚Ρ‹ Π½Π° bash|00 Π‘Π½ΠΈΠΏΠ΅Ρ‚Ρ‹ Π½Π° bash]]" parents: linked: --- PNG ΠΈ JPG ΡΠ²Π»ΡΡŽΡ‚ΡΡ Ρ…ΠΎΡ€ΠΎΡˆΠΈΠΌΠΈ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π°ΠΌΠΈ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΠΎΠΆΠ½ΠΎ [ΡΠΆΠ°Ρ‚ΡŒ Π±Π΅Π· ΠΏΠΎΡ‚Π΅Ρ€ΠΈ качСства](Π‘ΠΆΠ°Ρ‚ΠΈΠ΅%20ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ%20Π±Π΅Π·%20ΠΏΠΎΡ‚Π΅Ρ€ΠΈ%20качСства.md). Однако, Π½Π° сСгодняшний дСнь сущСствуСт Π±ΠΎΠ»Π΅Π΅ соврСмСнный Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ WebP, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ Π΅Ρ‰Π΅ Π±ΠΎΠ»Π΅Π΅ эффСктивныС Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ ΠΏΡ€ΠΈ сТатии ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ, Π½ΠΎ с Π΅Π΄Π²Π° Π·Π°ΠΌΠ΅Ρ‚Π½Ρ‹ΠΌ ΡƒΡ…ΡƒΠ΄ΡˆΠ΅Π½ΠΈΠ΅ΠΌ качСства. Π’ [Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ WebP](https://developers.google.com/speed/webp/docs/cwebp?hl=ru) пСрСчислСно мноТСство ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ², ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΠΎΠ²Π»ΠΈΡΡŽΡ‚ Π½Π° качСство ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌΠΎΠ³ΠΎ изобраТСния. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ провСсти ΡΠΊΡΠΏΠ΅Ρ€ΠΈΠΌΠ΅Π½Ρ‚Π°Π»ΡŒΠ½Ρ‹ΠΉ ΠΏΠΎΠ΄Π±ΠΎΡ€ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ² ΠΎΠ½Π»Π°ΠΉΠ½ Π½Π° сайтС [https://squoosh.app](https://squoosh.app/). Π― Π²Ρ‹ Π²Ρ‹Π±Ρ€Π°Π» для сСбя ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ Π½Π°Π±ΠΎΡ€ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ²: ```bash cwebp -mt -af -progress -m 6 -q 80 -pass 10 input.jpg -o output.webp ``` Π­Ρ‚ΠΎ ΠΊΠΎΠΌΠ°Π½Π΄Π° ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΡƒΠ΅Ρ‚ JPG Ρ„Π°ΠΉΠ» `input.jpg` Π² Ρ„Π°ΠΉΠ» изобраТСния WebP с ΠΈΠΌΠ΅Π½Π΅ΠΌ `output.webp`. Команда Π²ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ нСсколько ΠΎΠΏΡ†ΠΈΠΉ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΡƒΠΏΡ€Π°Π²Π»ΡΡŽΡ‚ процСссом кодирования: - `-mt` Π²ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ ΠΌΠ½ΠΎΠ³ΠΎΠΏΠΎΡ‚ΠΎΡ‡Π½ΠΎΡΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ ΠΌΠΎΠΆΠ΅Ρ‚ ΡƒΠ»ΡƒΡ‡ΡˆΠΈΡ‚ΡŒ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ Π½Π° многоядСрных процСссорах. - `-af` Π²ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΡ‡Π΅ΡΠΊΡƒΡŽ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°Ρ†ΠΈΡŽ, которая примСняСт Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°Ρ†ΠΈΠΈ для ΠΏΠΎΠ²Ρ‹ΡˆΠ΅Π½ΠΈΡ эффСктивности сТатия. - `-progress` Π²Ρ‹Π²ΠΎΠ΄ΠΈΡ‚ ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ ΠΏΡ€ΠΎΡ†Π΅Π½Ρ‚ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Ρ„Π°ΠΉΠ»Π°. - `-m 6` устанавливаСт максимальноС количСство сСгмСнтов, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹Ρ… Π² процСссС кодирования, Ρ€Π°Π²Π½Ρ‹ΠΌ 6, Ρ‡Ρ‚ΠΎ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΠ²Ρ‹ΡΠΈΡ‚ΡŒ ΡΡ„Ρ„Π΅ΠΊΡ‚ΠΈΠ²Π½ΠΎΡΡ‚ΡŒ сТатия Π·Π° счСт увСличСния Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ кодирования. - `-q 80` устанавливаСт коэффициСнт качСства Π½Π° `80`, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΠΈΡ€ΡƒΠ΅Ρ‚ ΡΡ‚Π΅ΠΏΠ΅Π½ΡŒ сТатия ΠΈ влияСт Π½Π° Π²ΠΈΠ·ΡƒΠ°Π»ΡŒΠ½ΠΎΠ΅ качСство Π²Ρ‹Ρ…ΠΎΠ΄Π½ΠΎΠ³ΠΎ изобраТСния. - `-pass 10` устанавливаСт число ΠΏΡ€ΠΎΡ…ΠΎΠ΄ΠΎΠ² кодирования Ρ€Π°Π²Π½Ρ‹ΠΌ 10, Ρ‡Ρ‚ΠΎ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΠ²Ρ‹ΡΠΈΡ‚ΡŒ ΡΡ„Ρ„Π΅ΠΊΡ‚ΠΈΠ²Π½ΠΎΡΡ‚ΡŒ сТатия Π·Π° счСт увСличСния Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ кодирования. > [!WARNING] > `-lossless` позволяСт ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ сТатиС Π±Π΅Π· ΠΏΠΎΡ‚Π΅Ρ€ΡŒ. Но Ρ‚ΠΎΠ³Π΄Π° вашС Π½ΠΎΠ²ΠΎΠ΅ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΎΠΊΠ°Π·Π°Ρ‚ΡŒΡΡ сущСствСнно тяТСлСС исходного. Π£Π»ΡƒΡ‡ΡˆΠΈΠΌ [скрипт сТатия ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ](Π‘ΠΆΠ°Ρ‚ΠΈΠ΅%20ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ%20Π±Π΅Π·%20ΠΏΠΎΡ‚Π΅Ρ€ΠΈ%20качСства.md) ΠΈ Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Ρ‚Π°ΠΊΠΆΠ΅ ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ Π² webp: ```bash title="zip_image.sh" {6, 15} #!/bin/bash # Настройки IMAGE_DIR="./images" COMP_DIR="$IMAGE_DIR/comp" WEBP_DIR="$IMAGE_DIR/webp" # АвтоматичСскоС ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ количСства ядСр процСссора THREADS=$(getconf _NPROCESSORS_ONLN) echo "Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ $THREADS ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ² для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ." # Π€Π°ΠΉΠ»Ρ‹ логирования LOG_FILE="./zip_image_compression.log" ERROR_LOG_FILE="./zip_image_error.log" # ЭкспортируСм Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ для использования Π² subshell export IMAGE_DIR COMP_DIR WEBP_DIR LOG_FILE ERROR_LOG_FILE # Ѐункция для опрСдСлСния Ρ€Π°Π·ΠΌΠ΅Ρ€Π° Ρ„Π°ΠΉΠ»Π° get_file_size() { local file="$1" if [[ "$OSTYPE" == "linux-gnu"* ]]; then stat -c%s "$file" elif [[ "$OSTYPE" == "darwin"* ]]; then stat -f%z "$file" else # ΠŸΠΎΠΏΡ‹Ρ‚ΠΊΠ° ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ GNU stat, Ссли установлСн if command -v gstat &> /dev/null; then gstat -c%s "$file" else # Π’ качСствС Π°Π»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ wc -c wc -c < "$file" | tr -d ' ' fi fi} export -f get_file_size # Ѐункция для логирования успСха log_success() { local message="$1" echo "$message" echo "$(date '+%Y-%m-%d %H:%M:%S') $message" >> "$LOG_FILE" } # Ѐункция для логирования ошибок log_error() { local message="$1" echo "$message" >&2 echo "$(date '+%Y-%m-%d %H:%M:%S') $message" >> "$ERROR_LOG_FILE" } # ЭкспортируСм Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ логирования export -f log_success export -f log_error # Ѐункция для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ PNG Ρ„Π°ΠΉΠ»ΠΎΠ² process_png() { local input_file="$1" local relative_path="${input_file#$IMAGE_DIR/}" local output_file="$COMP_DIR/$relative_path" local output_dir output_dir="$(dirname "$output_file")" mkdir -p "$output_dir" # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Ρ„Π°ΠΉΠ»Π° ошибки local error_file="${output_file}.error" if [ -f "$error_file" ]; then # Π€Π°ΠΉΠ» ошибки сущСствуСт, пропускаСм ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ return fi # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Ρ…Π΅ΡˆΠ° Ρ„Π°ΠΉΠ»Π° local hash_file="${output_file}.md5" local current_hash current_hash="$(md5sum "$input_file" | awk '{print $1}')" if [ -f "$hash_file" ]; then local previous_hash previous_hash="$(cat "$hash_file")" if [ "$current_hash" == "$previous_hash" ]; then # Π€Π°ΠΉΠ» Π½Π΅ измСнился, Π½ΠΈΡ‡Π΅Π³ΠΎ Π½Π΅ Π΄Π΅Π»Π°Π΅ΠΌ return fi fi # Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ local temp_output_file="${output_file}.tmp" cp "$input_file" "$temp_output_file" # Π Π°Π·ΠΌΠ΅Ρ€ Π΄ΠΎ сТатия local original_size original_size=$(get_file_size "$input_file") # Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ pngquant if ! pngquant --quality=90-100 --speed 1 --output "$temp_output_file" --force "$input_file"; then local error_msg="Ошибка ΠΏΡ€ΠΈ сТатии $input_file с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ pngquant" log_error "$error_msg" echo "$error_msg" > "$error_file" rm -f "$temp_output_file" return 1 fi # Π”ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Π°Ρ оптимизация с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ zopflipng if ! zopflipng -y "$temp_output_file" "$temp_output_file"; then local error_msg="Ошибка ΠΏΡ€ΠΈ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ $temp_output_file с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ zopflipng" log_error "$error_msg" echo "$error_msg" > "$error_file" rm -f "$temp_output_file" return 1 fi # Π Π°Π·ΠΌΠ΅Ρ€ послС сТатия local new_size new_size=$(get_file_size "$temp_output_file") # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ°, Ρ‡Ρ‚ΠΎ original_size Π½Π΅ Ρ€Π°Π²Π΅Π½ Π½ΡƒΠ»ΡŽ if [ "$original_size" -eq 0 ]; then local error_msg="Ошибка: Ρ€Π°Π·ΠΌΠ΅Ρ€ ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½ΠΎΠ³ΠΎ Ρ„Π°ΠΉΠ»Π° Ρ€Π°Π²Π΅Π½ 0 для $input_file" log_error "$error_msg" echo "$error_msg" > "$error_file" rm -f "$temp_output_file" return 1 fi # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ°, ΡƒΠΌΠ΅Π½ΡŒΡˆΠΈΠ»ΡΡ Π»ΠΈ Ρ€Π°Π·ΠΌΠ΅Ρ€ Ρ„Π°ΠΉΠ»Π° if [ "$new_size" -ge "$original_size" ]; then log_success "Π‘ΠΆΠ°Ρ‚ΠΈΠ΅ Π½Π΅ ΡƒΠΌΠ΅Π½ΡŒΡˆΠΈΠ»ΠΎ Ρ€Π°Π·ΠΌΠ΅Ρ€ Ρ„Π°ΠΉΠ»Π° $input_file, пропускаСм сохранСниС" # БохраняСм Ρ…Π΅Ρˆ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π΅ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ Ρ„Π°ΠΉΠ» снова echo "$current_hash" > "$hash_file" rm -f "$temp_output_file" return fi # ΠŸΡ€ΠΎΡ†Π΅Π½Ρ‚ сТатия local reduction reduction=$(awk "BEGIN {printf \"%.2f\", (($original_size - $new_size) / $original_size) * 100}") log_success "Π‘ΠΆΠ°Ρ‚ PNG Ρ„Π°ΠΉΠ»: $input_file Π½Π° $reduction% ($original_size Π±Π°ΠΉΡ‚ -> $new_size Π±Π°ΠΉΡ‚)" # ΠŸΠ΅Ρ€Π΅ΠΌΠ΅Ρ‰Π°Π΅ΠΌ Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» Π½Π° мСсто Π²Ρ‹Ρ…ΠΎΠ΄Π½ΠΎΠ³ΠΎ mv "$temp_output_file" "$output_file" # БохраняСм Ρ…Π΅Ρˆ echo "$current_hash" > "$hash_file" } export -f process_png # Ѐункция для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ JPEG Ρ„Π°ΠΉΠ»ΠΎΠ² process_jpeg() { local input_file="$1" local relative_path="${input_file#$IMAGE_DIR/}" local output_file="$COMP_DIR/$relative_path" local output_dir output_dir="$(dirname "$output_file")" mkdir -p "$output_dir" # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Ρ„Π°ΠΉΠ»Π° ошибки local error_file="${output_file}.error" if [ -f "$error_file" ]; then # Π€Π°ΠΉΠ» ошибки сущСствуСт, пропускаСм ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ return fi # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Ρ…Π΅ΡˆΠ° Ρ„Π°ΠΉΠ»Π° local hash_file="${output_file}.md5" local current_hash current_hash="$(md5sum "$input_file" | awk '{print $1}')" if [ -f "$hash_file" ]; then local previous_hash previous_hash="$(cat "$hash_file")" if [ "$current_hash" == "$previous_hash" ]; then # Π€Π°ΠΉΠ» Π½Π΅ измСнился, Π½ΠΈΡ‡Π΅Π³ΠΎ Π½Π΅ Π΄Π΅Π»Π°Π΅ΠΌ return fi fi # Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ local temp_output_file="${output_file}.tmp" cp "$input_file" "$temp_output_file" # Π Π°Π·ΠΌΠ΅Ρ€ Π΄ΠΎ сТатия local original_size original_size=$(get_file_size "$input_file") # Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ mozjpeg if ! cjpeg -quality 95 -progressive -optimize -outfile "$temp_output_file" "$input_file"; then local error_msg="Ошибка ΠΏΡ€ΠΈ сТатии $input_file с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ mozjpeg" log_error "$error_msg" echo "$error_msg" > "$error_file" rm -f "$temp_output_file" return 1 fi # Π Π°Π·ΠΌΠ΅Ρ€ послС сТатия local new_size new_size=$(get_file_size "$temp_output_file") # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ°, Ρ‡Ρ‚ΠΎ original_size Π½Π΅ Ρ€Π°Π²Π΅Π½ Π½ΡƒΠ»ΡŽ if [ "$original_size" -eq 0 ]; then local error_msg="Ошибка: Ρ€Π°Π·ΠΌΠ΅Ρ€ ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½ΠΎΠ³ΠΎ Ρ„Π°ΠΉΠ»Π° Ρ€Π°Π²Π΅Π½ 0 для $input_file" log_error "$error_msg" echo "$error_msg" > "$error_file" rm -f "$temp_output_file" return 1 fi # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ°, ΡƒΠΌΠ΅Π½ΡŒΡˆΠΈΠ»ΡΡ Π»ΠΈ Ρ€Π°Π·ΠΌΠ΅Ρ€ Ρ„Π°ΠΉΠ»Π° if [ "$new_size" -ge "$original_size" ]; then log_success "Π‘ΠΆΠ°Ρ‚ΠΈΠ΅ Π½Π΅ ΡƒΠΌΠ΅Π½ΡŒΡˆΠΈΠ»ΠΎ Ρ€Π°Π·ΠΌΠ΅Ρ€ Ρ„Π°ΠΉΠ»Π° $input_file, пропускаСм сохранСниС" # БохраняСм Ρ…Π΅Ρˆ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π΅ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ Ρ„Π°ΠΉΠ» снова echo "$current_hash" > "$hash_file" rm -f "$temp_output_file" return fi # ΠŸΡ€ΠΎΡ†Π΅Π½Ρ‚ сТатия local reduction reduction=$(awk "BEGIN {printf \"%.2f\", (($original_size - $new_size) / $original_size) * 100}") log_success "Π‘ΠΆΠ°Ρ‚ JPEG Ρ„Π°ΠΉΠ»: $input_file Π½Π° $reduction% ($original_size Π±Π°ΠΉΡ‚ -> $new_size Π±Π°ΠΉΡ‚)" # ΠŸΠ΅Ρ€Π΅ΠΌΠ΅Ρ‰Π°Π΅ΠΌ Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» Π½Π° мСсто Π²Ρ‹Ρ…ΠΎΠ΄Π½ΠΎΠ³ΠΎ mv "$temp_output_file" "$output_file" # БохраняСм Ρ…Π΅Ρˆ echo "$current_hash" > "$hash_file" } export -f process_jpeg # Ѐункция для ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚Π°Ρ†ΠΈΠΈ Π² WebP process_webp() { local input_file="$1" local relative_path="${input_file#$IMAGE_DIR/}" local output_file="$WEBP_DIR/$relative_path" output_file="${output_file%.*}.webp" local output_dir output_dir="$(dirname "$output_file")" mkdir -p "$output_dir" # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Ρ„Π°ΠΉΠ»Π° ошибки local error_file="${output_file}.error" if [ -f "$error_file" ]; then # Π€Π°ΠΉΠ» ошибки сущСствуСт, пропускаСм ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ return fi # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Ρ…Π΅ΡˆΠ° Ρ„Π°ΠΉΠ»Π° local hash_file="${output_file}.md5" local current_hash current_hash="$(md5sum "$input_file" | awk '{print $1}')" if [ -f "$hash_file" ]; then local previous_hash previous_hash="$(cat "$hash_file")" if [ "$current_hash" == "$previous_hash" ]; then # Π€Π°ΠΉΠ» Π½Π΅ измСнился, Π½ΠΈΡ‡Π΅Π³ΠΎ Π½Π΅ Π΄Π΅Π»Π°Π΅ΠΌ return fi fi # Π Π°Π·ΠΌΠ΅Ρ€ Π΄ΠΎ ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚Π°Ρ†ΠΈΠΈ local original_size original_size=$(get_file_size "$input_file") # Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» для Π²Ρ‹Π²ΠΎΠ΄Π° local temp_output_file="${output_file}.tmp" if ! cwebp -mt -af -quiet -m 6 -q 95 -pass 10 "$input_file" -o "$temp_output_file"; then local error_msg="Ошибка ΠΏΡ€ΠΈ ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚Π°Ρ†ΠΈΠΈ $input_file Π² WebP" log_error "$error_msg" echo "$error_msg" > "$error_file" rm -f "$temp_output_file" return 1 fi # Π Π°Π·ΠΌΠ΅Ρ€ послС ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚Π°Ρ†ΠΈΠΈ local new_size new_size=$(get_file_size "$temp_output_file") # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ°, Ρ‡Ρ‚ΠΎ original_size Π½Π΅ Ρ€Π°Π²Π΅Π½ Π½ΡƒΠ»ΡŽ if [ "$original_size" -eq 0 ]; then local error_msg="Ошибка: Ρ€Π°Π·ΠΌΠ΅Ρ€ ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½ΠΎΠ³ΠΎ Ρ„Π°ΠΉΠ»Π° Ρ€Π°Π²Π΅Π½ 0 для $input_file" log_error "$error_msg" echo "$error_msg" > "$error_file" rm -f "$temp_output_file" return 1 fi # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ°, ΡƒΠΌΠ΅Π½ΡŒΡˆΠΈΠ»ΡΡ Π»ΠΈ Ρ€Π°Π·ΠΌΠ΅Ρ€ Ρ„Π°ΠΉΠ»Π° if [ "$new_size" -ge "$original_size" ]; then log_success "ΠšΠΎΠ½Π²Π΅Ρ€Ρ‚Π°Ρ†ΠΈΡ Π² WebP Π½Π΅ ΡƒΠΌΠ΅Π½ΡŒΡˆΠΈΠ»Π° Ρ€Π°Π·ΠΌΠ΅Ρ€ Ρ„Π°ΠΉΠ»Π° $input_file, пропускаСм сохранСниС" # БохраняСм Ρ…Π΅Ρˆ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π΅ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ Ρ„Π°ΠΉΠ» снова echo "$current_hash" > "$hash_file" rm -f "$temp_output_file" return fi # ΠŸΡ€ΠΎΡ†Π΅Π½Ρ‚ сТатия local reduction reduction=$(awk "BEGIN {printf \"%.2f\", (($original_size - $new_size) / $original_size) * 100}") log_success "ΠšΠΎΠ½Π²Π΅Ρ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½ Π² WebP: $input_file Π½Π° $reduction% ($original_size Π±Π°ΠΉΡ‚ -> $new_size Π±Π°ΠΉΡ‚)" # ΠŸΠ΅Ρ€Π΅ΠΌΠ΅Ρ‰Π°Π΅ΠΌ Π²Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ» Π½Π° мСсто Π²Ρ‹Ρ…ΠΎΠ΄Π½ΠΎΠ³ΠΎ mv "$temp_output_file" "$output_file" # БохраняСм Ρ…Π΅Ρˆ echo "$current_hash" > "$hash_file" } export -f process_webp # ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° PNG Ρ„Π°ΠΉΠ»ΠΎΠ² find "$IMAGE_DIR" -type f \ -not -path "$COMP_DIR/*" \ -not -path "$WEBP_DIR/*" \ ! -name "*-no-comp.*" \ -iname "*.png" -print0 | \ xargs -0 -P "$THREADS" -I {} bash -c 'process_png "$@"' _ {} # ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° JPEG Ρ„Π°ΠΉΠ»ΠΎΠ² find "$IMAGE_DIR" -type f \ -not -path "$COMP_DIR/*" \ -not -path "$WEBP_DIR/*" \ ! -name "*-no-comp.*" \ -iregex '.*\.\(jpg\|jpeg\)' -print0 | \ xargs -0 -P "$THREADS" -I {} bash -c 'process_jpeg "$@"' _ {} # ΠšΠΎΠ½Π²Π΅Ρ€Ρ‚Π°Ρ†ΠΈΡ Π² WebP ΠΈΠ· исходных Ρ„Π°ΠΉΠ»ΠΎΠ² find "$IMAGE_DIR" -type f \( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' \) \ -not -path "$COMP_DIR/*" \ -not -path "$WEBP_DIR/*" \ ! -name "*-no-comp.*" \ -print0 | \ xargs -0 -P "$THREADS" -I {} bash -c 'process_webp "$@"' _ {} ``` ΠœΡ‹ Π±Π΅Ρ€Π΅ΠΌ сТатыС изобраТСния ΠΈΠ· ΠΏΠ°ΠΏΠΊΠΈ `comp` ΠΈ ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΡƒΠ΅ΠΌ ΠΈΡ… Π² WebP, складывая Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΡƒΡŽ ΠΏΠ°ΠΏΠΊΡƒ `webp`. Если Π²Ρ‹ Π·Π°Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ сТатия, Π²Ρ‹ всСгда смоТСтС ΠΏΠ΅Ρ€Π΅ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ изобраТСния с Π½ΠΎΠ²Ρ‹ΠΌΠΈ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π°ΠΌΠΈ. ## ВСсты прСобразования Π‘ΠΎΠΆΠΌΠ΅ΠΌ наши Ρ„Π°ΠΉΠ» Ρ€Π°Π·ΠΌΠ΅Ρ€ΠΎΠΌ Π² 2,7 ΠΌΠ± ΠΈ 2.2 Π² Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ WebP с Ρ€Π°Π·Π½Ρ‹ΠΌΠΈ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π°ΠΌΠΈ качСства: - -q 90: Π Π°Π·ΠΌΠ΅Ρ€ 325 ΠΊΠ±. - -q 85: Π Π°Π·ΠΌΠ΅Ρ€ 267 ΠΊΠ±. - -q 80: Π Π°Π·ΠΌΠ΅Ρ€ 229 ΠΊΠ±. - -q 75: Π Π°Π·ΠΌΠ΅Ρ€ 200 ΠΊΠ±. - -q 70: Π Π°Π·ΠΌΠ΅Ρ€ 191 ΠΊΠ±. - -q 60: Π Π°Π·ΠΌΠ΅Ρ€ 176 ΠΊΠ±. - -q 50: Π Π°Π·ΠΌΠ΅Ρ€ 163 ΠΊΠ±. - -q 40: Π Π°Π·ΠΌΠ΅Ρ€ 147 ΠΊΠ±. - -q 30: Π Π°Π·ΠΌΠ΅Ρ€ 129 ΠΊΠ±. - -q 20: Π Π°Π·ΠΌΠ΅Ρ€ 115 ΠΊΠ±. - -q 10: Π Π°Π·ΠΌΠ΅Ρ€ 90 ΠΊΠ±. - -q 1: Π Π°Π·ΠΌΠ΅Ρ€ 70 ΠΊΠ±. Для экстрСнных случаСв. НапримСр, Π²Ρ‹ Π·Π°Π±Π»ΡƒΠ΄ΠΈΠ»ΠΈΡΡŒ Π² лСсу ΠΈ Π½Π°Π΄ΠΎ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ Ρ„ΠΎΡ‚ΠΎ ΠΏΠΎ спутниковой сСти πŸ˜… ΠŸΡ€ΠΈΠΌΠ΅Ρ€ использования Π½Π° Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹Ρ… изобраТСниях ΠΌΠΎΠ΅Π³ΠΎ Π±Π»ΠΎΠ³Π° ![[../../meta/files/images/Pasted image 20240925144640.png]] ## Nginx Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΡ‹ Π½Π°ΡƒΡ‡ΠΈΠΌ nginx ΠΏΡ€ΠΈ запросС ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ сначала ΠΏΡ‹Ρ‚Π°Ρ‚ΡŒΡΡ Π½Π°ΠΉΡ‚ΠΈ WebP Ρ„Π°ΠΉΠ», ΠΈ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΏΠΎΡ‚ΠΎΠΌ ΠΎΡ‚Π΄Π°Π²Π°Ρ‚ΡŒ сТатый PNG/JPG, Π° Ссли ΠΈ сТатого Π½Π΅Ρ‚, Ρ‚ΠΎ ΠΎΡ‚Π΄Π°Π²Π°Ρ‚ΡŒ ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹ΠΉ Ρ„Π°ΠΉΠ». Для этого напишСм ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ `location`: ```nginx location ~* ^(/blog/ru/content/images/)(.+)\.(png|jpe?g)$ { expires 1d; add_header Cache-Control "public, must-revalidate, proxy-revalidate"; root /var/site/images; try_files /webp/$2.webp /comp/$2.$3 $uri =404; } ``` *** ## ΠœΠ΅Ρ‚Π° информация **ΠžΠ±Π»Π°ΡΡ‚ΡŒ**:: [[../../meta/zero/00 Π‘Π½ΠΈΠΏΠ΅Ρ‚Ρ‹ Π½Π° bash|00 Π‘Π½ΠΈΠΏΠ΅Ρ‚Ρ‹ Π½Π° bash]] **Π ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ**:: **Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ**:: **Автор**:: **Π‘ΠΎΠ·Π΄Π°Π½Π°**:: [[2024-09-05]] ### Π”ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»Ρ‹ - ### Π”ΠΎΡ‡Π΅Ρ€Π½ΠΈΠ΅ Π·Π°ΠΌΠ΅Ρ‚ΠΊΠΈ