Nedanstående är första delen av en serie artiklar med temat ”Optimera din webbplats”. Serien utgår från LAMP (Linux Apache MySQL PHP) som plattform, men de flesta tekniker är förstås tillgängliga universellt. Vi börjar med en av de mest självklara och enkla optimeringsåtgärderna, att optimera de bilder vi presenterar.

Förlustfri Optimering

Tux innan optimeringTux efter optimering

De två bilderna ovan är identiska  till både utseende och kvalitet. Bilden till höger har dock optimerats med optipng och är därför 11% mindre till storlek (datamängd). Den högra pingvinen har optimerats med förlustfri komprimering vilket innebär att ingen synlig data förändrats. I den här introduktionen använder vi endast förlustfri optimering. Det kan ibland vara berättigat att komprimera bilder ytterligare med mer eller mindre synbara förluster som resultat, men att optimera utan försämrat resultat är alltid ett första steg. Att inte göra det är slöseri med både din och andras bandbredd och tid!

Varför optimera?

Optimering gör förstås störst skillnad om du har hög trafik till din sida. Det kan tyckas onödigt att skala bort några enstaka kilobytes här och där om din sida inte besöks av fler än några stycken om dagen, och till viss del stämmer det väl också, men det finns faktiskt skäl till att optimera redan från början:

  • Sökmotorer premierar snabba sidor.
  • En snabb sida är roligare att besöka. Flera undersökningar från bland annat Amazon visar att en sidas responstid står direkt i proportion till hur länge besökare/kunder stannar kvar och om de återkommer eller ej.
  • Det kommer bli mycket mer abete att optimera din sida i efterhand.
  • Ligger din sida på ett webbhotell har du ofta en begränsning i hur mycket data du får lagra, samt hur mycket bandbredd din sida får omsätta per månad.
  • Det är roligt att ständigt förbättra sin skapelse!

Jpegoptim

Programmet jpegoptim använder en förlustfri kompressionsalgoritm som rekommenderas (och får man anta, används) av inga mindre än Google. Använder du Ubuntu finns paketet jpegoptim direkt att hämta med apt-get. För Fedora finns inget färdigt paket, och eftersom det är Fedora jag använder för tillfället var jag nödgad att gå den lite längre vägen och kompilera programmet själv.

Laddade först ner senaste versionen (för stunden 1.2.4) från programmets egna sida. Programmet kräver att utvecklingsfilerna för libjpeg finns installerade. Började därför först med att installera dessa, som på fedora heter libjpeg-turbo-devel. Sedan var det bara att packa upp programmet och kompilera det:

./configue
make
make strip
make install

Proceduren torde se liknande ut även på andra plattformar där färdiga paket saknas, så som Mac OS X. Programmet kommer med en rad möjligheter för kompression, såväl förlustfri som med förluster. Då jag inte vill försämra kvaliteten på bilderna är det förlustfri som gäller, och det får vi med växeln –strip-all:

[anders@anders-laptop ~]$ jpegoptim --strip-all DSC_0055.JPG
DSC_0055.JPG 3008x2000 24bit  [OK] 2525257 --> 2438219 bytes (3.45%), optimized.

Som synes blev det i det här fallet ingen dramatiskt förminskning av bildens storlek. Men 3.45% är förstås bättre än ingenting, framför allt som vi inte försämrat bildens kvalitet! Hur mycket data som kan skalas bort beror på flera faktorer i bilden, men normalt brukar det röra sig mellan 2-20%. Enkelt uttryckt så är det lättare att få bra resultat med enkla bilder med mindre detaljer och färger än t.ex. ett foto.

Optipng

Optipng är nästa program i ordningen och som namnet ger en vag ledtråd om är det specialiserat på bilder i PNG-formatet. Mer detaljerad information om optipng hittar du på programmets webbplats. Programmet används normalt så här:

[anders@anders-laptop tmp]$ optipng -o7 ~/kylskapmini.png
OptiPNG 0.6.4: Advanced PNG optimizer.
Copyright (C) 2001-2010 Cosmin Truta.

** Processing: /home/anders/kylskapmini.png
560x314 pixels, 3x8 bits/pixel, RGB
Input IDAT size = 73786 bytes
Input file size = 74004 bytes

Trying:
  zc = 9  zm = 9  zs = 0  f = 0		IDAT size = 56020
  zc = 3  zm = 9  zs = 0  f = 0		IDAT size = 53390
  zc = 3  zm = 9  zs = 1  f = 0		IDAT size = 53390

Selecting parameters:
  zc = 3  zm = 9  zs = 1  f = 0		IDAT size = 53390

Output IDAT size = 53390 bytes (20396 bytes decrease)
Output file size = 53500 bytes (20504 bytes = 27.71% decrease)

Som synes på sista raden fick vi alltså en förminskning på nästan 28% utan bildförsämring! Växeln -oX där X är ett nummer mellan 1-7 kan användas om man själv vill bestämma hur hårt programmet ska anstränga sig för att optimera din bild. Har du ett stort bildbibliotek får du vara beredd på att en optimering med -o7 kan ta en bra stund. Annars finns ingen anledning att  inte optimera maximalt.

Automatisk optimering av uppladdade bilder

