Albumeur photo: script de création d'album photo en html à partir d'un dossier contenant des images (utilise pil)

Description

Ce code est un script que j'avais réalisé pour mes besoins personnels.
En effet, je fais tourner un petit serveur apache maison, et je m'étais demandé si j'allais m'atteler à la tache de réaliser une application PHP/SQL pour gérer mes albums de photo. J'hésitais car je trouvais cela assez lourd par rapport aux besoins ponctuels que j'avais d'afficher des photos (photos de vacances de temps en temps par exemple). Et un jour, EUREKA! L'idée m'est venue : J'allais réaliser un script python qui s'occupait de tout:
Organisation:
Des fichiers images dans un répertoire donné (pour l'instant, il ne gère que les jpeg)
Méthode:
Le script parcourt simplement les fichiers du répertoire,
pour chaque image il crée une miniature(thumbnail) et une réduction: image un peu plus légère que les gros fichiers photos numériques qui peuvent allegrement atteindre les 5Mo l'image.
Il génère ensuite le code HTML de la page dont l'architecture principale est une <TABLE> qui affiche les photos.

Au final, on se retrouve avec le dossier de départ qui contient les images de départ + leurs miniatures + leurs réductions ainsi qu'un fichier html qui contient l'album photo.

Ce script nécessite PIL (Python Imaging Library) que vous pourrez télécharger ici gratuitement: http://www.pythonware.com/products/pil/
Cette bibliothèque contient moultes fonctionnalités de manipulation d'image, vraiment très bien pensées.

Source / Exemple :


# -*- coding: cp1252 -*-
"""
Albumeur photo:
script python écrit par VyCHNou (vychnou@hotmail.com)
Transforme un répertoire contenant des photos en album photo html avec création de thumbnails et de réductions des photos.
"""
import os, sys, Image, time
from optparse import OptionParser
def resize(im,x,y):
	"""retourne l'image redimensionnée(diminution) en gardant les proportions"""
	if ((im.size[0]/x)>(im.size[1]/y)):
		coeffResize=float(im.size[0]/float(x))
	else:
		coeffResize=float(im.size[1]/float(y))
	return im.resize((int(round((im.size[0]/coeffResize))),int(round((im.size[1]/coeffResize)))))

def fichierOk(dir, fic):
	"""retourne True si le fichier est ok, False sinon"""
	fic=fic.lower()
	if (os.path.isfile(dir+os.sep+fic) and fic[len(fic)-4:len(fic)]==".jpg" and fic[0:6]!="petit_" and fic[0:6]!="moyen_"):
		return True
	else:
		return False

listePhotos=[]
parser=OptionParser()
parser.add_option("-i", "--i", "--interactif",
                  dest="interactif", action="store_true", default=False,
                  help="lance le script en mode interactif)")
parser.add_option("-d", "--d", "--dossier", action="store",
                  dest="dossier", type="string",
                  help="dossier a transformer en album photo")
parser.add_option("--html", "--fichier_html", action="store",
                  dest="html", type="string",
                  help="nom du fichier html genere",
                  default="index.html")
parser.add_option("--css", "--fichier_css", action="store",
                  dest="css", type="string",
                  help="nom du fichier css utilise (pas d'option=pas de fichier css utilise)")
parser.add_option("-t", "--t", "--titre", action="store",
                  dest="titre", type="string",
                  help="titre de l'album",
                  default="album photo")
parser.add_option("-c", "--c", "--commentaire", action="store",
                  dest="commentaire", type="string",
                  help="commentaire sur l'album",
                  default="Quelques photos du dossier ")
parser.add_option("--nc", "--nombre_colonnes", action="store",
                  dest="nombre_colonnes", type="int",
                  help="nombre de colonnes de photos",
                  default=4)
parser.add_option("--lm", "--largeur_miniature", action="store",
                  dest="largeur_miniature", type="int",
                  help="largeur en pixels d'une miniature (thumbnail)",
                  default=200)
parser.add_option("--hm", "--hauteur_miniature", action="store",
                  dest="hauteur_miniature", type="int",
                  help="hauteur en pixels d'une miniature (thumbnail)",
                  default=200)
parser.add_option("--lr", "--largeur_reduction", action="store",
                  dest="largeur_reduction", type="int",
                  help="largeur en pixels d'une reduction",
                  default=800)
parser.add_option("--hr", "--hauteur_reduction", action="store",
                  dest="hauteur_reduction", type="int",
                  help="hauteur en pixels d'une reduction",
                  default=600)
parser.add_option("-q", "--q", "--qualite", action="store",
                  dest="qualite", type="int",
                  help="qualite des miniatures",
                  default=80)
(options, args) = parser.parse_args()
if (options.interactif):
	options.dossier=raw_input("repertoire a transformer en album photo ? >>")
	options.html=raw_input("nom du fichier html album photo ? >>")
	options.titre=raw_input("titre de votre album ? >>")
	options.commentaire=raw_input("commentaire sur votre album ? >>")
	options.nombre_colonnes=int(raw_input("nombre de colonnes de photo ? >>"))
	options.largeur_miniature=int(raw_input("largeur des miniatures ? >>"))
 	options.hauteur_miniature=int(raw_input("hauteur des miniatures ? >>"))
	options.largeur_reduction=int(raw_input("largeur des photos allegees? >>"))
	while (options.largeur_miniature>=options.largeur_reduction):
		print "Miniature doit etre moins large que photo allegee"
		options.largeur_reduction=int(raw_input("largeur des photos allegees? >>"))
	options.hauteur_reduction=int(raw_input("hauteur des photos allegees? ? >>"))
	while (options.hauteur_miniature>=options.hauteur_reduction):
		print "Miniature doit etre moins haute que photo allegee"
	options.hauteur_reduction=int(raw_input("hauteur des photos allegees? ? >>"))
	options.qualite=int(raw_input("qualite des miniatures ?(chiffre entre 1 et 100) >>"))
#on liste les fichiers du répertoire
listePhotos=[]
for fichier in os.listdir(options.dossier):
	if (fichierOk(options.dossier,fichier)):
		listePhotos.append(fichier)
print str(len(listePhotos))+" images a traiter dans "+options.dossier
nbImages=len(listePhotos)
cptImage=1
pourtrenteage=0
pourtrenteagetmp=0
#on parcours tous les fichiers du dossier entré
for fichier in listePhotos:
        #on ouvre le fichier image
	im = Image.open(options.dossier+os.sep+fichier)
	#on ouvre le fichier de la réduction
	outfile=options.dossier+os.sep+"moyen_"+fichier
	try:
                #on met à l'échelle la réduction
		im=resize(im,options.largeur_reduction,options.hauteur_reduction)
		#on la sauvegarde dans le fichier dont le nom commence par moyen_
		#en qualité maximale
		im.save(outfile,quality=100)
	except IOError:
		print "cannot convert"
	im = Image.open(options.dossier+os.sep+fichier)
	#on ouvre le fichier de la miniature
	outfile=options.dossier+os.sep+"petit_"+fichier
	try:
		#on met à l'échelle la miniature
		im=resize(im,options.largeur_miniature,options.hauteur_miniature)
		#on sauvegarde la miniature à la qualité voulue dans le fichier dont le
		#nom commence par petit_ et à la qualité voulue
		im.save(outfile,quality=options.qualite)
	except IOError:
		print "cannot convert"
	#on affiche un renseignement sur la console
	#print "{"+str(cptImage)+"/"+str(nbImages)+"} Fichier [ "+fichier+" ] traite"
	ratio=(float)(cptImage)/nbImages
	str="["
	for i in range((int)(50*ratio)):
		str=str+"#"
	for i in range((int)(50-(50*ratio))):
		str=str+" "
	str=str+"]"
	print str
	cptImage=cptImage+1
#On calcule le nombre de lignes à partir du nombre de colonnes et du nombre de photos
nombreDeLignes=int(round(float(len(listePhotos))/float(options.nombre_colonnes)))
#on ajuste la derniere ligne
if (nombreDeLignes<(float(len(listePhotos))/float(options.nombre_colonnes))):
	nombreDeLignes=nombreDeLignes+1
#On génère le début du code html
if (options.css!=None):
        codecss=	'''<style type="text/css" title="default" media="screen">
                @import "'''+nomCss+'''";
                </style>'''
else:
        codecss=""
album_photo_html='''
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/HTML4/loose.dtd">
<head>
<title>'''+options.titre+'''</title>
'''+codecss+'''
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
\n<body>
<h1>'''+options.titre+'''</h1>
'''+options.commentaire+'''
<table width="100%" border="0">
'''
site="http://vychnou.info/test"
#on va maintenant construire le tableau HTML de photos
#pour chaque ligne de photos à créer:
for i in range(nombreDeLignes):
	j=0
	#nouvelle ligne de la table:
	album_photo_html=album_photo_html+'  <tr>'
        #ajout de chaque photo dans une balise img, génération des liens etc..:
	while (j<options.nombre_colonnes and ((i*options.nombre_colonnes)+j)<len(listePhotos)):
		album_photo_html=album_photo_html+'<td>\n  <a href="moyen_'+listePhotos[(i*options.nombre_colonnes)+j]+'''">
		<img src="petit_'''+listePhotos[(i*options.nombre_colonnes)+j]+'" alt="'+listePhotos[(i*options.nombre_colonnes)+j]+'''"/></a><br>\n
                <a href="'''+listePhotos[(i*options.nombre_colonnes)+j]+'">'+listePhotos[(i*options.nombre_colonnes)+j]+'</a>\n  </td>\n'
		j=j+1
	#fin de ligne de la table:
	album_photo_html=album_photo_html+'</tr>'
album_photo_html=album_photo_html+'''
</table>
<i>album photo réalis&eacute &agrave l'aide d'un script python écrit par VyCHNou (vychnou@hotmail.com)</i>
</body>
'''
#on ouvre le fichier dans lequel on veut le sauvegarder
f=open(options.dossier+os.sep+options.html,"w")
#on écrit dedans ce code html
f.write(album_photo_html)
f.close()
#on informe l'utilisateur de la fin des opérations
print "\n>>>Fichier [ "+options.dossier+os.sep+options.html+ "] cree\n\n>>>>>>ALBUM PHOTO CREE<<<<<<"

Conclusion :


Ce script tourne simplement sur la console. Il peut marcher en mode interactif (python albumeur.py -i) et il va alors demander de renseigner divers paramètres. Il peut aussi marcher en mode passage d'arguments pour une utilisation beaucoup plus rapide. (l'option -h affichera une aide en ligne de commandes qui explique tout).

