desoto-photoapp 0.4.7 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6f46bf791e878c8020fcc4f3164aa85d23e077b6
4
- data.tar.gz: 0e3f59eb18ff5eafa81e1e183912b0bbe731744c
3
+ metadata.gz: 0d179b8286429cb3e024ca35397e545a9fc7bec6
4
+ data.tar.gz: 2a5ffe60691b4d23ae1e11d8f683b36949e6d5a2
5
5
  SHA512:
6
- metadata.gz: 77c3f1064d046fb2a5544a772adbb0355b1cfa9e1c95ec80349979a14ca9ea8f2666d4b547d63896a71e6a2c6a2cbd0ae079da4281b3fa55d5037bf7d0498c98
7
- data.tar.gz: 6b79b7e663726394215089ea7a66dc0377a4940ddadb9c2420fcdf0defaee30c2aaa27062e0a55a24d014f626c9558c030b7fb6a04ab5de229c084e31a5aa73d
6
+ metadata.gz: 9859dc880a300ae8562918c7bf2fc17640ba3377ef45ef97d046be9b6e7a859deccb8e94d4f045d766efbf219422c8167c3527a0d71078704b0343ddd1501a2a
7
+ data.tar.gz: f365b6b4b5bd127ca84abf773af83492ac7ddad1b665b65c1bee1d462c55c8d08aad46c389af6aa7120422a39fa3ec210dd0c8c37fc26d864832be0f83051892
data/README.md CHANGED
@@ -22,9 +22,6 @@ And then execute:
22
22
 
23
23
  $ bundle
24
24
 
