pattulus
4/29/2016 - 8:20 PM

jpeg-archive-replace.sh

#!/bin/sh

# requires jpeg-recompress <https://github.com/danielgtaylor/jpeg-archive>

# same as jpeg-archive, but:
# * without 3rd-party dependencies
# * can re-compress a single file as well as a directory
# * replaces original with optimized version (keeping file timestamps)
# * no support for RAW images

# Copyright 2015 Cédrik LIME



help()
{
	echo 'JPEG-Archive-Replace - Compress an replace a single JPEG image, or a directory of JPEG images'
	echo "Usage: `basename $0` [file|dir] [options]"
	echo 'Warning: [file|dir] *must* be first argument; expect the unexpected if you dare try to put options first!'
	echo ''
	echo 'Possible compression options:'
	echo "`jpeg-recompress --help | tail -n+6`"
}

# number of parallel re-compression processes to use
PARALLELISM=1

get_ncpu()
{

	OS_NAME="$(uname)"
	# Use hyperthreading?
	HT="$1"
	CORES=""

	if [ -z "$HT" ]; then
		HT="no"
	fi

	if [ "$HT" = "yes" ]; then

		if [ "$OS_NAME" = "Linux" ]; then
			CORES=$(grep -c '^processor' /proc/cpuinfo)
		elif [ "$OS_NAME" = "Darwin" ]; then
			CORES=$(sysctl -n hw.logicalcpu)
		elif [ "$OS_NAME" = "FreeBSD" ];  then
			CORES=$(sysctl -n hw.ncpu)
		elif [ "$OS_NAME" = "SunOS" ]; then
			CORES=$(psrinfo | grep -c 'on-line')
		elif [ -e /proc/cpuinfo ]; then
			CORES=$(grep -c '^processor' /proc/cpuinfo)
		fi

	elif [ "$HT" = "no" ]; then

		if [ "$OS_NAME" = "Linux" ]; then
			if grep -q 'physical id' /proc/cpuinfo; then
				PHYSICAL=$(grep 'physical id' /proc/cpuinfo | sort -u | wc -l)
				# $PHYSICAL physical CPUs
				if grep -q 'core id' /proc/cpuinfo; then
					# Computing the total number of physical core(s):
					# physical processor(s) * physical core(s) per CPU
					# (assuming all installed CPUs have the same number of cores)
					CORES="$(expr $PHYSICAL '*' `grep 'core id' /proc/cpuinfo | sort -u | wc -l`)"
					# $CORES physical cores
				else
					# Single core processor(s)
					CORES=$PHYSICAL
				fi
			else
				# No 'physical id' section found in /proc/cpuinfo, typical for older or "exotic" (e.g. ARM) cpus
				CORES=$(grep -c '^processor' /proc/cpuinfo)
			fi
		elif [ "$OS_NAME" = "Darwin" ]; then
			CORES=$(sysctl -n hw.physicalcpu)
		elif [ "$OS_NAME" = "FreeBSD" ]; then
			CORES=$(sysctl -n hw.ncpu)
		elif [ "$OS_NAME" = "SunOS" ]; then
			CORES=$(psrinfo | grep -c 'on-line')
		elif [ -e /proc/cpuinfo ]; then
			CORES=$(grep 'cpu cores' /proc/cpuinfo | cut -d ":" -f 2 | uniq | sed -e 's/\ //g')
		fi 

	fi

	if [ -z "$CORES" -o "$CORES" -eq "0" ]; then
		# fallback
		CORES=1
	fi

	#echo $CORES
	PARALLELISM=$CORES
}



if [ "$1" = "" -o "$1" = "--help" ]; then
	help
	exit 0
fi

if [ "$1" = "--version" ]; then
	jpeg-recompress --version
	exit 0
fi


if [ -f "$1" -o -d "$1" ]; then
	# 1st param is a file or a directory: it is not a jpeg-recompress option
	ORIGINAL_JPG="$1"
	shift
else
	help
	exit 1
fi


if [ -d "${ORIGINAL_JPG}" ]; then

	# directory: optimize JPEG images inside

	get_ncpu
	echo "Recompressing JPEG files in \"${ORIGINAL_JPG}\" (using ${PARALLELISM} threads)"
	find "${ORIGINAL_JPG}" -type f -iname '*.jpg' -print0 | xargs -0 -P${PARALLELISM} -I{} -n1 "$0" "{}" $@
	echo 'Done!'

elif [ -s "${ORIGINAL_JPG}" ]; then

	# single file
	# We could simply jpeg-recompress "${ORIGINAL_JPG}" "${ORIGINAL_JPG}", but we would lose file meta-data

	# TODO: place temp file in /dev/shm for speed
	TMP_FILE=`mktemp -t jpeg-recompress.XXXXX.jpg` || exit 1

# FIXME this should be enough (and no need for /dev/shm anymore):
#	touch -r "${ORIGINAL_JPG}" "${TMP_FILE}"
#	jpeg-recompress ${@:--Q -c -q high --accurate} "${ORIGINAL_JPG}" "${ORIGINAL_JPG}"
#	touch -r "${TMP_FILE}" "${ORIGINAL_JPG}"
#	rm "${TMP_FILE}"

	jpeg-recompress ${@:--Q -c -q high --accurate} "${ORIGINAL_JPG}" "${TMP_FILE}"

	if [ -s "${TMP_FILE}" ]; then
		# move optimized image in place of original
		touch -r "${ORIGINAL_JPG}" "${TMP_FILE}"
		if [ "$(uname)" = "Linux" ]; then
			# Linux-only
			chmod --reference="${ORIGINAL_JPG}" "${TMP_FILE}"
			chown --reference="${ORIGINAL_JPG}" "${TMP_FILE}"
		elif [ "$(uname)" = "Darwin" -o "$(uname)" = "FreeBSD" ]; then
			# BSD-only (Linux stat has slightly different syntax):
			chmod $( stat -f '%Lp' "${ORIGINAL_JPG}" ) "${TMP_FILE}"
			chown $( stat -f '%u:%g' "${ORIGINAL_JPG}" ) "${TMP_FILE}"
		fi
		mv "${TMP_FILE}" "${ORIGINAL_JPG}"
	else
		# don't leave empty temporary files lying around
		rm "${TMP_FILE}"
	fi

else

	echo "Can not process ${ORIGINAL_JPG}"

fi