From b06ad52d6b45016affc3c67371614bb4a7a474b3 Mon Sep 17 00:00:00 2001 From: Will Gallego Date: Fri, 5 Aug 2016 15:10:03 +0000 Subject: [PATCH 1/2] moving original to compare with outside of loop We're computing the original image png base64 on every iteration of the loop, which is pretty wasteful. In the worst case scenario here, we never do any loops in the while and we calculate the original image png base64 unnecessarily, but that should be a rare enough scenario where this optimization is preferred --- cjpeg-dssim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cjpeg-dssim b/cjpeg-dssim index 4cf71be..1782fd4 100755 --- a/cjpeg-dssim +++ b/cjpeg-dssim @@ -108,6 +108,9 @@ function optimize_quality_level () { local -i __current_jpeg_quality_summand_subtrahend=$2 local -i __iteration_counter="0" local __current_dssim_score="0" + # Convert the original JPEG to PNG for DSSIM comparison + # Also base64 it so we can safely store its result in a variable without needing to write the file to disk + __original_image_png_base64=$(convert "${INPUTFILE}" png:- | base64) # While the result of the current run is either too similar (ecouraging stronger compression) or too different (already too many artifacts visible), run the compression again while homing in on a proper quality setting for the current encoder while ( (( $(echo "${__current_dssim_score} >= ${DSSIM_UPPER_BOUND}" | bc -l) )) || (( $(echo "${__current_dssim_score} < ${DSSIM_LOWER_BOUND}" | bc -l) )) ) && (( ${__iteration_counter}<7 )); do # Retrieve the current dissimilarity score @@ -132,12 +135,9 @@ function optimize_quality_level () { function calculate_dissimilarity () { local __current_jpeg_quality=$1 - # Convert the original JPEG to PNG for DSSIM comparison - # Also base64 it so we can safely store its result in a variable without needing to write the file to disk - local __original_image_png_base64=$(convert "${INPUTFILE}" png:- | base64) # Run the JPEG compressor, pipe its output to convert, create a PNG from the newly compressed JPEG and hand it to DSSIM for comparison - all without creating a file on disk to increase runtime performance local __current_dissimilarity=$(eval ${JPEG_COMPRESSION_COMMAND} | convert - png:- | dssim <(echo "${__original_image_png_base64}" | base64 --decode) /dev/stdin | awk '{print $1}') echo ${__current_dissimilarity} } -main \ No newline at end of file +main From 9fdc9c67de8a8f5c210fcab62142312f873ef520 Mon Sep 17 00:00:00 2001 From: Will Gallego Date: Fri, 5 Aug 2016 21:25:20 +0000 Subject: [PATCH 2/2] option added to allow use of GraphicsMagick for png conversion By default, it will still use ImageMagick (convert command) for conversion from jpeg -> png. Supplying imagick as the third param will also do this. Using gmagick, though, will use GraphicsMagick tool for this conversion --- cjpeg-dssim | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/cjpeg-dssim b/cjpeg-dssim index 1782fd4..7976e30 100755 --- a/cjpeg-dssim +++ b/cjpeg-dssim @@ -14,6 +14,7 @@ # # Required tools: # * ImageMagick >= v.6 +# * GraphicsMagick (alternative to ImageMagick) # * dssim - https://github.com/pornel/dssim # * jpegoptim - https://github.com/tjko/jpegoptim # * mozjpeg - https://github.com/mozilla/mozjpeg @@ -47,6 +48,8 @@ else exit 1 fi +IMAGE_PROCESSOR="$3" + # Path and filename retrieval to save the output image CLEANFILENAME=${INPUTFILE%.jp*g} FILEEXTENSION=${INPUTFILE##*.} @@ -84,6 +87,7 @@ OUTPUTFILESUFFIX="_cjpeg_dssim" main () { define_encoder_toolbelt + define_conversion_tool local -i __current_jpeg_quality=$(optimize_quality_level ${INITIAL_JPEG_QUALITY} ${JPEG_QUALITY_SUMMAND_SUBTRAHEND}) $(eval ${JPEG_COMPRESSION_COMMAND} > "${CLEANPATH}${CLEANFILENAME##*/}${OUTPUTFILESUFFIX}".${FILEEXTENSION}); } @@ -103,6 +107,16 @@ function define_encoder_toolbelt () { esac } +function define_conversion_tool () { + # Define conversion tool + case ${IMAGE_PROCESSOR} in + "gmagick") CONVERSION_COMMAND="gm convert";; + "imagick") ;& + "") CONVERSION_COMMAND="convert";; + *) echo "Supported JPEG conversion methods: imagick | gmagick"; exit 1;; + esac +} + function optimize_quality_level () { local -i __current_jpeg_quality=$1 local -i __current_jpeg_quality_summand_subtrahend=$2 @@ -110,7 +124,7 @@ function optimize_quality_level () { local __current_dssim_score="0" # Convert the original JPEG to PNG for DSSIM comparison # Also base64 it so we can safely store its result in a variable without needing to write the file to disk - __original_image_png_base64=$(convert "${INPUTFILE}" png:- | base64) + __original_image_png_base64=$(${CONVERSION_COMMAND} "${INPUTFILE}" png:- | base64) # While the result of the current run is either too similar (ecouraging stronger compression) or too different (already too many artifacts visible), run the compression again while homing in on a proper quality setting for the current encoder while ( (( $(echo "${__current_dssim_score} >= ${DSSIM_UPPER_BOUND}" | bc -l) )) || (( $(echo "${__current_dssim_score} < ${DSSIM_LOWER_BOUND}" | bc -l) )) ) && (( ${__iteration_counter}<7 )); do # Retrieve the current dissimilarity score @@ -136,7 +150,7 @@ function optimize_quality_level () { function calculate_dissimilarity () { local __current_jpeg_quality=$1 # Run the JPEG compressor, pipe its output to convert, create a PNG from the newly compressed JPEG and hand it to DSSIM for comparison - all without creating a file on disk to increase runtime performance - local __current_dissimilarity=$(eval ${JPEG_COMPRESSION_COMMAND} | convert - png:- | dssim <(echo "${__original_image_png_base64}" | base64 --decode) /dev/stdin | awk '{print $1}') + local __current_dissimilarity=$(eval ${JPEG_COMPRESSION_COMMAND} | ${CONVERSION_COMMAND} - png:- | dssim <(echo "${__original_image_png_base64}" | base64 --decode) /dev/stdin | awk '{print $1}') echo ${__current_dissimilarity} }