begin process at 2008 08 29 04:10:04
1 233 495 membres
36 nouveaux aujourd'hui
14 291 membres club

Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum.
Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

COMPACTEUR D'IMAGES JPEG PAR LOT


Information sur la source

Catégorie :Application complète Classé sous : compactage, images, barre progression, PIL, jpeg Niveau : Débutant Date de création : 10/12/2007 Date de mise à jour : 11/12/2007 19:18:00 Vu / téléchargé: 1 875 / 46

Note :
9 / 10 - par 1 personne
9,00 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

Commentaire sur cette source (9)
Ajouter un commentaire et/ou une note

Description

Lassé d'appeler une à une avec Gimp toutes mes photos pour en réduire le poids sans en modifier ni la taille ni la qualité,j'ai écrit ce petit programme qui lit et réécrit tous les fichier en .jpeg (ou .jpg) d'un répertoire. L'algorithme utilisé par le module PIL a les mêmes effets que Gimp et c'est ainsi beaucoup plus rapide.
Je n'ai jamais constaté de perte de qualité dans mes photos et la réduction de poids est dûe à l'optimisation du code de compression jpeg utilisé, ce qui n'est pas le cas pour les appareils photo que j'ai testés.

Source

  • #Compacteur images JPEG v1.3
  • # -*- coding: utf-8 -*-
  • from Tkinter import *
  • from PIL import Image
  • import glob
  • import os
  • import tkFileDialog
  • import string
  • import Tix
  • global repert, nbfich, tailaff
  • def Exploration() :
  • global repert, nbfich,tailaff, tailrepe
  • list1.delete(0,END)
  • nbfich=0
  • lab4.configure(text='')
  • lab5.configure(text='')
  • lab6.configure(text='')
  • lab7.configure(text='')
  • repert=tkFileDialog.askdirectory(title='Choisir le répertoire à compacter, puis OK', initialdir='C:\\')
  • repert=repert+'\\*.*'
  • for fichier in glob.glob(repert):
  • file, ext = os.path.splitext(fichier)
  • tailfich = os.path.getsize(fichier)
  • tailfiaff = tailfich/1024
  • chaine='%4d'%tailfiaff+' Ko ^ '+fichier
  • if ext=='.jpg' or ext=='.JPG' or ext=='.jpeg' or ext=='.JPEG' :
  • list1.insert(END,chaine)
  • nbfich=nbfich+1
  • Taille_Repert()
  • tailrepe = tailaff
  • lab2.configure(text='Taille cumulée des images = '+tailaff)
  • lab3.configure(text='Nombre d''\'images = '+str(nbfich))
  • if nbfich > 0 :
  • button1.config(bg='yellow',text='Valider',state=NORMAL)
  • else : button1.config(bg='lightgrey',text='')
  • button2.config(bg='lightblue',text='Autre répertoire',state=NORMAL,relief=RAISED)
  • list1.select_set(0)
  • list1.bind('<ButtonRelease>',Affiche_image)
  • def Affiche_image(e) :
  • index = map(int,list1.curselection())[0]
  • fichima = string.strip(list1.get(index))
  • nom=''
  • ind=0
  • i=0
  • while i< len(fichima) :
  • if ind==1 :
  • nom=nom+fichima[i]
  • if fichima[i]=='^' :
  • ind=1
  • i=i+1
  • i=i+1
  • im=Image.open(nom)
  • im.show()
  • def Validation() :
  • global repert, nbfich, ficherr, tailaff, tailrep, tailrepe
  • fen3=Tix.Tk()
  • fen3.geometry("400x80+407+340")
  • fen3.title(repert)
  • labb=Label(fen3,text='Progression du compactage', fg='blue', font=('Arial', 10))
  • labb.pack(side=TOP)
  • meter=Tix.Meter(fen3,value=0.)
  • meter.pack()
  • labf=Label(fen3,text='', fg='black', font=('Arial',9))
  • labf.pack(side=BOTTOM)
  • nberr=0
  • nbok = 0
  • ficherr=[] # liste des fichiers en erreur écriture
  • if repert <> '' and nbfich>0 :
  • lab4.configure(text='Traitement en cours.......Patience, merci.')
  • fram5.update_idletasks()
  • i=0
  • for fichier in glob.glob(repert):
  • file, ext = os.path.splitext(fichier)
  • if ext=='.jpg' or ext=='.JPG' or ext=='.jpeg' or ext=='.JPEG' :
  • i=i+1
  • meter.config(value=float(i)/nbfich)
  • meter.update()
  • labf.configure(text=file)
  • im=Image.open(fichier)
  • try :
  • im.save(file+'.jpg')
  • nbok = nbok+1
  • except IOError :
  • nberr = nberr+1
  • ficherr.append(file)
  • button1.config(bg='grey',state=DISABLED)
  • lab4.configure(text='Résultat du traitement :')
  • Taille_Repert()
  • if nbok==0 :
  • lab5.configure(text=' Aucune image traitée')
  • elif tailaff == tailrepe :
  • lab5.configure(text=' Ce dossier est déjà compacté')
  • else :
  • lab5.configure(text=str(nbok)+' image(s) traitée(s)')
  • lab6.configure(text='Nouvelle taille cumulée des images = '+tailaff)
  • nbfich=0
  • if nberr>0 :
  • lab7.configure(text=str(nberr)+' erreur(s)')
  • Trt_Erreur(nberr,ficherr)
  • repert=''
  • fen3.destroy()
  • def Taille_Repert() :
  • global repert, tailaff, tailrep
  • tailrep=0
  • for fichier in glob.glob(repert) :
  • file, ext = os.path.splitext(fichier)
  • tailfich = os.path.getsize(fichier)
  • if ext=='.jpg' or ext=='.JPG' or ext=='.jpeg' or ext=='.JPEG' :
  • tailrep=tailrep+tailfich
  • tailrep1 = tailrep/1024/1024.0
  • tailaff = '%.2f' % tailrep1 +' Mo'
  • def Trt_Erreur(nberr,ficherr) :
  • fen2=Toplevel()
  • fen2.title("CompactImages : Erreurs de traitement")
  • labf2=Label(fen2,text=str(nberr)+' images ne pouvant être traitées \n (Images peut-être en lecture seule)', fg='blue', font=('Arial', 9))
  • labf2.pack(side=TOP,pady=10)
  • fram4=Frame(fen2,borderwidth=0)
  • scrollf2 =Scrollbar(fram4,orient=VERTICAL)
  • listf2 = Listbox(fram4,bg='yellow',width=60,height=15,selectmode='single', yscrollcommand=scrollf2.set)
  • scrollf2.config(command = listf2.yview)
  • scrollf2.pack(side=LEFT,fill=Y)
  • listf2.pack(side=LEFT)
  • fram4.pack()
  • bouf2=Button(fen2,text="Fermer",bg='brown',fg='white', command=fen2.destroy)
  • bouf2.pack(side=BOTTOM,pady=10)
  • for x in ficherr :
  • listf2.insert(END,x)
  • def Affich_Infos() :
  • feninf = Toplevel()
  • feninf.config(bg='lightblue')
  • feninf.geometry("400x250+400+220")
  • feninf.title("À propos de CompactImages")
  • labinf=Label(feninf,bg='lightblue', fg='black',width=50,font=('Arial', 9),
  • text= "\nCompactImages v.1.3\n\n"
  • "Programme écrit en Python / Tkinter \n"
  • "et distribué sous licence GNU GPL.\n\n"
  • "© 2007 Yves Le Chevalier\n\n"
  • "Ce programme compacte toutes les images JPG (jpeg)\n"
  • "d'un répertoire donné, sans modifier leurs qualités ni\n"
  • "réduire leurs tailles. Il n'affecte pas les images déjà\n"
  • "compactées, ni les images en lecture seule.")
  • labinf.pack(pady=5)
  • bouf3=Button(feninf, text="Fermer", command=feninf.destroy,bg="orange", fg='brown')
  • bouf3.pack(side=BOTTOM,pady=10)
  • # main
  • fen1 = Tk(className='Compacteur images JPEG v1_2')
  • fen1.geometry("500x750+350+200")
  • fen1.resizable(width=False, height=False)
  • can1 = Canvas(fen1, width=20, height=20, bg='lightgrey')
  • signat=PhotoImage(file='YLC.gif')
  • sign=can1.create_image(12,12, image=signat)
  • can1.pack(side=BOTTOM,anchor=E)
  • fram1=Frame(fen1,borderwidth=0)
  • button2 = Button(fram1, text = '', command = Exploration,state=DISABLED,relief=FLAT)
  • button2.grid(row=0,column=0,pady=10)
  • bouinf=Button(fram1,text="A propos", bg="#A6D6A6", fg='blue',command=Affich_Infos)
  • bouinf.grid(row=0,column=1,padx=80)
  • bouf1=Button(fram1,text="Quitter", command=fen1.destroy,bg="pink", fg='brown')
  • bouf1.grid(row=0,column=2)
  • fram1.pack(side=TOP)
  • fram2=Frame(fen1,borderwidth=0)
  • lab1=Label(fram2,text='Liste des fichiers images (Jpg ou Jpeg) à compacter', fg='blue', font=('Arial', 10))
  • lab1.pack(side=TOP)
  • lab1b=Label(fram2,text='(Cliquer sur une image pour la visualiser)', fg='black', font=('Arial', 8))
  • lab1b.pack()
  • scrolly =Scrollbar(fram2,orient=VERTICAL)
  • list1 = Listbox(fram2,bg="#A0D0C0",width=70,height=35,selectmode='single', yscrollcommand=scrolly.set)
  • scrolly.config(command = list1.yview)
  • scrolly.pack(side=LEFT,fill=Y)
  • list1.pack()
  • fram2.pack()
  • fram3=Frame(fen1)
  • lab3=Label(fram3,fg='blue',font=('Arial', 9))
  • lab3.grid(row=0,column=0,padx=5)
  • lab2=Label(fram3,fg='blue',font=('Arial', 9))
  • lab2.grid(row=0,column=1,padx=15)
  • button1 = Button(fram3, text = '', command = Validation)
  • button1.grid(row=0,column=2,padx=35,pady=5)
  • fram3.pack()
  • fram5=Frame(fen1)
  • lab4=Label(fram5,fg='black', font=('Arial', 11))
  • lab4.grid(row=0,column=0,pady=5)
  • lab5=Label(fram5,fg='blue', font=('Arial', 9))
  • lab5.grid(row=0,column=1,padx=20)
  • lab6=Label(fram5,fg='blue', font=('Arial', 9))
  • lab6.grid(row=1,column=1)
  • lab7=Label(fram5,fg='red', font=('Arial', 9))
  • lab7.grid(row=1,column=0)
  • fram5.pack()
  • Exploration()
  • fen1.mainloop()
