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 |
Glad it was useful for you! It's been so long since I looked at this that the original user's script is gone. My abilities extend only as far as modding the original, so if you have improvements a) they are most welcome and b) I'll need you to spell them out.
I made no improvement at all, I simply added your lines 141-145 under 147 in order to always save as JPG if the imageType is not recognized. In other words: make JPG the default extension, even when it does not match with the hexdump.
Got it -- thank you for that!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for this script, it has been really helpful.
In my case, it fell into the else clause in line 146 (imageType was 0x00002328), so I decided to simply save it as a TIFF file and it worked seamlessly. Then I tried changed it to JPG or PNG and it still worked. So I assume that, as long as you give it a valid image extension, tools like Gimp are able to open it.