diff --git a/bin/Crunch.app/Contents/Info.plist b/bin/Crunch.app/Contents/Info.plist
index 7057b5e..939b424 100644
Binary files a/bin/Crunch.app/Contents/Info.plist and b/bin/Crunch.app/Contents/Info.plist differ
diff --git a/bin/Crunch.app/Contents/Resources/Credits.html b/bin/Crunch.app/Contents/Resources/Credits.html
index f70f219..dbf82b2 100644
--- a/bin/Crunch.app/Contents/Resources/Credits.html
+++ b/bin/Crunch.app/Contents/Resources/Credits.html
@@ -19,7 +19,12 @@
Upgrade
The latest release can be found
here
- . To upgrade with Homebrew, enter the following command in your terminal:
+ . A
+
+ changelog
+ is available for review of changes to the application since your installed version was released.
+
+ To upgrade with Homebrew, enter the following command in your terminal:
$ brew cask uninstall crunch && brew cask install crunch
diff --git a/bin/Crunch.app/Contents/Resources/crunch.py b/bin/Crunch.app/Contents/Resources/crunch.py
index cc3777d..54cf372 100755
--- a/bin/Crunch.app/Contents/Resources/crunch.py
+++ b/bin/Crunch.app/Contents/Resources/crunch.py
@@ -14,6 +14,7 @@
import sys
import os
import shutil
+import struct
import subprocess
from subprocess import CalledProcessError
@@ -22,11 +23,21 @@
# Locks
lock = Lock()
-# Processor Constants
-PROCESSES = 0 # detected automatically in source if this is defined as zero
+# Processor Constant
+# - Modify this to an integer value if you want to fix the number of
+# processes spawned during execution. The process number is
+# automatically defined during source execution when this is defined
+# as a value of 0
+PROCESSES = 0
+
+# Dependency Path Constants for Command Line Executable
+# - Redefine these path strings to use system-installed versions of
+# pngquant and zopflipng (e.g. to "/usr/local/bin/[executable]")
+PNGQUANT_CLI_PATH = os.path.join(os.path.expanduser("~"), "pngquant", "pngquant")
+ZOPFLIPNG_CLI_PATH = os.path.join(os.path.expanduser("~"), "zopfli", "zopflipng")
# Application Constants
-VERSION = "2.0.2"
+VERSION = "2.1.0"
VERSION_STRING = "crunch v" + VERSION
HELP_STRING = """
@@ -98,9 +109,8 @@ def main(argv):
# COMMAND LINE ERROR HANDLING
# //////////////////////////////////
- # PNG file path error handling
-
for png_path in png_path_list:
+ # Not a file test
if not os.path.isfile(png_path): # is not an existing file
sys.stderr.write(
"[ERROR] '"
@@ -109,13 +119,9 @@ def main(argv):
+ os.linesep
)
sys.exit(1)
- elif not png_path[-4:] == ".png": # does not end with .png extension
- sys.stderr.write(
- "[ERROR] '"
- + png_path
- + "' does not appear to be a PNG image file"
- + os.linesep
- )
+ # PNG validity test
+ if not is_valid_png(png_path):
+ sys.stderr.write("[ERROR] '" + png_path + "' is not a valid PNG file." + os.linesep)
sys.exit(1)
# Dependency error handling
@@ -162,7 +168,7 @@ def main(argv):
except Exception as e:
lock.acquire()
sys.stderr.write("-----" + os.linesep)
- sys.stderr.write("[ERROR] Error detected during execution of request:" + os.linesep)
+ sys.stderr.write("[ERROR] Error detected during execution of the request." + os.linesep)
sys.stderr.write(str(e) + os.linesep)
lock.release()
sys.exit(1)
@@ -240,13 +246,36 @@ def optimize_png(png_path):
lock.release()
+def fix_filepath_args(args):
+ arg_list = []
+ parsed_filepath = ""
+ for arg in args:
+ if arg[0] == "-":
+ # add command line options
+ arg_list.append(arg)
+ elif len(arg) > 4 and arg[-4:] == ".png":
+ # this is the end of a filepath string that may have had
+ # spaces in directories prior to this level. Let's recreate
+ # the entire original path
+ filepath = parsed_filepath + arg
+ arg_list.append(filepath)
+ # reset the temp string that is used to reconstruct the filepaths
+ parsed_filepath = ""
+ else:
+ # if the argument does not end with a .png, then there must have
+ # been a space in the directory paths, let's add it back
+ parsed_filepath = parsed_filepath + arg + " "
+ # return new argument list with fixed filepaths to calling code
+ return arg_list
+
+
def get_pngquant_path():
if sys.argv[1] == "--gui":
return "./pngquant"
elif sys.argv[1] == "--service":
return "/Applications/Crunch.app/Contents/Resources/pngquant"
else:
- return os.path.join(os.path.expanduser("~"), "pngquant", "pngquant")
+ return PNGQUANT_CLI_PATH
def get_zopflipng_path():
@@ -255,7 +284,17 @@ def get_zopflipng_path():
elif sys.argv[1] == "--service":
return "/Applications/Crunch.app/Contents/Resources/zopflipng"
else:
- return os.path.join(os.path.expanduser("~"), "zopfli", "zopflipng")
+ return ZOPFLIPNG_CLI_PATH
+
+
+def is_valid_png(filepath):
+ # The PNG byte signature (https://www.w3.org/TR/PNG/#5PNG-file-signature)
+ expected_signature = struct.pack('8B', 137, 80, 78, 71, 13, 10, 26, 10)
+ # open the file and read first 8 bytes
+ with open(filepath, 'rb') as filer:
+ signature = filer.read(8)
+ # return boolean test result for first eight bytes == expected PNG byte signature
+ return signature == expected_signature
def shellquote(filepath):
@@ -298,26 +337,7 @@ def get_compression_percent(self):
# that are split by the shell script into separate arguments
# when there are spaces in the macOS file path
if sys.argv[1] == "--gui" or sys.argv[1] == "--service":
- arg_list = []
- parsed_filepath = ""
- for arg in sys.argv[1:]:
- if arg[0] == "-":
- # add command line options
- arg_list.append(arg)
- elif arg[-4:] == ".png":
- # this is the end of a filepath string that may have had
- # spaces in directories prior to this level. Let's recreate
- # the entire original path
- filepath = parsed_filepath + arg
- arg_list.append(filepath)
- # reset the temp string that is used to reconstruct the filepaths
- parsed_filepath = ""
- else:
- # if the argument does not end with a .png, then there must have
- # been a space in the directory paths, let's add it back
- parsed_filepath = arg + " "
- # now that any space characters are appropriately escaped in the
- # original filepaths, call main function with the new arg list
+ arg_list = fix_filepath_args(sys.argv[1:])
main(arg_list)
else:
# the command line executable assumes that users will appropriately quote