Op 17 maart 1994 werd de aflevering "Homer Loves Flanders" van de Simpsons voor het eerst uitgezonden. Daarin komt een scène voor waarin het hoofdpersonage Homer Simpson aan zijn buren — de familie Flanders — vraagt of ze met hem op stap willen gaan. Als ze antwoorden dat ze daar geen zin in hebben, antwoord Homer met "Oh, ok" voordat hij in de struiken verdwijnt.

homer
Deze animated GIF werd bekend onder de naam Homer Backs Into Things.

De scène hierboven werd op 8 december 2010 vastgelegd in een animated GIF die is uitgegroeid tot één van de bekendste Internet memes. De GIF wordt gebruikt als uitdrukking van schaamte en werd vaak bewerkt tot Homer (of iemand anders) die in andere dingen verdwijnt.

Opgave

GIF1 (Graphics Interchange Format) is een bestandsformaat voor het opslaan van rasterafbeeldingen in digitale vorm. Het formaat ondersteunt kleuren, verschillende resoluties, animatie en een transparante achtergrond. Bij een animated GIF worden verschillende afbeeldingen achter elkaar opgeslagen in hetzelfde GIF-bestand. Deze afbeeldingen worden de frames van de animated GIF genoemd. Animatie ontstaat door deze frames snel na elkaar af te spelen. Door na het laatste frame terug het eerste frame weer te geven, kan een animated GIF zichzelf eindeloos herhalen.

ImageMagick2 is een open source bibliotheek die bestaat uit verschillende Unix commando's voor het weergeven, converteren en bewerken van digitale afbeeldingen (zowel rasterafbeeldingen als vectorafbeeldingen). De bibliotheek bevat onder andere het commando convert dat als volgt kan gebruikt worden om drie afbeeldingen 0.png, 1.png en 2.png in PNG-formaat3 te bundelen tot één animated GIF animated.gif:

$ convert frame0.png frame1.png frame2.png animated.gif

Hetzelfde commando kan ook als volgt gebruikt worden om de frames van een animated GIF animated.gif op te slaan als individuele bestanden in PNG-formaat:

$ convert -coalesce animated.gif "frame%d.png"
$ ls
frame0.png frame1.png frame2.png

Hierbij vormt het laatste argument ("frame%d.png") een template die aangeeft hoe de bestanden met de individuele frames moeten genoemd worden. Hierbij worden de opeenvolgende frames genummerd vanaf nul en wordt de plaatshouder %d ingevuld met het volgnummer van het frame in het GIF-bestand. Het commando identify uit de ImageMagick bibliotheek kan dan weer gebruikt worden om te bepalen hoeveel frames een animated GIF heeft.

Schrijf een bash shell script animate dat kan gebruikt worden om bewerkingen uit te voeren op animated GIF-bestanden. Aan het shell script moeten altijd minstens twee argumenten doorgegeven worden: i) de naam van een subcommando en ii) de padnaam van een (bestaand of nieuw aan te maken) GIF-bestand. Het shell script moet de volgende vijf subcommando's ondersteunen:

bundle
Als extra argumenten moeten aan dit subcommando de padnamen van één of meer PNG-bestanden doorgegeven worden. Als er geen extra argumenten doorgegeven worden dan moet een boodschap met de signatuur van het subcommando (zie onderstaande voorbeeldsessie) uitgeschreven worden naar stdout en moet het shell script eindigen met exit status 2. Als één van de extra argumenten geen gewoon bestand is of niet leesbaar is, dan moet de gepaste boodschap (zie onderstaande voorbeeldsessie) uitgeschreven worden naar stdout en moet het shell script eindigen met exit status 3. Anders moet het shell script de gegeven PNG-bestanden bundelen tot één animated GIF, die wordt opgeslagen op de bestandslocatie die als tweede argument werd doorgegeven aan het shell script.
unpack
Als extra argument kan aan dit subcommando optioneel nog een padnaam van een directory doorgegeven worden. Als er meer dan één extra argument doorgegeven wordt dan moet een boodschap met de signatuur van het subcommando (zie onderstaande voorbeeldsessie) uitgeschreven worden naar stdout en moet het shell script eindigen met exit status 2. Anders moet het shell script de frames van het gegeven animated GIF-bestand opslaan als individuele PNG-bestanden in de gegeven directory. Hierbij moeten de opeenvolgende frames benoemd worden als 0.png, 1.png, 2.png, …. Als er geen directory gegeven werd dan moeten de bestanden in de huidige directory opgeslagen worden. Als de gegeven directory nog niet bestond dan moet die door het shell script aangemaakt worden.
sample
Als extra argumenten moeten de padnaam van een tweede GIF-bestand doorgegeven worden, gevolgd door één of meer volgnummers van frames in het eerste GIF-bestand (waarbij de opeenvolgende frames genummerd worden vanaf nul). Als er minder dan twee extra argumenten doorgegeven worden dan moet een boodschap met de signatuur van het subcommando (zie onderstaande voorbeeldsessie) uitgeschreven worden naar stdout en moet het shell script eindigen met exit status 2. Als één van de gegeven frames buiten het bereik van de volgnummers van het eerste GIF-bestand ligt dan moet de gepaste boodschap (zie onderstaande voorbeeldsessie) uitgeschreven worden naar stdout en moet het shell script eindigen met exit status 3. Anders moet het shell script een nieuw GIF-bestand aanmaken op de gegeven bestandslocatie (padnaam van tweede GIF-bestand), waarvan de frames bestaan uit de geselecteerde frames van het gegeven GIF-bestand (padnaam van eerste GIF-bestand) in de volgorde waarop de volgnummers als argument doorgegeven worden.
invert
Als extra argument moet de padnaam van een tweede GIF-bestand doorgegeven worden. Als dat niet het geval is dan moet een boodschap met de signatuur van het subcommando (zie onderstaande voorbeeldsessie) uitgeschreven worden naar stdout en moet het shell script eindigen met exit status 2. Anders moet het shell script een nieuw GIF-bestand aanmaken op de gegeven bestandslocatie (padnaam van tweede GIF-bestand), waarvan de frames bestaan uit de frames van het gegeven GIF-bestand (padnaam van eerste GIF-bestand), maar dan in omgekeerde volgorde.
mirror
Als extra argument moet de padnaam van een tweede GIF-bestand doorgegeven worden. Als dat niet het geval is dan moet een boodschap met de signatuur van het subcommando (zie onderstaande voorbeeldsessie) uitgeschreven worden naar stdout en moet het shell script eindigen met exit status 2. Anders moet het shell script een nieuw GIF-bestand aanmaken op de gegeven bestandslocatie (padnaam van tweede GIF-bestand), waarvan de frames bestaan uit de frames van het gegeven GIF-bestand (padnaam van eerste GIF-bestand) gevolgd door de frames van het gegeven GIF-bestand maar dan in omgekeerde volgorde. Het resultaat is dat de frames van het gegeven GIF-bestand in het nieuwe GIF-bestand van voor naar achter en van achter naar voor worden afgespeeld.