Lättja är en grundpelare i all systemadministration. Istället för att manuellt optimera varje enskild bild med verktygen ovan vore det väl skönt om vi kunde automatisera processen? Optimalt hade det ju varit om vi bara kunde ladda upp våra bildfiler som vanligt och låta servern optimera dom utan att vi behövde lyfta ett finger. Det finns som alltid i Linux olika sätt att lösa ett sådant problem, men i det här exemplet använder jag det utmärkta programmet incron.

Bevaka en katalog med incron

I UNIX-system och dess derivat är cron ett system för att schemalägga processer till valda tidpunkter och intervaller. Programmet incron bygger på samma princip (och använder samma syntax) men istället för att bevaka klockslag och datum bevakar incron förändringar i kataloger. Du väljer själv vilka förändringar du vill bevaka, men i vårt fall vill vi bara se när en ny fil anländer i vår katalog.

Börja med att installera (yum install, apt-get install, etc) incron. Lägg sedan till de användare som ska använda incron i filen incron.allow som du hittar (eller skapar) i /etc/incron.d/. Starta sedan incron med kommandot ”service incrond start”. Det som återstår nu är att välja vilken katalog vi vill bevaka och vad som ska hända när en ny fil anländer till katalogen. För att ställa in de reglerna använder vi kommandot:

incrontab -e

Detta öppnar en editor (vilken bestämmer du i /etc/incron.conf) för redigering av regler för incron. Syntaxen för den här filen känner du igen om du jobbat med crontab tidigare, annars är den som följer:

<katalog> <händelse> <kommando>

Exakt vilka händelser du kan bevaka hittar du i manualsidan för incrontab (och en bra guide online här), och du kan separera flera händelser med ett kommatecken. I vårt fall vill vi veta när nya filer skapats i vår katalog eller flyttats till den. De händelserna heter IN_CREATE och IN_MOVED_TO. Filen ser så här långt alltså ut såhär:

/var/www/uploads/ IN_CREATE,IN_MOVED_TO

Så långt har vi alltså angett vilken katalog som ska bevakas och vilka händelser vi ska bevaka. Återstår gör att ange vad vi vill göra när dessa händelser inträffar, alltså vilket kommando vi vill köra. Vi skulle också behöva veta vilken fil det är som flyttats till vår katalog för att kunna optimera just den. Lyckligtvis har incron två inbyggda variablar som gör det enklare för oss:

$@ den bevakade katalogen
$# filen som triggat händelsen

Fler inbyggda variabler kan du läsa om i manualen, men i vårt fall är det just dessa två vi behöver. För att köra kommandot ”optipng -o7″ på varje png-fil som laddas upp hade vi alltså kunnat skriva:

/var/www/uploads/ IN_CREATE,IN_MOVED_TO /usr/bin/optipng -o7 $@$#

Våra variabler $@ och $# kommer här expandera till /var/www/uploads/uppladdadebilden.png

Bedöma filtyp efter filändelse

Detta funkar ju utmärkt så länge det är en PNG-fil vi laddat upp. Är det en JPEG-bild eller något annat format kommer optipng att säga ifrån. Vi behöver därför något sätt att särskilja de filer vi laddar upp efter filändelse eller typ. Finns även här olika sätt att lösa det på. Min lösning var ett kort shell-skript:

#!/bin/bash
# Simple script to determine file type and pass file to appropriate
# program. To be called from incrontab.
# Written by Anders Eknert, anders@lonewolfmedia.se

if [ "$1" == "" ]; then

	echo "Usage: optimize [file].[jpg|jpeg|png]"

else
	# Set filename to first argument
	filename=$1
	# Set myindex to position of .
	myindex=`expr index $1 .`
	# Set extension to substring after .
	extension=${filename:myindex}
	# Check for filetype and process accordingly
	if [ "$extension" == "png" ]; then
		optipng -o7 $filename &> /dev/null

	elif [ "$extension" == "jpg" ]; then
		jpegoptim --strip-all $filename &> /dev/null

	elif [ "$extension" == "jpeg" ]; then
		jpegoptim --strip-all $filename &> /dev/null

	fi
fi

Skriptet ovan (som jag döpt till optimize och gjort körbart med chmod +x) tar en parameter, nämligen ett filnamn och kontrollerar sedan filändelsen. Är den .png kommer den anropa optipng för att optimera bilden. Är den en bild av jpeg-typ kommer den anropa jpegoptim för samma uppdrag. Det kan tyckas vanskligt att bedöma en fil endast efter filändelse, men i mitt fall vet jag att det bara är jag som kommer att ladda upp bilder och kan därför förutsätta att jag inte laddar upp annat än bilder i korrekta format och filändelser.

Slutligen (äntligen!)

Skriptet placerar vi sedan i valfri katalog. Jag valde /home/anders/bin. Återstår då bara att ändra vår incrontab, vilket vi återigen gör med ”incrontab -e”:

/var/www/uploads/ IN_CREATE,IN_MOVED_TO /home/anders/bin/optimize $@$#

Sådär! Varje gång någonting händer, specifikt när en ny fil skapas eller flyttas in  i vår uploads-katalog kommer incron att kalla på skriptet optimize som bedömer filtypen och sedan komprimerar den uppladdade bilden åt oss. Och vi kan nu framöver jobba mindre med optimering och mer åt att skapa innehåll!

Kommentera