Exemple: python albumeur.py -d "c:\photos\Vacances 2005" -t "vacances en Espagne" -c "Tata Robert et toute la famille dans les environs de Valence" -nc 5 -lm 180 -hm 180 -lr 800 -hr 600 -html index.htm -css css.css
Génère un album photo à partir du dossier (-d) c:\photos\Vacances 2005 dont le titre (-t) sera vacances en Espagne, dont le commentaire (-c) sera "Tata Robert et toute la famille dans les environs de Valence", qui aura 5 colonnes (-nc), des miniatures de 180pixels de large (-lm) et de 180pixels de haut (-hm), des réductions de 800 pixels de large (-lr), 600 pixels de haut(-hr), dont le nom du fichier html de sortie sera index.htm (-html), dont le nom du fichier css(-css facultatif) sera css.css .

Pour une démonstration du résultat, allez voir: http://vychnou.info/albumeur/demo

Divers choses restent à améliorer:
-Gestions des erreurs de saisie
-Compatibilité avec plus de types d'images (très simple à faire, il suffit de se baser sur les images que PIL accepte de traiter)
-Gestion des codes spéciaux dans les fichiers HTML (ça ne doit pas être très compliqué à faire non plus)
...
N'hésitez pas à laisser des commentaires, en bien ou en mal

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.