#Compacteur images JPEG  v1.3
# -*- coding: utf-8 -*-
from Tkinter import *
from PIL import Image
import glob
import os
import tkFileDialog
import  string
import Tix

global repert, nbfich, tailaff

def Exploration() :
    global repert, nbfich,tailaff, tailrepe
    list1.delete(0,END)
    nbfich=0
    lab4.configure(text='')
    lab5.configure(text='')
    lab6.configure(text='')
    lab7.configure(text='')
    repert=tkFileDialog.askdirectory(title='Choisir le répertoire à compacter,  puis OK', initialdir='C:\\')
    repert=repert+'\\*.*'
    for fichier in glob.glob(repert):
        file, ext = os.path.splitext(fichier)
        tailfich = os.path.getsize(fichier)
        tailfiaff = tailfich/1024
        chaine='%4d'%tailfiaff+' Ko   ^ '+fichier
        if ext=='.jpg' or ext=='.JPG'  or ext=='.jpeg' or ext=='.JPEG' :
            list1.insert(END,chaine)
            nbfich=nbfich+1
    Taille_Repert()
    tailrepe = tailaff
    lab2.configure(text='Taille cumulée des images = '+tailaff)
    lab3.configure(text='Nombre d''\'images = '+str(nbfich))
    if nbfich > 0 :
        button1.config(bg='yellow',text='Valider',state=NORMAL)
    else : button1.config(bg='lightgrey',text='')
    button2.config(bg='lightblue',text='Autre répertoire',state=NORMAL,relief=RAISED)
    list1.select_set(0)
    list1.bind('<ButtonRelease>',Affiche_image)