25
- Install the [Automator actions](https://photosautomation.com/index.html) for importing photos. Download the [installer here](https://photosautomation.com/installer.zip).
26
-
27
-
28
25
  Be sure your shell profile loads in executables.
29
26
 
30
27
  ```
@@ -46,9 +43,8 @@ $ photoapp setup
46
43
  This will do the following:
47
44
 
48
45
  - Installs `imagemagick` with (using Homebrew).
49
- - Installs [Automator actions](https://photosautomation.com/index.html) for importing pictures into Photos.app [Manually install from here](https://photosautomation.com/installer.zip)
50
46
  - Copies the image processing Automator workflow to `~/Library/Workflows/Applications/Folder\ Actions/`
51
- - Installs the `Reprint.app` to `/Applications` (You should add this app to the dock for easy reprinting).
47
+ - Installs the `Reprint.app`, `Update.app`, and `Upload.app` to `/Applications`.
52
48
 
53
49
  Finally you'll need to enable the folder action to trigger photo processing when photos are added to the import folder. Launch the folder actions setup app:
54
50
 
@@ -88,18 +84,6 @@ $ photoapp config printer
88
84
  These are the default settings for an Epson Stylus Photo R280. If using a different printer, use whatever settings are equivalent.
89
85
 
90
86
  ```
91
- Page Setup: Sheet Feeder - Borderless
92
- Paper Size: 5x7 in
93
- Media Type: Ulta Premium Photo Paper Glossy
94
-
95
- ... further down ...
96
-
97
- MediaType: Ulta Premium Photo Paper Glossy
98
- Media Size: 5x7 in (Sheet Feeder - Borderless)
87
+ Paper Size: 5x7
88
+ Media Type: Glossy
99
89
  ```
100
-
101
- ## Development
102
-
103
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
104
-
105
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
@@ -0,0 +1,86 @@
1
+ #!/bin/bash
2
+
3
+ # ------------------------------------
4
+ # LOCATE THIS SCRIPT
5
+ # ------------------------------------
6
+
7
+ CLI_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
8
+
9
+ # ------------------------------------
10
+ # IMPORT BASH LIBRARY
11
+ # ------------------------------------
12
+
13
+ source "${CLI_PATH}/imageOptimBashLib"
14
+
15
+ # ------------------------------------
16
+ # INGEST COMMAND LINE ARGUMENTS
17
+ # ------------------------------------
18
+
19
+ while [ "$1" != "" ]; do
20
+ case $1 in
21
+ -d | --directory )
22
+ shift;
23
+ DIRECTORY_OPTION="$1"
24
+ ;;
25
+ -a | --image-alpha )
26
+ USE_IMAGE_ALPHA="true"
27
+ ;;
28
+ -j | --jpeg-mini )
29
+ USE_JPEGMINI="true"
30
+ ;;
31
+ -m | --min-quality )
32
+ shift;
33
+ MIN_QUALITY="$1"
34
+ ;;
35
+ -s | --skip-if-larger )
36
+ SKIP_IF_LARGER="true"
37
+ ;;
38
+ -q | --quit )
39
+ QUIT_ON_COMPLETE="true"
40
+ ;;
41
+ -c | --no-color )
42
+ NO_COLOR="true"
43
+ ;;
44
+ -h | --help )
45
+ usage;
46
+ exit 0
47
+ ;;
48
+ -e | --examples )
49
+ examples;
50
+ exit 0
51
+ ;;
52
+ --verbose )
53
+ IS_VERBOSE="true"
54
+ ;;
55
+ -v | --version )
56
+ echo $VERSION;
57
+ exit 0
58
+ ;;
59
+ * )
60
+ usage
61
+ exit 1
62
+ esac
63
+ shift
64
+ done
65
+
66
+ # ------------------------------------
67
+ # POPULATE VARIABLES
68
+ # ------------------------------------
69
+
70
+ # Determine which Applications are installed.
71
+ HAS_IMAGE_OPTIM=$(has_imageoptim)
72
+ HAS_JPEGMINI=$(has_jpegmini)
73
+ HAS_IMAGEMAGICK=$(has_imagemagick)
74
+ HAS_GUI_SCRIPT=`osascript -e 'tell application "System Events" to get UI elements enabled'`
75
+ JPEGMINI_NAME=$(get_jpegmini_app_name)
76
+
77
+ # ------------------------------------
78
+ # BEGIN PROCESSING
79
+ # ------------------------------------
80
+
81
+ start
82
+ run_image_alpha
83
+ run_jpegmini
84
+ run_image_optim
85
+ output_savings
86
+ finish
@@ -0,0 +1,251 @@
1
+ #!/bin/osascript
2
+
3
+ -- https://raw.githubusercontent.com/JamieMason/LICENSES/master/LICENSE-MIT
4
+
5
+ global DIRECTORY_GIF
6
+ global DIRECTORY_JPG
7
+ global DIRECTORY_PNG
8
+ global DIRECTORY_TEMP
9
+ global ID_IMAGEOPTIM
10
+ global ID_JPEGMINI
11
+ global ID_JPEGMINI_RETAIL
12
+ global ID_JPEGMINI_LITE
13
+ global ID_JPEGMINI_LITE_RETAIL
14
+ global ID_JPEGMINI_PRO
15
+ global ID_JPEGMINI_PRO_RETAIL
16
+ global JPEGMINI_APP_NAME
17
+
18
+ (*
19
+ * @description
20
+ * Is the app with this bundle id installed somewhere on this machine?
21
+ *
22
+ * @param {String} bundleId eg. ID_IMAGEOPTIM
23
+ * @return {Boolean}
24
+ *)
25
+ on isInstalled(bundleId)
26
+ try
27
+ tell application "Finder" to get application file id bundleId
28
+ return true
29
+ on error
30
+ return false
31
+ end try
32
+ end isInstalled
33
+
34
+ (*
35
+ * @description
36
+ * Check whether access for assistive devices is enabled under System
37
+ * Preferences, needed to perform synthetic user actions so JPEGmini can be
38
+ * automated.
39
+ *
40
+ * Enable access for assistive devices in Mavericks;
41
+ * http://www.tekrevue.com/how-to-enable-access-for-assistive-devices-in-os-x-mavericks/
42
+ *
43
+ * Enable access for assistive devices in Yosemite;
44
+ * https://thequantumself.wordpress.com/2014/06/26/enable-access-for-assistive-devices-in-osx-yosmite/
45
+ *
46
+ * @return {Boolean}
47
+ *)
48
+ on supportsAssistiveDevices()
49
+ try
50
+ -- return do shell script "osascript -e 'tell application \"System Events\" to get UI elements enabled'"
51
+ tell application "System Events" to get UI elements enabled
52
+ on error
53
+ return "ERROR_GUISCRIPT_UNREADABLE"
54
+ end try
55
+ end supportsAssistiveDevices
56
+
57
+ (*
58
+ * @description
59
+ * Find the appropriate JPEGmini app name, starting with the paid-for plans
60
+ * down to the free one.
61
+ *
62
+ * @return {String} eg. "JPEGmini Pro"
63
+ *)
64
+ on getJpegMiniAppName()
65
+ if isInstalled(ID_JPEGMINI_PRO) or isInstalled(ID_JPEGMINI_PRO_RETAIL) then
66
+ return "JPEGmini Pro"
67
+ else if isInstalled(ID_JPEGMINI) or isInstalled(ID_JPEGMINI_RETAIL) then
68
+ return "JPEGmini"
69
+ else if isInstalled(ID_JPEGMINI_LITE) or isInstalled(ID_JPEGMINI_LITE_RETAIL) then
70
+ return "JPEGmini Lite"
71
+ end if
72
+ return "false"
73
+ end getJpegMiniAppName
74
+
75
+ on hasJPEGmini()
76
+ if getJpegMiniAppName() is "false" then
77
+ return false
78
+ else
79
+ return true
80
+ end if
81
+ end hasJPEGmini
82
+
83
+ on hasImageOptim()
84
+ return isInstalled(ID_IMAGEOPTIM)
85
+ end hasImageOptim
86
+
87
+ (*
88
+ * @description
89
+ * Run JPEGmini <variant> over the contents of DIRECTORY_JPG.
90
+ *)
91
+ on runJPEGmini()
92
+ (* DETERMINE WHICH VERSION IS INSTALLED *)
93
+ set JPEGMINI_APP_NAME to getJpegMiniAppName()
94
+ (* QUIT IF NOT INSTALLED *)
95
+ if JPEGMINI_APP_NAME is "false" then
96
+ return "ERROR_JPEGMINI_UNAVAILABLE"
97
+ end if
98
+ (* OPEN AND FOCUS JPEGMINI *)
99
+ tell application JPEGMINI_APP_NAME
100
+ activate
101
+ delay 3
102
+ activate
103
+ end tell
104
+ (* SPAWN THE FILE > OPEN MENU *)
105
+ tell application "System Events"
106
+ keystroke "o" using {command down}
107
+ delay 3
108
+ keystroke "g" using {command down, shift down}
109
+ delay 2
110
+ end tell
111
+ (* NAVIGATE TO OUR FOLDER OF IMAGES *)
112
+ tell application "System Events"
113
+ tell process JPEGMINI_APP_NAME
114
+ (* < SIERRA, FILE PATH SELECTOR IS TEXT INPUT *)
115
+ if text field 1 of sheet 1 of sheet 1 of window 1 exists then
116
+ set value of text field 1 of sheet 1 of sheet 1 of window 1 to DIRECTORY_JPG
117
+ repeat
118
+ if (value of text field 1 of sheet 1 of sheet 1 of window 1) is not equal to DIRECTORY_JPG then
119
+ delay 1
120
+ else
121
+ exit repeat
122
+ end if
123
+ end repeat
124
+ end if
125
+ (* = SIERRA, FILE PATH SELECTOR IS COMBO BOX *)
126
+ if combo box 1 of sheet 1 of sheet 1 of window 1 exists then
127
+ set value of combo box 1 of sheet 1 of sheet 1 of window 1 to DIRECTORY_JPG
128
+ repeat
129
+ if (value of combo box 1 of sheet 1 of sheet 1 of window 1) is not equal to DIRECTORY_JPG then
130
+ delay 1
131
+ else
132
+ exit repeat
133
+ end if
134
+ end repeat
135
+ end if
136
+ (* >= HIGH SIERRA *)
137
+ if combo box 1 of sheet 1 of window 1 exists then
138
+ set value of combo box 1 of sheet 1 of window 1 to DIRECTORY_JPG
139
+ repeat
140
+ if (value of combo box 1 of sheet 1 of window 1) is not equal to DIRECTORY_JPG then
141
+ delay 1
142
+ else
143
+ exit repeat
144
+ end if
145
+ end repeat
146
+ end if
147
+ -- give Finder time to resolve the path
148
+ delay 2
149
+ keystroke return
150
+ delay 2
151
+ keystroke return
152
+ -- start optimising (>= Yosemite)
153
+ -- click button "Go" of sheet 1 of window 1
154
+ -- start optimising (<= Mavericks)
155
+ -- click button "Open" of sheet 1 of window 1
156
+ end tell
157
+ end tell
158
+ (* WAIT FOR JPEGMINI TO FINISH RUNNING *)
159
+ tell application "System Events"
160
+ set timesIdle to 0
161
+ repeat
162
+ -- get all process information | filtered to JPEGmini
163
+ set getRawProcess to "ps aux | grep '/Applications/" & JPEGMINI_APP_NAME & "'"
164
+ -- filter out JPEGmini grep | get column 3 of output (% CPU)
165
+ set filterRawProcess to "grep -v grep | awk '{print $3}'"
166
+ -- store above pipe chain in a variable
167
+ set getRawCpu to "RAWCPU=$(" & getRawProcess & " | " & filterRawProcess & ")"
168
+ -- round that variable to a whole number
169
+ set outputRoundedCpu to "$(printf \"%.0f\" $(echo \"scale=2;$RAWCPU\" | bc))"
170
+ -- join the two commands and echo it out to applescript
171
+ set getCpuPercent to getRawCpu & " && echo " & outputRoundedCpu
172
+ -- get raw terminal string output
173
+ set cpuPercent to (do shell script getCpuPercent) as number
174
+ -- give the app a little time to work
175
+ delay 0.5
176
+ -- if the app is idle
177
+ if (cpuPercent) < 1 then
178
+ -- increment number of times we've found the app consecutively idle
179
+ set timesIdle to timesIdle + 1
180
+ -- if it's been idle for long enough we can exit
181
+ if (timesIdle) > 5 then
182
+ exit repeat
183
+ end if
184
+ end if
185
+ -- (implied else: by not exiting we repeat again)
186
+ end repeat
187
+ delay 0.5
188
+ end tell
189
+ end runJPEGmini
190
+
191
+ (*
192
+ * @param {String} appName eg. "ImageOptim"
193
+ *)
194
+ on quitApp(appName)
195
+ tell application appName to quit
196
+ end quitApp
197
+
198
+ on quitImageOptim()
199
+ quitApp("ImageOptim")
200
+ end runImageOptim
201
+
202
+ on quitJPEGmini()
203
+ quitApp(getJpegMiniAppName())
204
+ end runImageOptim
205
+
206
+ (*
207
+ * @description
208
+ * Handle command-line arguments.
209
+ *
210
+ * @example
211
+ * ./imageOptimAppleScriptLib "<action>" "<quitAfter>"
212
+ *)
213
+ on run argv
214
+
215
+ (* INITIALISE GLOBALS *)
216
+
217
+ set DIRECTORY_TEMP to (do shell script "echo $TMPDIR") & "imageoptim-cli/"
218
+ set DIRECTORY_GIF to DIRECTORY_TEMP & "gif"
219
+ set DIRECTORY_JPG to DIRECTORY_TEMP & "jpg"
220
+ set DIRECTORY_PNG to DIRECTORY_TEMP & "png"
221
+ set ID_IMAGEOPTIM to "net.pornel.ImageOptim"
222
+ set ID_JPEGMINI to "com.icvt.JPEGmini"
223
+ set ID_JPEGMINI_RETAIL to "com.icvt.JPEGmini-retail"
224
+ set ID_JPEGMINI_LITE to "com.icvt.JPEGminiLite"
225
+ set ID_JPEGMINI_LITE_RETAIL to "com.icvt.JPEGminiLite-retail"
226
+ set ID_JPEGMINI_PRO to "com.icvt.JPEGmini-Pro"
227
+ set ID_JPEGMINI_PRO_RETAIL to "com.icvt.JPEGmini-Pro-retail"
228
+
229
+ (* HANDLE COMMAND LINE ARGUMENTS *)
230
+
231
+ set action to item 1 of argv
232
+
233
+ (* PERFORM ACTION *)
234
+
235
+ if action is "quitImageOptim" then
236
+ return quitImageOptim()
237
+ else if action is "quitJPEGmini" then
238
+ return quitJPEGmini()
239
+ else if action is "runJPEGmini" then
240
+ return runJPEGmini()
241
+ else if action is "supportsAssistiveDevices" then
242
+ return supportsAssistiveDevices()
243
+ else if action is "getJpegMiniAppName" then
244
+ return getJpegMiniAppName()
245
+ else if action is "hasJPEGmini" then
246
+ return hasJPEGmini()
247
+ else if action is "hasImageOptim" then
248
+ return hasImageOptim()
249
+ end if
250
+
251
+ end run
@@ -0,0 +1,534 @@
1
+ #!/bin/bash
2
+
3
+ # https://raw.githubusercontent.com/JamieMason/LICENSES/master/LICENSE-MIT
4
+
5
+ # ------------------------------------
6
+ # DEFAULT / ENVIRONMENT VARIABLES
7
+ # ------------------------------------
8
+
9
+ # current version of ImageOptim-CLI from package.json
10
+ VERSION="1.15.4"
11
+
12
+ # {DirectoryPath} Absolute file system path to this shell script.
13
+ CLI_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
14
+
15
+ # {DirectoryPath} Absolute file system path to where this shell script was invoked from.
16
+ EXEC_PATH="$PWD"
17
+
18
+ # {FilePath} The location of our Applescript library file.
19
+ APPLESCRIPT_BIN="$CLI_PATH/imageOptimAppleScriptLib"
20
+
21
+ # {FilePath} The location of stat (see issue #59 with stat & homebrew)
22
+ STAT_BIN="/usr/bin/stat"
23
+
24
+ # {DirectoryPath} Where we'll copy all images to be processed, compared, then returned to their
25
+ # original locations.
26
+ TEMP_PATH="${TMPDIR}imageoptim-cli"
27
+
28
+ # {FilePath} A list of all images we'll be operating on.
29
+ INDEX_FILE="${TEMP_PATH}/index.txt"
30
+
31
+ # {FilePath[]} The original locations of every image to be processed.
32
+ INDEX_ARRAY=[]
33
+
34
+ # {Number} How many images in total being processed.
35
+ TOTAL_IMAGES=0
36
+
37
+ # {DirectoryPath|String} The optionally provided -d or --directory command line argument.
38
+ DIRECTORY_OPTION="false"
39
+
40
+ # {Number} Optinally overriden with -m or --min-quality
41
+ MIN_QUALITY="75"
42
+
43
+ # {BooleanString} Optionally use -s or --skip-if-larger with pngquant
44
+ SKIP_IF_LARGER="false"
45
+
46
+ # {BooleanString} Optionally overridden with -a or --image-alpha.
47
+ USE_IMAGE_ALPHA="false"
48
+
49
+ # {BooleanString} Optionally overridden with -j or --jpeg-mini.
50
+ USE_JPEGMINI="false"
51
+
52
+ # {BooleanString} Optionally overridden with -q or --quit.
53
+ QUIT_ON_COMPLETE="false"
54
+
55
+ # {RegEx} Supported file extensions for each application.
56
+ FILE_TYPES_REGEX_IMAGE_ALPHA=".*(png)$"
57
+ FILE_TYPES_REGEX_IMAGE_OPTIM=".*(bmp|gif|jpeg|jpg|pcx|png|pnm|tga|tiff)$"
58
+ FILE_TYPES_REGEX_JPEGMINI=".*(jpg|jpeg)$"
59
+
60
+ # {FilePath} Location of pngquant executable within ImageAlpha.
61
+ PNGQUANT_PATH="${CLI_PATH}/pngquant"
62
+
63
+ # {FilePath} Location of executable within ImageOptim.
64
+ IMAGEOPTIM_BIN_PATH="/Applications/ImageOptim.app/Contents/MacOS/ImageOptim"
65
+
66
+ # {BooleanString} Whether we can compare file quality afterwards, will be set to
67
+ # true accordingly during initialisation.
68
+ HAS_IMAGEMAGICK="false"
69
+
70
+ # {BooleanString} Whether to disable ANSI colour output.
71
+ NO_COLOR="false"
72
+
73
+ # {BooleanString} Whether to print detailed information about the optimizations
74
+ IS_VERBOSE="false"
75
+
76
+ # ------------------------------------
77
+ # LOGGING UTILS
78
+ # ------------------------------------
79
+
80
+ # Display a red error message and quit
81
+ # param {String} $1 message
82
+ function fatal {
83
+ if [ $NO_COLOR == "false" ]; then
84
+ printf "\e[31m✘ $1\033[0m\n"
85
+ else
86
+ echo "Error: $1"
87
+ fi
88
+ exit 1
89
+ }
90
+
91
+ # Display a message in green with a tick by it
92
+ # param {String} $1 message
93
+ function success {
94
+ if [ $NO_COLOR == "false" ]; then
95
+ printf "\e[32m✔ $1\033[0m\n"
96
+ else
97
+ echo "Success: $1"
98
+ fi
99
+ }
100
+
101
+ # Display an info message
102
+ # param {String} $1 message
103
+ function info {
104
+ if [ $NO_COLOR == "false" ]; then
105
+ printf "\e[90m$1\e[39m\n"
106
+ else
107
+ echo $1
108
+ fi
109
+ }
110
+
111
+ # Display a message in green
112
+ # param {String} $1 message
113
+ function format_green {
114
+ if [ $NO_COLOR == "false" ]; then
115
+ echo "\e[32m$1\e[39m"
116
+ else
117
+ echo $1
118
+ fi
119
+ }
120
+
121
+ # Display a message in red
122
+ # param {String} $1 message
123
+ function format_red {
124
+ if [ $NO_COLOR == "false" ]; then
125
+ echo "\e[31m$1\e[39m"
126
+ else
127
+ echo $1
128
+ fi
129
+ }
130
+
131
+ # Display usage information
132
+ function usage {
133
+ echo "Usage: imageOptim [options]"
134
+ echo ""
135
+ echo "Options:"
136
+ echo ""
137
+ echo " -d, --directory directory of images to process"
138
+ echo " -a, --image-alpha pre-process PNGs with ImageAlpha.app *"
139
+ echo " -j, --jpeg-mini pre-process JPGs with JPEGmini.app **"
140
+ echo " -m, --min-quality pngquant min quality parameter"
141
+ echo " -s, --skip-if-larger pngquant use --skip-if-larger"
142
+ echo " -q, --quit quit all apps when complete"
143
+ echo " -c, --no-color disable color output"
144
+ echo " -h, --help display this usage information"
145
+ echo " -e, --examples display some example commands and uses"
146
+ echo " -v, --version display the version number"
147
+ echo " --verbose display detailed, per-file info on optimizations"
148
+ echo ""
149
+ echo "* http://pngmini.com"
150
+ echo "** https://itunes.apple.com/us/app/jpegmini/id498944723"
151
+ echo ""
152
+ }
153
+
154
+ # Display usage examples
155
+ function examples {
156
+ echo "### Optimise a directory of images"
157
+ echo ""
158
+ echo "This command will optimise all image files in your Awesome project."
159
+ echo ""
160
+ echo " imageOptim --directory ~/Sites/Awesome # [options]"
161
+ echo ""
162
+ echo "### Optimise a filtered set of images"
163
+ echo ""
164
+ echo "This command will optimise just the .jpg files in your Awesome project."
165
+ echo ""
166
+ echo " find ~/Sites/Awesome -name '*.jpg' | imageOptim # [options]"
167
+ echo ""
168
+ echo "### Passing additional options"
169
+ echo ""
170
+ echo "The long format for enabling options is as follows;"
171
+ echo ""
172
+ echo " imageOptim --jpeg-mini --image-alpha --quit --no-color --directory path/to/images"
173
+ echo ""
174
+ echo "The equivalent of the above in short format is as follows;"
175
+ echo ""
176
+ echo " imageOptim -j -a -q -c -d path/to/images"
177
+ echo ""
178
+ echo "### Adding to git pre-commit hook"
179
+ echo ""
180
+ echo "Adding the below to **your_project/.git/hooks/pre-commit** will run imageoptim-CLI"
181
+ echo "each time you commit new and changed files into your project. Any files which"
182
+ echo "aren't images will be ignored."
183
+ echo ""
184
+ echo " images=$(git diff --exit-code --cached --name-only --diff-filter=ACM -- '*.png' '*.jpg')"
185
+ echo " $(exit $?) || (echo "$images" | imageOptim && git add $images)"
186
+ echo ""
187
+ }
188
+
189
+ # Display the before/after result of a file
190
+ # param {String} $1 label
191
+ # param {Number} $2 size_before
192
+ # param {Number} $3 size_after
193
+ # param {Number} $4 quality_loss
194
+ function render_result {
195
+ let local savings=$2-$3
196
+ local savings_percent=$(bc <<< "scale=2; $savings/$2 * 100")
197
+ local size_before=$(format_red "$(toKb $2)kb")
198
+ local size_after=$(format_green "$(toKb $3)kb")
199
+ local savings=$(format_green "$(toKb $savings)kb")
200
+ local savings_percent=$(format_green "$savings_percent%%")
201
+ local quality_loss=$(bc <<< "scale=2; 100-$4")
202
+ local quality_loss=$(format_green "$quality_loss%%")
203
+ local output="$1 was: $size_before now: $size_after saving: $savings ($savings_percent)"
204
+ if [[ $HAS_IMAGEMAGICK != "false" ]]; then
205
+ local output="$output quality: $quality_loss"
206
+ fi
207
+ printf "$output\n"
208
+ }
209
+
210
+ # Display the before/after results of all files
211
+ function output_savings {
212
+ local total_before=0
213
+ local total_after=0
214
+ local perfect_quality=0
215
+ local actual_quality=0
216
+ for source_file in "${INDEX_ARRAY[@]}"; do
217
+ local image_type=$(get_image_type "$source_file")
218
+ if [[ $image_type != "unsupported" ]]; then
219
+ local temp_file=$(get_temp_path_for_file "$source_file")
220
+ local size_before=$(sizeInBytes "$source_file")
221
+ local size_after=$(sizeInBytes "$temp_file")
222
+ let local total_before=$total_before+$size_before
223
+ let local total_after=$total_after+$size_after
224
+ local perfect_quality=$(bc <<< "scale=2; $perfect_quality+100")
225
+ local quality_loss="false"
226
+ if [[ $HAS_IMAGEMAGICK == "true" ]]; then
227
+ local quality_loss=$(compare -metric MSE "$source_file" "$temp_file" /dev/null 2>&1 >/dev/null | awk '{print $1}')
228
+ if [[ $quality_loss == *:* ]]; then
229
+ quality_loss=0
230
+ fi
231
+ local actual_quality=$(bc <<< "scale=2; $actual_quality+$quality_loss")
232
+ fi
233
+ if [[ $IS_VERBOSE == "true" ]]; then
234
+ render_result "$source_file" $size_before $size_after $quality_loss
235
+ fi
236
+ fi
237
+ done
238
+ render_result "TOTAL" $total_before $total_after $quality_loss
239
+ }
240
+
241
+ # ------------------------------------
242
+ # DETERMINE WHAT EXISTS AT A GIVEN LOCATION
243
+ # ------------------------------------
244
+
245
+ # State whether the entity at path is a "file", "directory", or "other".
246
+ # param {EntityPath} $1 entity
247
+ # return {String} file_type
248
+ function get_entity_type {
249
+ if [ -f "$1" ]; then
250
+ echo "file"
251
+ elif [ -d "$1" ]; then
252
+ echo "directory"
253
+ else
254
+ echo "other"
255
+ fi
256
+ }
257
+
258
+ # State whether the entity at path is a "png", "jpg", "other", or "unsupported" image file.
259
+ # param {EntityPath} $1 entity
260
+ # return {String} image_type
261
+ function get_image_type {
262
+ shopt -s nocasematch
263
+ if [[ "$1" =~ $FILE_TYPES_REGEX_IMAGE_ALPHA ]]; then
264
+ echo "png"
265
+ elif [[ "$1" =~ $FILE_TYPES_REGEX_JPEGMINI ]]; then
266
+ echo "jpg"
267
+ elif [[ "$1" =~ $FILE_TYPES_REGEX_IMAGE_OPTIM ]]; then
268
+ echo "other"
269
+ else
270
+ echo "unsupported"
271
+ fi
272
+ shopt -u nocasematch
273
+ }
274
+
275
+ # ------------------------------------
276
+ # GATHER PATHS TO IMAGES
277
+ # ------------------------------------
278
+
279
+ # Add file received via stdin to our index file.
280
+ # param {FilePath} $1 file
281
+ function add_file_to_index {
282
+ local image_type=$(get_image_type "$1")
283
+ if [ $image_type != "unsupported" ]; then
284
+ echo "$1" >> $INDEX_FILE
285
+ else
286
+ info "Ignored as an unsupported file type: $LINE"
287
+ fi
288
+ }
289
+
290
+ # Add all files in a directory to our index file.
291
+ # param {DirectoryPath} $1 directory
292
+ function add_directory_to_index {
293
+ find -E "$1" -iregex $FILE_TYPES_REGEX_IMAGE_OPTIM -type f -print0 | while read -d '' -r file; do
294
+ add_file_to_index "$file"
295
+ done
296
+ }
297
+
298
+ # Read files received via stdin into an index which will outlive the LINE variable.
299
+ function add_stdin_to_index {
300
+ if [ "$DIRECTORY_OPTION" == "false" ]; then
301
+ while read LINE; do
302
+ local entity_type=$(get_entity_type "$LINE")
303
+ if [ $entity_type == "file" ]; then
304
+ add_file_to_index "$LINE"
305
+ elif [ $entity_type == "directory" ]; then
306
+ add_directory_to_index "$LINE"
307
+ else
308
+ info "Ignored as neither file or directory: $LINE"
309
+ fi
310
+ done
311
+ fi
312
+ }
313
+
314
+ # If -d or --directory were supplied, add the contents of that directory to our processing index.
315
+ function add_directory_option_to_index {
316
+ if [ "$DIRECTORY_OPTION" != "false" ]; then
317
+ if [ -d "$DIRECTORY_OPTION" ]; then
318
+ add_directory_to_index "$DIRECTORY_OPTION"
319
+ else
320
+ fatal "Value for --directory is not a directory: $LINE"
321
+ fi
322
+ fi
323
+ }
324
+
325
+ # Remove any duplicate files in our index, which may have occurred when importing directories whose
326
+ # images have already been gathered by other means.
327
+ function remove_duplicate_indexes {
328
+ LC_ALL=C sort -uf "$INDEX_FILE" > "$INDEX_FILE.uniq.txt"
329
+ mv "$INDEX_FILE.uniq.txt" "$INDEX_FILE"
330
+ }
331
+
332
+ # Check we actually got some files
333
+ # test -s means exists and size > zero
334
+ # See: man bash | less '+/^\s*CONDITIONAL'
335
+ function check_index_exists {
336
+ if [ ! -s "$INDEX_FILE" ]; then
337
+ fatal "No files found by the find command or in the provided directory"
338
+ fi
339
+ }
340
+
341
+ # Read our index file into an Array.
342
+ function parse_index {
343
+ IFS=$'\n' read -d '' -r -a INDEX_ARRAY < "$INDEX_FILE"
344
+ TOTAL_IMAGES=${#INDEX_ARRAY[@]}
345
+ }
346
+
347
+ # Construct a clean Array containing sorted, unique paths to every image we should process.
348
+ function gather_paths_to_images {
349
+ add_stdin_to_index
350
+ add_directory_option_to_index
351
+ check_index_exists
352
+ remove_duplicate_indexes
353
+ parse_index
354
+ }
355
+
356
+ # ------------------------------------
357
+ # PREPARE A TEMPORARY DIRECTORY
358
+ # ------------------------------------
359
+
360
+ function clean {
361
+ rm -rf "$TEMP_PATH"
362
+ }
363
+
364
+ # Automating JPEGmini is particularily difficult and unusably slow when working with arbitrary sets
365
+ # of files. Instead, we create a temporary directory and pass that once to JPEGmini rather than
366
+ # each file individually.
367
+ function init_temp_directory {
368
+ clean
369
+ mkdir -p "$TEMP_PATH"
370
+ chmod 777 "$TEMP_PATH"
371
+ }
372
+
373
+ # Get the absolute path of an entity
374
+ # param {EntityPath} $1 entity
375
+ # return {EntityPath} absolute_path
376
+ function to_absolute {
377
+ local present_dir="$PWD"
378
+ local file_dir=$(dirname "$1")
379
+ local file_name=$(basename "$1")
380
+ cd "$file_dir"
381
+ local absolute_dir="$PWD"
382
+ cd "$present_dir"
383
+ echo "${absolute_dir}/${file_name}"
384
+ }
385
+
386
+ # Determine the location in our temp directory a given file should be held at.
387
+ # param {FilePath} $1 file
388
+ # return {FilePath} temp_file
389
+ function get_temp_path_for_file {
390
+ local absolute_path=$(to_absolute "$1")
391
+ local image_type=$(get_image_type "$absolute_path")
392
+ echo "${TEMP_PATH}/${image_type}/$absolute_path"
393
+ }
394
+
395
+ # Copy all files received to a temp directory, grouped by file extension.
396
+ function populate_temp_directories {
397
+ local image_type
398
+ local temp_file
399
+ for source_file in "${INDEX_ARRAY[@]}"; do
400
+ image_type=$(get_image_type "$source_file")
401
+ temp_file=$(get_temp_path_for_file "$source_file")
402
+ if [[ $image_type != "unsupported" ]]; then
403
+ ditto "$source_file" "$temp_file"
404
+ fi
405
+ done
406
+ }
407
+
408
+ # @TODO: DRY these two methods
409
+
410
+ # Copy all files received back to their original locations.
411
+ function replace_originals {
412
+ local image_type
413
+ local temp_file
414
+ for source_file in "${INDEX_ARRAY[@]}"; do
415
+ image_type=$(get_image_type "$source_file")
416
+ temp_file=$(get_temp_path_for_file "$source_file")
417
+ if [[ $image_type != "unsupported" ]]; then
418
+ ditto "$temp_file" "$source_file"
419
+ rm "$temp_file"
420
+ fi
421
+ done
422
+ }
423
+
424
+ # Gather paths to all images we should process and prepare a temporary directory containing copies.
425
+ function prepare_images {
426
+ gather_paths_to_images
427
+ if [ $TOTAL_IMAGES -gt 0 ]; then
428
+ populate_temp_directories
429
+ fi
430
+ }
431
+
432
+ function start {
433
+ init_temp_directory
434
+ prepare_images
435
+ }
436
+
437
+ function finish {
438
+ replace_originals
439
+ clean
440
+ }
441
+
442
+ # ------------------------------------
443
+ # INVOKE IMAGE APPLICATIONS
444
+ # ------------------------------------
445
+
446
+ # Determine whether GUI Scripting is enabled, which is needed to automate JPEGmini.
447
+ function has_gui_script {
448
+ echo `osascript "$APPLESCRIPT_BIN" supportsAssistiveDevices`
449
+ }
450
+
451
+ # State whether eg node, brew, gem etc is installed
452
+ # param {CliApp} $1 bin
453
+ # return {BooleanString} is_installed
454
+ function has_imagemagick {
455
+ local is_installed="true"
456
+ type compare >/dev/null 2>&1 || { local is_installed="false"; }
457
+ echo "$is_installed"
458
+ }
459
+
460
+ function has_imageoptim {
461
+ echo `osascript "$APPLESCRIPT_BIN" hasImageOptim`
462
+ }
463
+
464
+ function has_jpegmini {
465
+ echo `osascript "$APPLESCRIPT_BIN" hasJPEGmini`
466
+ }
467
+
468
+ function get_jpegmini_app_name {
469
+ echo `osascript "$APPLESCRIPT_BIN" getJpegMiniAppName`
470
+ }
471
+
472
+ # If enabled and installed, run ImageAlpha on our temp directory
473
+ function run_image_alpha {
474
+ if [ "true" == "$USE_IMAGE_ALPHA" ]; then
475
+ info "Running ImageAlpha..."
476
+ local added_options
477
+ if [ "true" == "$SKIP_IF_LARGER" ]; then
478
+ added_options="--skip-if-larger"
479
+ fi
480
+ find "${TEMP_PATH}/png" -type f -print0 | xargs -n10 -P8 -0 "$PNGQUANT_PATH" --ext=.png --force --speed=1 --quality="$MIN_QUALITY"-100 ${added_options} --
481
+ fi
482
+ }
483
+
484
+ # If enabled and installed, run JPEGmini on our temp directory
485
+ function run_jpegmini {
486
+ if [ "true" == "$USE_JPEGMINI" ]; then
487
+ if [ "true" == "$HAS_JPEGMINI" ]; then
488
+ if [ "true" != "$HAS_GUI_SCRIPT" ]; then
489
+ fatal "To automate JPEGmini we need to add Terminal.app (or iTerm.app etc) to the 'support for assistive devices' whitelist. Please see README for more details."
490
+ fi
491
+ info "Running ${JPEGMINI_NAME}..."
492
+ local location=`osascript -e "POSIX path of (path to application \"${JPEGMINI_NAME}\")"`
493
+ open "${location}"
494
+ osascript "$APPLESCRIPT_BIN" runJPEGmini
495
+ if [ "true" == "$QUIT_ON_COMPLETE" ]; then
496
+ osascript "$APPLESCRIPT_BIN" quitJPEGmini
497
+ fi
498
+ else
499
+ fatal "JPEGmini is not installed (https://itunes.apple.com/us/app/jpegmini/id498944723)"
500
+ fi
501
+ fi
502
+ }
503
+
504
+ # If enabled and installed, run ImageOptim on our temp directory
505
+ function run_image_optim {
506
+ info "Running ImageOptim..."
507
+ # find where imageoptim is installed (opens app)
508
+ local location=`osascript -e 'POSIX path of (path to application "ImageOptim")'`
509
+ # close duplicate app
510
+ osascript "$APPLESCRIPT_BIN" quitImageOptim
511
+ # run images over the app
512
+ "${location}Contents/MacOS/ImageOptim" 2> /dev/null "${TEMP_PATH}"
513
+ if [ "true" == "$QUIT_ON_COMPLETE" ]; then
514
+ osascript "$APPLESCRIPT_BIN" quitImageOptim
515
+ fi
516
+ }
517
+
518
+ # ------------------------------------
519
+ # GET AND MANAGE FILE SIZES
520
+ # ------------------------------------
521
+
522
+ # Get the size of a file, in bytes.
523
+ # param {FilePath} $1 file
524
+ # return {Number} file_size
525
+ function sizeInBytes {
526
+ echo $($STAT_BIN -f %z "$1")
527
+ }
528
+
529
+ # Convert a value in bytes to kilobytes in 3 decimal places, 1b is 0.001kb for example.
530
+ # param {Number} $1 bytes
531
+ # return {Number} kilobytes
532
+ function toKb {
533
+ echo $(bc <<< "scale=3; $1/1000")
534
+ }