about summary refs log tree commit diff stats
path: root/build/latex/letter/scripts/optimize_images.sh
blob: 444405daf0573a803af2869231236aac8a106cea (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#!/usr/bin/env nix
#! nix shell nixpkgs#optipng nixpkgs#jpegoptim nixpkgs#nodePackages.svgo nixpkgs#dash --command dash
# shellcheck shell=dash

# source: https://github.com/stride-tasks/stride/blob/148d513297c8ae66d79fc287769adfe5e711c93c/scripts/optimize-images

PROJECT_DIR="$(git rev-parse --show-toplevel)"

cd "$PROJECT_DIR" || {
    echo "No '$PROJECT_DIR' ?!"
    exit 1
}

PNG_OPITMIZE_COMMAND='optipng --quiet -o7 -preserve'
JPG_OPITMIZE_COMMAND='jpegoptim --quiet --strip-all -m76'
SVG_OPITMIZE_COMMAND='svgo --multipass --quiet --input'

# The extension is the part after the first dot in the filename:
#
# For example:
# file.png    => png
# file.tar.gz => tar.gz
find_files_by_extension() {
    wanted_extension="$1"
    tmp="$(mktemp)"

    git ls-files --cached --modified --other --exclude-standard --deduplicate | while IFS= read -r file; do
        file_basename="$(basename "$file")"
        extension="${file_basename#*.}"
        if [ "$extension" = "$wanted_extension" ]; then
            echo "$file"
        else
            :
            # echo "'$file' with extension: '$extension' does not match filter: '$wanted_extension'" 1>&2
        fi
    done >"$tmp"

    echo "$tmp"
}

size_of() {
    du -b "$1" | cut -f1
}

bytes_human() {
    number="$1"

    numfmt --to=iec-i --suffix=B --format="%9.2f" "$number"
}

# https://stackoverflow.com/questions/44695878/how-to-calculate-percentage-in-shell-script
# Native POSIX solution using string manipulation (assumes integer inputs).
percent() {
    DP="$1"
    SDC="$2"

    # Special case when DP is zero.
    [ "$DP" = "0" ] && echo "0.00" && return

    #                                  # e.g. round down   e.g. round up
    #                                  # DP=1 SDC=3        DP=2 SDC=3
    Percent=$((DP * 100000 / SDC + 5)) # Percent=33338     Percent=66671
    Whole=${Percent%???}               # Whole=33          Whole=66
    Percent=${Percent#"$Whole"}        # Percent=338       Percent=671
    Percent=$Whole.${Percent%?}        # Percent=33.33     Percent=66.67
    echo "$Percent"
}

TOTAL=0
TOTAL_SAVED=0

optimize_files() {
    FILTER="$1"
    PROGRAM="$2"

    printf "%s" "Processing $FILTER files:"

    FILES="$(find_files_by_extension "$FILTER")"
    COUNT=$(wc -l <"$FILES")

    if [ "$COUNT" -eq 0 ]; then
        echo " no files found!"
        return
    fi

    echo ""

    I=1

    TOTAL_INNER=0
    TOTAL_SAVED_INNER=0

    while IFS= read -r f; do
        printf "%s/${COUNT} $f ... " "$I"

        SIZE="$(size_of "$f")"

        $PROGRAM "$f"

        NEW_SIZE="$(size_of "$f")"
        DIFF=$((SIZE - NEW_SIZE))

        echo "saved: $(bytes_human "$DIFF") ($(percent $DIFF "$SIZE")%)"

        TOTAL_INNER=$((TOTAL_INNER + SIZE))
        TOTAL_SAVED_INNER=$((TOTAL_SAVED_INNER + DIFF))

        I=$((I + 1))
    done <"$FILES"
    rm "$FILES"

    echo "Total saved for $FILTER: $(bytes_human "$TOTAL_SAVED_INNER") ($(percent $TOTAL_SAVED_INNER $TOTAL_INNER)%)"
    echo ""

    TOTAL=$((TOTAL + TOTAL_INNER))
    TOTAL_SAVED=$((TOTAL_SAVED + TOTAL_SAVED_INNER))
}

optimize_files 'png' "$PNG_OPITMIZE_COMMAND"
optimize_files 'jpg' "$JPG_OPITMIZE_COMMAND"
optimize_files 'jpeg' "$JPG_OPITMIZE_COMMAND"
optimize_files 'svg' "$SVG_OPITMIZE_COMMAND"

echo "Total saved: $(bytes_human "$TOTAL_SAVED") ($(percent $TOTAL_SAVED $TOTAL)%)"