def Affiche_image(e) :
    index = map(int,list1.curselection())[0]
    fichima = string.strip(list1.get(index))
    nom=''
    ind=0
    i=0
    while i< len(fichima) :
        if ind==1 :          
            nom=nom+fichima[i]
        if fichima[i]=='^' :
            ind=1
            i=i+1
        i=i+1
    im=Image.open(nom)
    im.show()

def Validation() :
    global repert, nbfich, ficherr, tailaff, tailrep, tailrepe
    fen3=Tix.Tk()
    fen3.geometry("400x80+407+340")
    fen3.title(repert)
    labb=Label(fen3,text='Progression du compactage', fg='blue', font=('Arial', 10))
    labb.pack(side=TOP)
    meter=Tix.Meter(fen3,value=0.)
    meter.pack()
    labf=Label(fen3,text='', fg='black', font=('Arial',9))
    labf.pack(side=BOTTOM)
    nberr=0
    nbok = 0
    ficherr=[]       # liste des fichiers en erreur écriture
    if repert <> '' and nbfich>0 :
        lab4.configure(text='Traitement en cours.......Patience, merci.')
        fram5.update_idletasks()
        i=0
        for fichier in glob.glob(repert):
            file, ext = os.path.splitext(fichier)
            if ext=='.jpg' or ext=='.JPG'  or ext=='.jpeg' or ext=='.JPEG' :
                i=i+1
                meter.config(value=float(i)/nbfich)
                meter.update()
                labf.configure(text=file)
                im=Image.open(fichier)
                try :
                    im.save(file+'.jpg')
                    nbok = nbok+1
                except IOError :
                    nberr = nberr+1
                    ficherr.append(file)                    
        button1.config(bg='grey',state=DISABLED)
        lab4.configure(text='Résultat du traitement :')
        Taille_Repert()
        if nbok==0 :
            lab5.configure(text=' Aucune image traitée')
        elif tailaff == tailrepe  :
            lab5.configure(text=' Ce dossier est déjà compacté')
        else :
            lab5.configure(text=str(nbok)+'  image(s) traitée(s)')
            lab6.configure(text='Nouvelle taille cumulée des images = '+tailaff)
        nbfich=0
        if nberr>0 :
            lab7.configure(text=str(nberr)+'   erreur(s)')
            Trt_Erreur(nberr,ficherr)
        repert=''
        fen3.destroy()
    
