dewwwald
5/13/2012 - 10:11 PM

A bash/ImageMagick script to recolor transparent .png files

A bash/ImageMagick script to recolor transparent .png files

#!/bin/bash

# A small script to change the color of mono-colored transparent .pngs
#
# Uses ImageMagick to read the most common 100% alpha color and then computes
# scale factors to multiply the whole image by. 
#
# Improvements to be made:
#   -deal with images containing pure black.
#   -make portable between new and old ImageMagick versions

#########################################################
#                                                       #
#                   input validation                    #
#                                                       #
#########################################################

# make sure all command line arguments are actually given
if [ -z $1 ] || [ -z $2 ] || [ -z $2 ]
then 
   echo "Usage: $0 <color> <input file> <output file>"
   exit 0
fi

# make sure the input file is a real file
if [ ! -e $2 ]
then
   echo "Input file '$2' does not exist"
   exit 0
fi

# make sure the input file can be read by us
if [ ! -r $2 ]
then
   echo "Input file '$2' cannot be opened for reading"
   exit 0
fi

# if the output file exists, make sure that we can write to it
if [ -e $3 ]
then
   if [ ! -w $3 ]
   then
      echo "Output file '$3' cannot be opened for writing"
      exit 0
   fi
fi

newcolor=$1
infile=$2
outfile=$3

#########################################################
#                                                       #
#                 Normalize colors                      #
#                                                       #
#########################################################

if   [[ "$newcolor" =~ 0x[0-9A-Fa-f]{6} ]]
then
   # The color was given in a hex format, expand it to an array and convert to decimal
   newcolors=($(sed 's/0x\(..\)\(..\)\(..\)/\1 \2 \3/' <<< "$newcolor"))
   newcolors[0]=$(echo "ibase=16;obase=A;${newcolors[0]}" | bc)
   newcolors[1]=$(echo "ibase=16;obase=A;${newcolors[1]}" | bc)
   newcolors[2]=$(echo "ibase=16;obase=A;${newcolors[2]}" | bc)
   # TODO - debugging, delete
   echo "Color entered in hex, components are: R:${newcolors[0]}, G:${newcolors[1]}, B:${newcolors[2]}"
elif [[ "$newcolor" =~ [0-9]{1,3},[0-9]{1,3},[0-9]{1,3} ]]
then
   # Color was entered in decimal, just convert to array
   newcolor=($(sed 's/\(.\{1,3\}\),\(.\{1,3\}\),\(.\{1,3\}\)/\1 \2 \3/' <<< "$newcolor"))
   # TODO - debugging, delete
   echo "Color entered in hex, components are: R:${newcolors[0]}, G:${newcolors[1]}, B:${newcolors[2]}"
else
   echo "Color is in an unknown format. Valid formats are hex: '0xNNNNNN' and dec: 'n,n,n'"
   exit 0
fi

#      Sample output from convert -colors command
#
# 601: (109,110,113,255) #6D6E71 rgba(109,110,113,1)
# .... more lines of the same

# Get the primary color in this .png
colors=($(convert $infile -colors 16 -depth 8 -format "%c" histogram:info: \
| sed -n 's/^.*(\([ 0-9]\{2\}[0-9]\),\([ 0-9]\{2\}[0-9]\),\([ 0-9]\{2\}[0-9]\),255).*$/\1 \2 \3/ p' \
| head -n1))

# Compute the scale factors to obtain the new colors from the old by multiplying
conversion[0]=$(echo "${newcolors[0]} / ${colors[0]}" | bc -l )
conversion[1]=$(echo "${newcolors[1]} / ${colors[1]}" | bc -l )
conversion[2]=$(echo "${newcolors[2]} / ${colors[2]}" | bc -l )

# TODO - debug, delete
echo "R: ${colors[0]} => ${newcolors[0]} (${conversion[0]})"
echo "G: ${colors[1]} => ${newcolors[1]} (${conversion[1]})"
echo "B: ${colors[2]} => ${newcolors[2]} (${conversion[2]})"


# TODO - Make portable between old and new versions of ImageMagick - This just requires checking the version
# and using either -recolor (old) or -color-matrix (new)
convert -recolor \
   " ${conversion[0]}, 0, 0, 0, 0,   \
     0, ${conversion[1]}, 0, 0, 0,   \
     0, 0, ${conversion[2]}, 0, 0,   \
     0, 0, 0, 1, 0,   \
     0, 0, 0, 0, 1"   \
     $infile $outfile