-
Notifications
You must be signed in to change notification settings - Fork 7
/
tinypng
executable file
·252 lines (225 loc) · 7.02 KB
/
tinypng
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
#!/bin/bash
# Written by Rany Albeg Wein - rany.albeg@gmail.com - 2017
# Contributors:
# * Jonas Hess ( re4jh )
# JPEG support.
# Source: https://github.com/RanyAlbegWein/Tinypng
# Use tinypng.com API to shrink a png/jpeg image.
# Requires Bash 4 (or above) and curl.
# Base URL for tinypng.com API service.
baseurl=api.tinify.com
# API URL.
apiurl=https://$baseurl/shrink
# Developers URL.
dev_url=https://tinypng.com/developers
# A file to keep the API key for future requests.
keyfile="$HOME/.tinypng.apikey"
# The API key.
apikey=
# PNGs to shrink.
org_images=()
# Indicates whether the user wants to download the shrinked PNGs.
download_images=0
# The directory to which the user wants to download the shrinked PNGs.
download_dir=
# Print URLs of shrinked PNGs after download.
print_urls_after_dl=0
# URLs to shrinked PNG/JPEGs.
declare -A image_urls
# Overwrite exisiting images.
overwrite=0
# Print help message to stdout.
# Args: none.
show_help() {
local bold=$(tput bold)
local reset=$(tput sgr0)
cat<<-EOF
${bold}NAME${reset}
tinypng - Shrink PNG/JPEGs using tinypng.com service.
${bold}SYNOPSIS${reset}
tinypng [-dkph] -f FILE
${bold}DESCRIPTION${reset}
Shrink PNG/JPEGs using tinypng.com service.
On first execution, or if $keyfile is not present, tinypng will ask for an API key.
Obtain your API key from $dev_url, copy and paste it when prompted.
${bold}OPTIONS${reset}
-f,--file FILE Select a FILE to be shrinked.
-d,--download DIRECTORY Download all shrinked images to DIRECTORY.
-o,--overwrite When -d is being used, overwrite the source images with the downloaded ones.
-k,--key API_KEY Use API_KEY, instead of the one stored in $keyfile.
-p,--print When -d is being used, the URLs of the shrinked images are not being printed to stdout.
Use this option to force printing even when using -d.
Otherwise, this option is set implicitly.
-- FILES Ignore any options to come.
Everything after this option is considered a file.
-h,--help Show this message and exit successfully.
${bold}EXAMPLES${reset}
Shrink foo.jpg, bar.png, baz.png and print the result URLs to stdout.
${bold}$ tinypng -f foo.jpg -f bar.png -f baz.png${reset}
or
${bold}$ tinypng -- foo.jpg bar.png baz.png${reset}
Shrink foo.jpg, bar.png, baz.png and download the result images to tiny_pngs/ directory
${bold}$ tinypng -d tiny_pngs/ -- foo.jpg bar.png baz.png${reset}
Written by Rany Albeg Wein - rany.albeg@gmail.com
Contributors
* Jonas Hess ( re4jh )
JPEG support.
24/11/2018
EOF
}
# Die, bitch.
# Args: Exit status (optional), failure message.
die() {
local r=$?
if [[ $1 != *[!0-9]* ]]; then
r=$1
shift
fi
printf 'tinypng: %s\n' "$@" >&2
exit $r
}
# Check if a file is a PNG image.
# Args: File name.
is_png() {
local file=$1
[[ "$(file --brief --mime-type "$file")" = "image/png" ]]
}
# Check if a file is a JPEG image.
# Args: File name.
is_jpg() {
local file=$1
[[ "$(file --brief --mime-type "$file")" = "image/jpeg" ]]
}
# Check if a file is a PNG/JPEG image and store it for shrinking.
# Args: File name.
check_and_store_image() {
local file=$1
if [[ -f $file ]] && (is_png "$file" || is_jpg "$file"); then
org_images+=("$file")
else
printf 'tinypng: Skipping %s. It is not a PNG/JPEG file.\n' "$file" >&2
fi
}
# Ping a site to see if it is reachable
# Args: URL.
is_reachable() {
local url=$1
ping -c1 -w2 "$url" >/dev/null 2>&1
}
# Reads the API key.
# Args: none.
read_key() {
read -r apikey < "$keyfile"
} 2>/dev/null
# Prompt and ask the user for an API key.
# Args: none.
prompt_for_key() {
printf 'Get your API key from %s copy and paste it here.\n' "$dev_url"
read -p 'Enter your API key: ' apikey
echo
}
# Saves the API key for future requests.
# Args: API key.
save_apikey() {
local key=$1
umask 0077
printf '%s\n' "$key" > "$keyfile"
}
# Request a tiny URL from tinypng.com.
# Args: PNGs.
get_shrinked_url() {
local png=$1
curl --fail --silent --user api:"$apikey" \
--data-binary @"$png" -i "$apiurl" --dump-header /dev/stdout | grep -oE -m1 "https://$baseurl/output/[[:alnum:]]+" &
wait
}
# Download a PNG.
# Args: File name, URL to PNG file.
# todo: change name to download in background
download() {
local file=$1 url=$2
curl --fail --progress-bar --output "$file" "$url" &
wait
}
### MAIN ###
# Parse command line options and arguments.
while (( $# ));do
case $1 in
-h|--help)
show_help
exit 0
;;
-k|--key)
apikey=$2
[[ $apikey ]] || die "$1 requires an argument."
shift
;;
-d|--download)
[[ -d $2 ]] || die "$1 requires a directory name as an argument."
download_dir=${2%/}
download_images=1
shift
;;
-f|--file)
if [[ $2 ]]; then
check_and_store_image "$2"
else
die "$1 requires an argument."
fi
shift
;;
-p|--print)
print_urls_after_dl=1
;;
-o|--overwrite)
overwrite=1
;;
--)
shift
for f;do
check_and_store_image "$f"
done
break
;;
*)
show_help && die "$1 Unknown option."
esac
shift
done
(( ${#org_images[@]} )) || { show_help; exit 1; }
# Check if tinypng.com is indeed reachable.
is_reachable "$baseurl" || die "tinypng.com is not reachable."
# Save and/or get API key.
if [[ ! $apikey ]]; then
if ! read_key; then
prompt_for_key
save_apikey "$apikey"
fi
fi
# Request tinypng.com to shrink imagess.
for image in "${org_images[@]}"; do
printf 'Shrinking %s\n' "${image##*/} ..." >&2
if image_url=$(get_shrinked_url "$image"); then
name="tinypng_${image##*/}"
(( overwrite )) && name="${name#tinypng_}"
image_urls["$name"]="$image_url"
else
printf 'tinypng: tinypng.com failed to shrink %s.\n' "$image" >&2
fi
done
# If some of the PNGs were shrinked successfully.
if (( ${#image_urls[@]} )); then
# Download shrinked PNGs.
if (( download_images )); then
for key in "${!image_urls[@]}"; do
printf 'Downloading %s to %s\n' "$key" "$download_dir" >&2
if ! download "$download_dir/$key" "${image_urls[$key]}"; then
printf 'tinypng: Failed to download %s from %s to %s.\n' "$key" "${image_urls[$key]}" "$download_dir" >&2
fi
done
(( print_urls_after_dl )) && printf '%s\n' "${image_urls[@]}"
# Print the URLs of the shrinked images.
else
printf '%s\n' "${image_urls[@]}"
fi
fi