def Taille_Repert() :
    global repert, tailaff, tailrep
    tailrep=0
    for fichier in glob.glob(repert) :
        file, ext = os.path.splitext(fichier)
        tailfich = os.path.getsize(fichier)
        if ext=='.jpg' or ext=='.JPG'  or ext=='.jpeg' or ext=='.JPEG' :
            tailrep=tailrep+tailfich
    tailrep1 = tailrep/1024/1024.0
    tailaff = '%.2f' % tailrep1 +'  Mo'
    
def Trt_Erreur(nberr,ficherr) :
    fen2=Toplevel()
    fen2.title("CompactImages : Erreurs de traitement")
    labf2=Label(fen2,text=str(nberr)+'  images ne pouvant être traitées \n (Images peut-être en lecture seule)', fg='blue', font=('Arial', 9))
    labf2.pack(side=TOP,pady=10)
    fram4=Frame(fen2,borderwidth=0)
    scrollf2 =Scrollbar(fram4,orient=VERTICAL)
    listf2 = Listbox(fram4,bg='yellow',width=60,height=15,selectmode='single', yscrollcommand=scrollf2.set)
    scrollf2.config(command  =  listf2.yview)
    scrollf2.pack(side=LEFT,fill=Y)
    listf2.pack(side=LEFT)
    fram4.pack()
    bouf2=Button(fen2,text="Fermer",bg='brown',fg='white', command=fen2.destroy)
    bouf2.pack(side=BOTTOM,pady=10)
    for x in ficherr :
        listf2.insert(END,x)

def Affich_Infos() :	
    feninf = Toplevel()
    feninf.config(bg='lightblue')
    feninf.geometry("400x250+400+220")
    feninf.title("À propos de CompactImages")
    labinf=Label(feninf,bg='lightblue', fg='black',width=50,font=('Arial', 9),
        text= "\nCompactImages v.1.3\n\n"
                "Programme écrit en Python / Tkinter \n"
                 "et distribué sous licence GNU GPL.\n\n"
                "© 2007  Yves Le Chevalier\n\n"
                "Ce programme compacte toutes les images JPG (jpeg)\n"
                "d'un répertoire donné, sans modifier leurs qualités ni\n"
                 "réduire leurs tailles. Il n'affecte pas les images déjà\n"
                 "compactées, ni les images en lecture seule.")
    labinf.pack(pady=5)
    bouf3=Button(feninf, text="Fermer", command=feninf.destroy,bg="orange", fg='brown')
    bouf3.pack(side=BOTTOM,pady=10)
	
