Last active
February 14, 2024 03:18
-
-
Save triplingual/a5aa4f15d8d255cbfd3f574d67f756bc to your computer and use it in GitHub Desktop.
Script to transform Apple iTunes' .itc files into images (JPG or PNG)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Script to transform Apple iTunes' .itc files into images (JPG or PNG) | |
# | |
# This is a mod of the very useful script by Matthieu Riegler (@kyro38) at | |
# https://github.com/kyro38/MiscStuff/blob/master/Useless/itc/itcToImageV2.sh | |
# | |
# The mods are | |
# * to use `find` rather than `gfind` (I'm on a Mac and find` works just fine | |
# and I don't need to install `coreutils` just for this task) | |
# * to parameterize the source and destination directories for the .itc files | |
# * to add some communication with the user | |
# * to count the ITC files being processed in order to get a confirmation from the user | |
# | |
# My iTunes folder is usually nonstandard, I want to be able to run this on Album Artwork | |
# folders copied from others' machines (who don't want me hogging their machine for this | |
# effort), and I'm not consistent on my own machines whether I use the standard directory | |
# structure for iTunes. | |
# | |
# .itc files may be located in ~/Music/iTunes/Album Artwork unless you, like I, | |
# have customized iTunes' directory | |
# | |
# This script uses (/!\ needs ) ImageMagick's convert, hexdump, printf and dd. | |
# | |
# "Newer" (>2012?) iTunes ITC files may contain ARGB content, with as many as 3 sizes | |
# of the same image in one ITC file. Because of that, and depending on the size | |
# of your artwork directory, this script might be a little slow. One alternative | |
# is Simon Kennedy's Python module: http://www.sffjunkie.co.uk/python-itc.html | |
# | |
# Have a nice day. | |
# Test for inputs, use defaults if absent | |
if [ -z $1 ]; then | |
# absent any parameters, use defaults | |
AlbumArtwork="${HOME}/Music/iTunes/Album Artwork" | |
DestinationDir="$AlbumArtwork/Images" | |
echo | |
echo "Using default directories:" | |
echo " Source: " $AlbumArtwork | |
echo " Destination:" $DestinationDir | |
else | |
# Source dir | |
AlbumArtwork=$1 | |
# Destination dir | |
DestinationDir=$2 | |
echo | |
echo "Using these directories:" | |
echo " Source: " $AlbumArtwork | |
echo " Destination:" $DestinationDir | |
echo | |
fi | |
# Get count of ITC files for notice to script executor | |
FileCount=`find "$AlbumArtwork" -name '*.itc' | wc -l` | |
read -r -p "About to extract all art from | |
$AlbumArtwork | |
to | |
$DestinationDir. | |
There are $FileCount .itc files to be processed. | |
Continue (y/n)? " choice | |
case "$choice" in | |
y|Y ) | |
echo "OK! Here we go." | |
;; | |
n|N ) | |
echo "Abandoning script." | |
exit 1 | |
;; | |
* ) | |
echo "Invalid response, exiting." | |
exit 1 | |
;; | |
esac | |
IFS=$'\n' | |
if [ ! -d "$DestinationDir" ]; then | |
mkdir "$DestinationDir" | |
echo "new Images dir" | |
fi | |
for file in `find "$AlbumArtwork" -name '*.itc'`; do | |
start=0x11C | |
exit=0; | |
i=1; | |
echo $file | |
while [ 1 ]; do | |
typeOffset=$(($start+0x30)) | |
imageType=$(hexdump -n 4 -s $typeOffset -e '"0x"4/1 "%02x" "\n"' $file) | |
#If there is no next byte, jump to the next itc file. | |
if [[ -z $imageType ]]; then | |
break | |
fi | |
imageOffsetOffset=$(($start+8)) | |
itemSize=$(hexdump -n 4 -s $start -e '"0x"4/1 "%02x" "\n"' $file) | |
imageOffset=$(hexdump -n 4 -s $imageOffsetOffset -e '"0x"4/1 "%02x" "\n"' $file) | |
imageStart=$(($start+$imageOffset)) | |
imageSize=$(($itemSize-imageOffset)) | |
imageWidth=$(hexdump -n 4 -s $(($start+56)) -e '"0x"4/1 "%02x" "\n"' $file) | |
imageWidth=$(printf "%d" $imageWidth) | |
imageHeight=$(hexdump -n 4 -s $(($start+60)) -e '"0x"4/1 "%02x" "\n"' $file) | |
imageHeight=$(printf "%d" $imageHeight) | |
dir=$(dirname "$file") | |
xbase=${file##*/} #file.etc | |
xpref=${xbase%.*} #file prefix | |
#echo $file | |
#echo itemsize $itemSize | |
#echo start $start | |
#echo imageOffset $imageOffset | |
#echo imageStart $imageStart | |
#echo imageSize $imageSize | |
#echo imageWidth $imageWidth | |
#echo imageHeight $imageHeight | |
if [[ $imageType -eq 0x504E4766 ]] || [[ $imageType -eq 0x0000000E ]] ; then | |
targetFile="$DestinationDir/$xpref-$i.png" | |
if [ ! -f "$targetFile" ]; then | |
echo PNG | |
dd skip=$imageStart count=$imageSize if="$file" of="$targetFile" bs=1 &> /dev/null | |
fi | |
elif [[ $imageType -eq 0x41524762 ]] ; then | |
targetFile="$DestinationDir/$xpref-$i.png" | |
if [ ! -f "$targetFile" ]; then | |
echo ARGB | |
dd skip=$imageStart count=$imageSize if="$file" of="$TMPDIR/test$i" bs=1 &> /dev/null | |
#Using a matrix to convert ARGB to RGBA since imagemagick does only support rgba input | |
convert -size $imageWidth"x"$imageHeight -depth 8 -color-matrix '0 1 0 0 0 0 1 0 0 0 0 1 1 0 0 0' rgba:"$TMPDIR/test$i" "$targetFile" | |
fi | |
elif [[ $imageType -eq 0x0000000D ]] ; then | |
targetFile="$DestinationDir/$xpref-$i.jpg" | |
if [ ! -f "$targetFile" ]; then | |
echo JPG | |
dd skip=$imageStart count=$imageSize if="$file" of="$targetFile" bs=1 &> /dev/null | |
fi | |
else | |
echo $imageType | |
exit=1 | |
break; | |
fi | |
start=$(($start+$itemSize)) | |
i=$(($i+1)) | |
done | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Got it -- thank you for that!