Naast alle foutafhandeling die we reeds bij de individuele subcommando's vermeld hebben, moet het shell script ook de volgende foutafhandeling voorzien:

Als er zich geen fouten voordoen dan moet het shell script eindigen met exit status 0. Als het shell script tijdelijke bestanden of directories aanmaakt, dan moet het er ook voor zorgen dat die bestanden of directories terug verwijderd worden vóór het shell script eindigt.

Voorbeeld

Onderstaande voorbeeldsessie geeft aan hoe het shell script animate moet kunnen gebruikt worden. Hierbij gaan we ervan uit dat het tekstbestand homer.gif45 zich in de huidige directory bevindt.

$ animate -h
animate [-h] [<action> <GIF> ...]

ACTIONS
    animate bundle <GIF> <FRAME> ...
    animate unpack <GIF> [<DIR>]
    animate sample <GIF> <GIF> <FRAME> ...
    animate invert <GIF> <GIF>
    animate mirror <GIF> <GIF>
$ echo $?
1
$ animate unpack homer.gif6 homer/
$ ls homer/
0.png7   15.png8  21.png  28.png  34.png  40.png  47.png  53.png9
1.png10   16.png11  22.png  29.png  35.png  41.png  48.png  54.png12
10.png13  17.png14  23.png  3.png   36.png  42.png  49.png  55.png15
11.png16  18.png17  24.png  30.png  37.png  43.png  5.png   6.png18
12.png19  19.png20  25.png  31.png  38.png  44.png  50.png  7.png21
13.png22  2.png23   26.png  32.png  39.png  45.png  51.png  8.png24
14.png25  20.png26  27.png  33.png  4.png   46.png  52.png  9.png27
$ animate bundle homer.bundled.gif28 homer/0.png29 homer/10.png30 homer/20.png31
$ animate sample homer.gif32 homer.sampled.gif33 0 10 20 30 40 50
$ animate invert homer.gif34 homer.inverted.gif35
$ animate mirror homer.gif36 homer.mirrored.gif37
$ ls
animate  homer.bundled.gif38  homer.inverted.gif39  homer.sampled.gif40
homer    homer.gif41          homer.mirrored.gif42

Onderstaande voorbeeldsessie toont enkele voorbeelden van de foutafhandeling die het shell script animate moet voorzien.

$ animate bundle homer.gif
animate bundle <GIF> <FRAME> ...
$ echo $?
2
$ animate bundle homer.bundled.gif homer/0.png XXX homer/20.png
animate bundle: file XXX does not exist
$ echo $?
3
$ animate unpack homer.gif homer/ XXX
animate unpack <GIF> [<DIR>]
$ echo $?
2
$ animate sample homer.gif homer.sampled.gif
animate sample <GIF> <GIF> <FRAME> ...
$ echo $?
2
$ animate sample homer.gif homer.sampled.gif 0 10 1000 1000000
animate sample: frames must be in range [0, 55]
$ echo $?
3
$ animate invert homer.gif
animate invert <GIF> <GIF>
$ echo $?
2
$ animate mirror homer.gif
animate mirror <GIF> <GIF>
$ echo $?
2
$ animate mirror marge.gif marge.mirrored.gif
animate mirror <GIF> <GIF>
$ echo $?
2

Epiloog

Dit is slim bedacht — in 1973 vond Cecil Slemp schoenen met omgekeerde zolen uit (Amerikaans patent US3823494A43). Op die manier kan je makkelijk voetafdrukken achterlaten die in de tegenovergestelde richting wijzen.

backtracking
Schoenen met met omgekeerde zolen (Cecil Slemp, 1974).

Nu zullen je bloederige sporen dus naar de moordscène leiden.