# main
fen1 = Tk(className='Compacteur images JPEG   v1_2')
fen1.geometry("500x750+350+200")
fen1.resizable(width=False, height=False)
can1 = Canvas(fen1, width=20, height=20, bg='lightgrey')
signat=PhotoImage(file='YLC.gif')
sign=can1.create_image(12,12, image=signat)
can1.pack(side=BOTTOM,anchor=E)

fram1=Frame(fen1,borderwidth=0)
button2 = Button(fram1, text = '', command = Exploration,state=DISABLED,relief=FLAT)
button2.grid(row=0,column=0,pady=10)
bouinf=Button(fram1,text="A propos", bg="#A6D6A6", fg='blue',command=Affich_Infos)
bouinf.grid(row=0,column=1,padx=80)
bouf1=Button(fram1,text="Quitter", command=fen1.destroy,bg="pink", fg='brown')
bouf1.grid(row=0,column=2)
fram1.pack(side=TOP)

fram2=Frame(fen1,borderwidth=0)
lab1=Label(fram2,text='Liste des fichiers images (Jpg ou Jpeg) à compacter', fg='blue', font=('Arial', 10))
lab1.pack(side=TOP)
lab1b=Label(fram2,text='(Cliquer sur une image pour la visualiser)', fg='black', font=('Arial', 8))
lab1b.pack()
scrolly =Scrollbar(fram2,orient=VERTICAL)
list1 = Listbox(fram2,bg="#A0D0C0",width=70,height=35,selectmode='single', yscrollcommand=scrolly.set)
scrolly.config(command  =  list1.yview)
scrolly.pack(side=LEFT,fill=Y)
list1.pack()
fram2.pack()

fram3=Frame(fen1)
lab3=Label(fram3,fg='blue',font=('Arial', 9))
lab3.grid(row=0,column=0,padx=5)
lab2=Label(fram3,fg='blue',font=('Arial', 9))
lab2.grid(row=0,column=1,padx=15)
button1 = Button(fram3, text = '', command = Validation)
button1.grid(row=0,column=2,padx=35,pady=5)
fram3.pack()

fram5=Frame(fen1)
lab4=Label(fram5,fg='black', font=('Arial', 11))
lab4.grid(row=0,column=0,pady=5)
lab5=Label(fram5,fg='blue', font=('Arial', 9))
lab5.grid(row=0,column=1,padx=20)
lab6=Label(fram5,fg='blue', font=('Arial', 9))
lab6.grid(row=1,column=1)
lab7=Label(fram5,fg='red', font=('Arial', 9))
lab7.grid(row=1,column=0)
fram5.pack()

Exploration()
fen1.mainloop()

Conclusion

