diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 546b793..3b255d6 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -16,8 +16,8 @@ Steps to reproduce the behavior: **Expected behavior** A clear and concise description of what you expected to happen. -**Screenshots** -If applicable, add screenshots to help explain your problem. +**Screenshots and/or Log Text** +If applicable, add screenshots to help explain your problem. For macOS GUI and macOS right-click menu service problems, please copy and paste the text from the log file `~/.crunch/crunch.log` into your bug report (requires Crunch v3.0.0 or higher). **Desktop (please complete the following information):** - OS: [e.g. macOS] diff --git a/CHANGELOG.md b/CHANGELOG.md index c0804f6..2460d14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ ## Changelog +### v3.0.0 + +- improved quality of pngquant quantization of PNG images across all file sizes +- upgraded embedded pngquant to v2.12.0 (includes reduced pngquant optimization times) +- converted to custom build of zopflipng that is modified for use in the Crunch applications (forked from google/zopfli at git tag zopfli-1.0.2) at git version tag v2.1.0 (source repository is chrissimpkins/zopfli) +- improved zopfli compression ratios for post-quantized and non-quantized in-file sizes under 350kB. Many files are ~33% original file size after they are quantized with pngquant so this affects pre-optimization files up to just over ~1MB in size when the pngquant step is completed (the quantize step yields a modified image binary when it does not lead to larger file size or image quality below Crunch project thresholds, when this does not occur the original file at the original file size is used as the in-file to zopflipng) +- improved zopfli compression speed for post-quantized and non-quantized in-file sizes over 750kB +- eliminate optional PNG chunks by default in all files (reduces file size) +- converted to use of PNG filter = 0 for zopflipng compression of all quantized files (increases compression speed) +- use automated detection of best PNG filter for zopfli compression in all non-quantized files (improves compression) +- remove hidden colors behind alpha channel 0 in files that are not quantized due to low quality or increased file size following pngquant runs +- added new macOS GUI animations with success and fail indicators (thanks Gary Jacobs!) +- added logging of compression data and errors in macOS GUI and macOS right-click menu service tools in a new log file that is generated on the path `~/.crunch/crunch.log` +- updated redirect to /dev/null in install-dependencies.sh compile script for POSIX compliance +- refactored command line option parsing code (thanks Chris Clauss!) +- added new bug reporting template + ### v2.1.0 - added automated detection of png image types through read of PNG file signatures diff --git a/README.md b/README.md index 35423a3..57efc01 100644 --- a/README.md +++ b/README.md @@ -50,16 +50,16 @@ Select one or more PNG images in the Finder, right-click, and select the `Servic ## Examples -The following examples demonstrate the benefits and disadvantages of the current iteration of Crunch's aggressive space saving optimization strategy. In many cases, the PNG optimization minimizes file size with an imperceptible decrease in image quality. In some cases, degradation of image quality is visible. For example, view the horizon line + clouds in the prairie photo below for a demonstration of the introduction of undesirable image artifacts in the image. Experiment with the image types that you use and please submit a report with examples of any images where the image quality falls short of expectations for production-ready files. +The following examples demonstrate the benefits and disadvantages of the current iteration of Crunch's aggressive space saving optimization strategy. In many cases, the PNG optimization minimizes file size with an imperceptible decrease in image quality. In some cases, degradation of image quality is visible. View the horizon line in the prairie photo below for a demonstration of an undesirable artifact that is introduced with image processing. Experiment with the image types that you use and please submit a report with examples of any images where the image quality falls short of expectations for production-ready files. ## Photography Examples ### Cat Image - Original Size: 583,398 bytes -- Optimized Size: 195,430 bytes -- DSSIM similarity score: 0.001504 -- Percent original size: 33.50% +- Optimized Size: 196,085 bytes +- DSSIM similarity score: 0.001471 +- Percent original size: 33.61% ##### Original @@ -72,9 +72,9 @@ The following examples demonstrate the benefits and disadvantages of the current ### Sun's Rays - Original Size: 138,272 -- Optimized Size: 64,982 -- DSSIM similarity score: 0.000913 -- Percent original size: 47.00% +- Optimized Size: 66,593 +- DSSIM similarity score: 0.000948 +- Percent original size: 48.16% ##### Original @@ -88,7 +88,7 @@ The following examples demonstrate the benefits and disadvantages of the current ### Prairie Image - Original Size: 196,794 bytes -- Optimized Size: 77,968 bytes +- Optimized Size: 77,965 bytes - DSSIM similarity score: 0.002988 - Percent original size: 39.62% @@ -107,9 +107,9 @@ The following examples demonstrate the benefits and disadvantages of the current ### Robot Image - Original Size: 197,193 bytes -- Optimized Size: 67,773 bytes -- DSSIM similarity score: 0.000163 -- Percent original size: 34.37% +- Optimized Size: 67,596 bytes +- DSSIM similarity score: 0.000162 +- Percent original size: 34.28% ##### Original @@ -122,9 +122,9 @@ The following examples demonstrate the benefits and disadvantages of the current ### Color Circle Image - Original Size: 249,251 bytes -- Optimized Size: 67,326 bytes -- DSSIM similarity score: 0.002503 -- Percent original size: 27.01% +- Optimized Size: 67,135 bytes +- DSSIM similarity score: 0.002491 +- Percent original size: 26.93% ##### Original @@ -138,9 +138,9 @@ The following examples demonstrate the benefits and disadvantages of the current ### Flowers Image - Original Size: 440,126 bytes -- Optimized Size: 196,979 bytes -- DSSIM similarity score: 0.000481 -- Percent original size: 44.76% +- Optimized Size: 196,962 bytes +- DSSIM similarity score: 0.000480 +- Percent original size: 44.75% ##### Original @@ -164,7 +164,7 @@ Crunch is licensed under the [MIT license](https://github.com/chrissimpkins/Crun pngquant is licensed under the [Gnu General Public License, version 3](https://github.com/pornel/pngquant/blob/master/COPYRIGHT). The pngquant source code is available [here](https://github.com/pornel/pngquant). -zopflipng is licensed under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0). The zopflipng source code is available [here](https://github.com/google/zopfli). +zopflipng is licensed under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0). The upstream zopflipng source code is available [here](https://github.com/google/zopfli). The source for the modified zopflipng fork that is used in this project is available [here](https://github.com/chrissimpkins/zopfli). See the [LICENSE.md](LICENSE.md) document for details and additional licensing information for this project. @@ -178,3 +178,5 @@ Crunch is a simple tool that makes excellent, free, open source software built b - Lode Vandevenne, Jyrki Alakuijala, and the [zopfli project contributors](https://github.com/google/zopfli/graphs/contributors) - Kornel LesiĆski and the [pngquant project contributors](https://github.com/kornelski/pngquant/graphs/contributors) + +The fantastic macOS GUI animations were designed by [Gary Jacobs](https://github.com/garyjacobs). diff --git a/bin/Crunch.app/Contents/Info.plist b/bin/Crunch.app/Contents/Info.plist index 939b424..8777f0e 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/01-Load-Up@2x.gif b/bin/Crunch.app/Contents/Resources/01-Load-Up@2x.gif new file mode 100644 index 0000000..85ef2e2 Binary files /dev/null and b/bin/Crunch.app/Contents/Resources/01-Load-Up@2x.gif differ diff --git a/bin/Crunch.app/Contents/Resources/02-Waiting@2x.gif b/bin/Crunch.app/Contents/Resources/02-Waiting@2x.gif new file mode 100644 index 0000000..2b8da05 Binary files /dev/null and b/bin/Crunch.app/Contents/Resources/02-Waiting@2x.gif differ diff --git a/bin/Crunch.app/Contents/Resources/03-Crunching@2x.gif b/bin/Crunch.app/Contents/Resources/03-Crunching@2x.gif new file mode 100644 index 0000000..0f73546 Binary files /dev/null and b/bin/Crunch.app/Contents/Resources/03-Crunching@2x.gif differ diff --git a/bin/Crunch.app/Contents/Resources/04-Error@2x.gif b/bin/Crunch.app/Contents/Resources/04-Error@2x.gif new file mode 100644 index 0000000..78a9816 Binary files /dev/null and b/bin/Crunch.app/Contents/Resources/04-Error@2x.gif differ diff --git a/bin/Crunch.app/Contents/Resources/04-Success@2x.gif b/bin/Crunch.app/Contents/Resources/04-Success@2x.gif new file mode 100644 index 0000000..cc7d0cb Binary files /dev/null and b/bin/Crunch.app/Contents/Resources/04-Success@2x.gif differ diff --git a/bin/Crunch.app/Contents/Resources/Credits.html b/bin/Crunch.app/Contents/Resources/Credits.html index dbf82b2..9d89ddf 100644 --- a/bin/Crunch.app/Contents/Resources/Credits.html +++ b/bin/Crunch.app/Contents/Resources/Credits.html @@ -26,7 +26,7 @@
To upgrade with Homebrew, enter the following command in your terminal:
- $ brew cask uninstall crunch && brew cask install crunch
+ $ brew cask upgrade
The Crunch GUI animations were designed by + Gary Jacobs and are licensed under the MIT License.
\ No newline at end of file diff --git a/bin/Crunch.app/Contents/Resources/clear.html b/bin/Crunch.app/Contents/Resources/clear.html index 3e0651f..fb80407 100644 --- a/bin/Crunch.app/Contents/Resources/clear.html +++ b/bin/Crunch.app/Contents/Resources/clear.html @@ -9,6 +9,7 @@ body, html { overflow: hidden; + background-color: #424242; } .clear { diff --git a/bin/Crunch.app/Contents/Resources/complete.html b/bin/Crunch.app/Contents/Resources/complete-error.html similarity index 74% rename from bin/Crunch.app/Contents/Resources/complete.html rename to bin/Crunch.app/Contents/Resources/complete-error.html index 906d4fd..a6a7c1c 100644 --- a/bin/Crunch.app/Contents/Resources/complete.html +++ b/bin/Crunch.app/Contents/Resources/complete-error.html @@ -9,18 +9,13 @@ body, html { overflow: hidden; - background-color: #FFF; + background-color: #424242; } .frame { - height: 200px; white-space: nowrap; text-align: center; } - - img { - margin-top: 50px; - } @@ -28,7 +23,7 @@diff --git a/html/complete.html b/bin/Crunch.app/Contents/Resources/complete-success.html similarity index 74% rename from html/complete.html rename to bin/Crunch.app/Contents/Resources/complete-success.html index 906d4fd..6f2643d 100644 --- a/html/complete.html +++ b/bin/Crunch.app/Contents/Resources/complete-success.html @@ -9,18 +9,13 @@ body, html { overflow: hidden; - background-color: #FFF; + background-color: #424242; } .frame { - height: 200px; white-space: nowrap; text-align: center; } - - img { - margin-top: 50px; - } @@ -28,7 +23,7 @@
diff --git a/bin/Crunch.app/Contents/Resources/crunch.py b/bin/Crunch.app/Contents/Resources/crunch.py index 54cf372..31a74fa 100755 --- a/bin/Crunch.app/Contents/Resources/crunch.py +++ b/bin/Crunch.app/Contents/Resources/crunch.py @@ -16,12 +16,14 @@ import shutil import struct import subprocess +import time from subprocess import CalledProcessError from multiprocessing import Lock, Pool, cpu_count # Locks -lock = Lock() +stdstream_lock = Lock() +logging_lock = Lock() # Processor Constant # - Modify this to an integer value if you want to fix the number of @@ -36,8 +38,14 @@ PNGQUANT_CLI_PATH = os.path.join(os.path.expanduser("~"), "pngquant", "pngquant") ZOPFLIPNG_CLI_PATH = os.path.join(os.path.expanduser("~"), "zopfli", "zopflipng") +# Crunch Directory (dot directory in $HOME) +CRUNCH_DOT_DIRECTORY = os.path.join(os.path.expanduser("~"), ".crunch") + +# Log File Path Constants +LOGFILE_PATH = os.path.join(CRUNCH_DOT_DIRECTORY, "crunch.log") + # Application Constants -VERSION = "2.1.0" +VERSION = "3.0.0" VERSION_STRING = "crunch v" + VERSION HELP_STRING = """ @@ -62,6 +70,15 @@ USAGE = "$ crunch [image path 1]...[image path n]" +# Create the Crunch dot directory in $HOME if it does not exist +# Only used for macOS GUI and macOS right-click menu service execution +if sys.argv[1] in ("--gui", "--service"): + if not os.path.isdir(CRUNCH_DOT_DIRECTORY): + os.makedirs(CRUNCH_DOT_DIRECTORY) + # clear the text in the log file before every script execution + # logging is only maintained for the last execution of the script + open(LOGFILE_PATH, "w").close() + def main(argv): @@ -80,10 +97,10 @@ def main(argv): # HELP, USAGE, VERSION option handling # ////////////////////////////////////// - if argv[0] == "-v" or argv[0] == "--version": + if argv[0] in ("-v", "--version"): print(VERSION_STRING) sys.exit(0) - elif argv[0] == "-h" or argv[0] == "--help": + elif argv[0] in ("-h", "--help"): print(HELP_STRING) sys.exit(0) elif argv[0] == "--usage": @@ -100,7 +117,7 @@ def main(argv): # PARSE PNG_PATH_LIST # //////////////////// - if argv[0] == "--gui" or argv[0] == "--service": + if is_gui(argv): png_path_list = argv[1:] else: png_path_list = argv @@ -109,20 +126,25 @@ def main(argv): # COMMAND LINE ERROR HANDLING # ////////////////////////////////// + NOTPNG_ERROR_FOUND = False 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] '" - + png_path - + "' does not appear to be a valid path to a PNG file" - + os.linesep - ) - sys.exit(1) + sys.stderr.write("[ERROR] '" + png_path + "' does not appear to be a valid path to a PNG file" + os.linesep) + sys.exit(1) # not a file, abort immediately # 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) + if is_gui(argv): + log_error(png_path + " is not a valid PNG file.") + NOTPNG_ERROR_FOUND = True + + # Exit after checking all file requests and reporting on all invalid file paths (above) + if NOTPNG_ERROR_FOUND is True: + sys.stderr.write("The request was not executed successfully. Please try again with one or more valid PNG files." + os.linesep) + if is_gui(argv): + log_error("The request was not executed successfully. Please try again with one or more valid PNG files.") + sys.exit(1) # Dependency error handling if not os.path.exists(PNGQUANT_EXE_PATH): @@ -132,6 +154,8 @@ def main(argv): + "'" + os.linesep ) + if is_gui(argv): + log_error("pngquant was not found on the expected path " + PNGQUANT_EXE_PATH) sys.exit(1) elif not os.path.exists(ZOPFLIPNG_EXE_PATH): sys.stderr.write( @@ -140,6 +164,8 @@ def main(argv): + "'" + os.linesep ) + if is_gui(argv): + log_error("zopflipng was not found on the expected path " + ZOPFLIPNG_EXE_PATH) sys.exit(1) # //////////////////////////////////// @@ -150,7 +176,6 @@ def main(argv): if len(png_path_list) == 1: # there is only one PNG file, skip spawning of processes and just optimize it optimize_png(png_path_list[0]) - sys.exit(0) else: processes = PROCESSES # if not defined by user, start by defining spawned processes as number of available cores @@ -166,13 +191,19 @@ def main(argv): try: p.map(optimize_png, png_path_list) except Exception as e: - lock.acquire() + stdstream_lock.acquire() sys.stderr.write("-----" + os.linesep) sys.stderr.write("[ERROR] Error detected during execution of the request." + os.linesep) sys.stderr.write(str(e) + os.linesep) - lock.release() + stdstream_lock.release() + if is_gui(argv): + log_error(str(e)) sys.exit(1) - sys.exit(0) + + # end of successful processing, exit code 0 + if is_gui(argv): + log_info("Crunch execution ended.") + sys.exit(0) # /////////////////////// @@ -189,9 +220,9 @@ def optimize_png(png_path): # -------------- # pngquant stage # -------------- + pngquant_options = " --quality=80-98 --skip-if-larger --force --strip --speed 1 --ext -crunch.png " + pngquant_command = PNGQUANT_EXE_PATH + pngquant_options + shellquote(img.pre_filepath) try: - pngquant_options = " --quality=80-98 --skip-if-larger --force --ext -crunch.png " - pngquant_command = PNGQUANT_EXE_PATH + pngquant_options + shellquote(img.pre_filepath) subprocess.check_output(pngquant_command, stderr=subprocess.STDOUT, shell=True) except CalledProcessError as cpe: if cpe.returncode == 98: @@ -205,45 +236,67 @@ def optimize_png(png_path): # below if it is not present to these errors pass else: - lock.acquire() + stdstream_lock.acquire() sys.stderr.write("[ERROR] " + img.pre_filepath + " processing failed at the pngquant stage." + os.linesep) - lock.release() - if sys.argv[1] == "--gui" or sys.argv[1] == "--service": + stdstream_lock.release() + if is_gui(sys.argv): + log_error(img.pre_filepath + " processing failed at the pngquant stage. " + os.linesep + str(cpe)) return None else: raise cpe except Exception as e: - raise e + if is_gui(sys.argv): + log_error(img.pre_filepath + " processing failed at the pngquant stage. " + os.linesep + str(e)) + return None + else: + raise e # --------------- # zopflipng stage # --------------- - - # confirm that a file with proper path was generated above (occurs with larger files following pngquant) + # use --filters=0 by default for quantized PNG files (based upon testing by CS) + zopflipng_options = " -y --filters=0 " + # confirm that a file with proper path was generated by pngquant + # pngquant does not write expected file path if the file was larger after processing if not os.path.exists(img.post_filepath): shutil.copy(img.pre_filepath, img.post_filepath) + # If pngquant did not quantize the file, permit zopflipng to attempt compression with mulitple + # filters. This achieves better compression than the default approach for non-quantized PNG + # files, but takes significantly longer (based upon testing by CS) + zopflipng_options = " -y --lossy_transparent " + zopflipng_command = ZOPFLIPNG_EXE_PATH + zopflipng_options + shellquote(img.post_filepath) + " " + shellquote(img.post_filepath) try: - zopflipng_options = " -y " - zopflipng_command = ZOPFLIPNG_EXE_PATH + zopflipng_options + shellquote(img.post_filepath) + " " + shellquote(img.post_filepath) subprocess.check_output(zopflipng_command, stderr=subprocess.STDOUT, shell=True) except CalledProcessError as cpe: - lock.acquire() + stdstream_lock.acquire() sys.stderr.write("[ERROR] " + img.pre_filepath + " processing failed at the zopflipng stage." + os.linesep) - lock.release() - if sys.argv[1] == "--gui" or sys.argv[1] == "--service": + stdstream_lock.release() + if is_gui(sys.argv): + log_error(img.pre_filepath + " processing failed at the zopflipng stage. " + os.linesep + str(cpe)) return None else: raise cpe except Exception as e: - raise e + if is_gui(sys.argv): + log_error(img.pre_filepath + " processing failed at the pngquant stage. " + os.linesep + str(e)) + return None + else: + raise e + # Check file size post-optimization and report comparison with pre-optimization file img.get_post_filesize() percent = img.get_compression_percent() percent_string = '{0:.2f}'.format(percent) - lock.acquire() + # report percent original file size / post file path / size (bytes) to stdout (command line executable) + stdstream_lock.acquire() print("[ " + percent_string + "% ] " + img.post_filepath + " (" + str(img.post_size) + " bytes)") - lock.release() + stdstream_lock.release() + + # report percent original file size / post file path / size (bytes) to stdout (macOS GUI + right-click service) + if is_gui(sys.argv): + log_info("[ " + percent_string + "% ] " + + img.post_filepath + " (" + str(img.post_size) + " bytes)") def fix_filepath_args(args): @@ -253,7 +306,8 @@ def fix_filepath_args(args): if arg[0] == "-": # add command line options arg_list.append(arg) - elif len(arg) > 4 and arg[-4:] == ".png": + elif len(arg) > 2 and "." in arg[1:]: + # if format is `\w+\.\w+`, then this is a filename, not directory # 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 @@ -287,6 +341,10 @@ def get_zopflipng_path(): return ZOPFLIPNG_CLI_PATH +def is_gui(arglist): + return ("--gui" in arglist or "--service" in arglist) + + 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) @@ -297,6 +355,27 @@ def is_valid_png(filepath): return signature == expected_signature +def log_error(errmsg): + current_time = time.strftime("%m-%d-%y %H:%M:%S") + logging_lock.acquire() + with open(LOGFILE_PATH, 'a') as filewriter: + filewriter.write(current_time + "\tERROR\t" + errmsg + os.linesep) + filewriter.flush() + os.fsync(filewriter.fileno()) + logging_lock.release() + + +def log_info(infomsg): + current_time = time.strftime("%m-%d-%y %H:%M:%S") + logging_lock.acquire() + with open(LOGFILE_PATH, 'a') as filewriter: + filewriter.write(current_time + "\tINFO\t" + infomsg + os.linesep) + filewriter.flush() + os.fsync(filewriter.fileno()) + logging_lock.release() + return None + + def shellquote(filepath): return "'" + filepath.replace("'", "'\\''") + "'" @@ -336,7 +415,7 @@ def get_compression_percent(self): # This workaround reconstructs the original filepaths # 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": + if sys.argv[1] in ("--gui", "--service"): arg_list = fix_filepath_args(sys.argv[1:]) main(arg_list) else: diff --git a/bin/Crunch.app/Contents/Resources/execution.html b/bin/Crunch.app/Contents/Resources/execution.html index 718d27b..bc7a2aa 100644 --- a/bin/Crunch.app/Contents/Resources/execution.html +++ b/bin/Crunch.app/Contents/Resources/execution.html @@ -9,18 +9,13 @@ body, html { overflow: hidden; - background-color: #FFF; + background-color: #424242; } .frame { - height: 200px; white-space: nowrap; text-align: center; } - - img { - margin-top: 50px; - } @@ -28,7 +23,7 @@
diff --git a/bin/Crunch.app/Contents/Resources/fastdots.gif b/bin/Crunch.app/Contents/Resources/fastdots.gif deleted file mode 100644 index 28c6096..0000000 Binary files a/bin/Crunch.app/Contents/Resources/fastdots.gif and /dev/null differ diff --git a/bin/Crunch.app/Contents/Resources/pngquant b/bin/Crunch.app/Contents/Resources/pngquant index cb81892..d8db8d2 100755 Binary files a/bin/Crunch.app/Contents/Resources/pngquant and b/bin/Crunch.app/Contents/Resources/pngquant differ diff --git a/bin/Crunch.app/Contents/Resources/script b/bin/Crunch.app/Contents/Resources/script index 64d0956..59687c3 100755 --- a/bin/Crunch.app/Contents/Resources/script +++ b/bin/Crunch.app/Contents/Resources/script @@ -17,14 +17,29 @@ # Message on application open (no arguments passed to script on initial open) if [ $# -eq 0 ]; then - cat start.html + cat waiting.html exit 0 fi cat execution.html -./crunch.py --gui "$@" >/dev/null - -cat clear.html -cat complete.html -exit 0 +if ./crunch.py --gui "$@" >/dev/null 2>&1; then + cat clear.html + cat complete-success.html + sleep 2 + cat clear.html + cat start.html + sleep 0.8 + cat waiting.html + exit 0 +else + sleep 0.6 + cat clear.html + cat complete-error.html + sleep 2 + cat clear.html + cat start.html + sleep 0.8 + cat waiting.html + exit 1 +fi diff --git a/bin/Crunch.app/Contents/Resources/slowdots.gif b/bin/Crunch.app/Contents/Resources/slowdots.gif deleted file mode 100644 index fbb3a67..0000000 Binary files a/bin/Crunch.app/Contents/Resources/slowdots.gif and /dev/null differ diff --git a/bin/Crunch.app/Contents/Resources/start.html b/bin/Crunch.app/Contents/Resources/start.html index 661cd37..8582f5f 100644 --- a/bin/Crunch.app/Contents/Resources/start.html +++ b/bin/Crunch.app/Contents/Resources/start.html @@ -4,30 +4,24 @@
-
diff --git a/bin/Crunch.app/Contents/Resources/waiting.html b/bin/Crunch.app/Contents/Resources/waiting.html new file mode 100644 index 0000000..b5c6221 --- /dev/null +++ b/bin/Crunch.app/Contents/Resources/waiting.html @@ -0,0 +1,27 @@ + + + +
+ +
+ + + +
+ +