Bien que ce ne soit pas un programme compliqué (C'est mon second programme en python), je le trouve très utile et je peu maintenant stocker plus de mille de mes photos sur un clé USB de moins d'un giga.
Ce programme est compatible avec la compilation py2exe sous windows et c'est sous cette forme que je le donne à mes amis.
Pour les "Membres Club", vous pouvez télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip

11 décembre 2007 19:18:01 :
En travaillant sur des répertoire de plusieurs centaines de photos, je trouvais le temps long et ne savais pas où le traitement en était rendu. J'ai donc ajouté une barre de progression (avec TIX). Attention à la compile sous windows avec py2exe, il manque les DLL Tix dans python 2.5 à récupérer à cette adresse: http://python.developpez.com/faq/?page=TkinterPrerequis (Merci à Guillaume Duriaud) Il faut aussi modifier le setup.py : voir à cette adresse: http://www.py2exe.org/index.cgi/TixSetup
  • signaler à un administrateur
    Commentaire de Lapou le 11/06/2008 12:57:52

    Bonjour,

    Cette "outil" m'intéresse fortement sauf que je ne parviens pas à le faire tourner, il semble que j'ai un problème avec PIL qui ne serait pas reconnu !
    Pourriez-vous m'aider ou même mettre à dispo l'exécutable windows :-)

    Merciiiiiiiiiiiiiiiiii

  • signaler à un administrateur
    Commentaire de yveslc le 12/06/2008 09:24:46

    Bonjour lapou,
    Encore faut-il télécharger la bibliothèque PIL pour l'utiliser. Pour avoir un package Windows, je n'ai jamais trouvé de site où les mettre. Si tu en connais un qui accepte d'uploader un gros ZIP indique le-moi. merci.
    YLC

  • signaler à un administrateur
    Commentaire de Lapou le 12/06/2008 13:45:42

    merci yveslc :-) je ne connais pas du tout pyhon donc j'ai eu la flemme de chercher !

    Merci

  • signaler à un administrateur
    Commentaire de Lapou le 12/06/2008 16:33:49 9/10

    Bon ça y'est j'ai réussi pour TIL ainsi que pour la progressbar :-)

    Cela fonctionne en utilisant le CompactImages.py.
    Je créer donc l'exécutable avec py2exe, et quand je lance le CompactImages.exe dans dist j'ai l'invite de commande pendant 1sec puis il disparait mais pas d'action !

    Merci de votre aide.

  • signaler à un administrateur
    Commentaire de yveslc le 13/06/2008 14:33:29

    Bonjour,
    as-tu pensé à mettre le fichier YLC.gif dans le répertoire où se trouve ton exécutable ?

  • signaler à un administrateur
    Commentaire de Lapou le 16/06/2008 09:48:38

    Bonjour,

    Effectivemment c'était bien cela !
    Je n'avais pas vu que le fichier ne s'était pas mis dans le dossier avec la création avec py2exe !

    Merci,
    @+

  • signaler à un administrateur
    Commentaire de Lapou le 16/06/2008 09:54:11

    Re Yves,

    Et donc logiquement je n'ai plus qu'à copier le dossier dist sur d'autres PC pour pouvoir utiliser ce magnifique outil ?

    Merci
    @+

  • signaler à un administrateur
    Commentaire de Lapou le 16/06/2008 14:20:10

    Re salut à tous !

    Je vous conseille vraiement cette source, yslc a vraiement fait un super boulot !!!
    La prochaine évolutions serait peut-être de pouvoir sélectionner plusieurs dossiers ? Car quand on a "cumulé" des dizaines de dossiers de photos, il n'y a pas d'autres possibilités que de lancer la source dossier par dossier,...
    Puis il serait peut-être intéressant d'avoir la possibilité d'inclure les sous-dossiers ou pas (au choix via une checkbox par exemple) ?

    Qu'en pensez-vous ?  N'ayant aucune connaissance en Python, voir même dans d'autres langages (oups), je suis incapable de réaliser ces évol' !

    Par avance merci,
    @+

  • signaler à un administrateur
    Commentaire de yveslc le 17/06/2008 08:37:27

    Bonjour,
    Effectivement c'est une possibilité, bien que si on s'organise bien ce n'est pas nécéssaire. Je m'explique : quand je remonte des photos sur mon ordi, je passe systématiquement par un dossier de travail sur lequel j'applique le compactage et que je reprend ensuite dans Picassa pour ventiler mes photos dans les dossiers destinataires finaux.
    De toutes façons, je n'écris pas de code à la belle saison, c'est pour passer l'hiver, quand on ne peut pas beaucoup sortir faire du vélo ou de la rando.....
    A+
    YLC
    PS : j'aurais aimé (pour ceux qui ne connaissent pas Python) pouvoir mettre la librairie exécutable sous Windows sur le net, mais je n'ai pas trouvé de site qui propose de téléchager des appli toutes faites.

Ajouter un commentaire

Discussions en rapport avec ce code source

Pub



Appels d'offres

Recherche developpeur ...
Budget : 700€
SITE MARCHAND LOCATION...
Budget : 3 000€
SITE MARCHAND POUR HOTEL
Budget : 4 000€

CalendriCode

Août 2008
LMMJVSD
    123
45678910
11121314151617
18192021222324
25262728293031

VS Express FR Gratuit !

VS Express en français et 100% gratuit !

Boutique

Boutique de goodies CodeS-SourceS