mercredi 20 mars 2013

Création de l'IHM en C# - Etape 3

Nous constatons que le bouton "Lancer l'import" est toujours désactivé.

Code

Nous allons créer une méthode afin de vérifier que les 2 dossiers sont bien sélectionnés et dans ce cas, nous allons activer le bouton.

private void checkImportButton()
{
    if ("" != srcText.Text && "" != destText.Text)
    {
        execBtn.Enabled = true;
    }
    else
    {
        execBtn.Enabled = false;
    }
}

Maintenant nous allons appeler cette méthode dans les 2 méthodes btn_Click

private void destButton_Click(object sender, EventArgs e)
{

    //Au clic, on créé le FolderBrowserDialog
    FolderBrowserDialog dialog = new FolderBrowserDialog();
    //on l'affiche
    dialog.ShowDialog();

    //on passe le dossier selectionné dans la valeur du champs text
    destText.Text = dialog.SelectedPath;
    
    checkImportButton();
}

Exécution


Nous allons relancer l'application avec un CTRL+F5 puis sélectionner les 2 dossiers. Nous voyons que le bouton "Lancer l'import" est désormais actif. Mais ce dernier ne fait rien. Il va falloir de la même façon ajouter un gestionnaire d’évènement dessus.


Création de l'IHM en C# - Etape 2

Nous avons désormais une interface mais aucune action n'est affectée aux différents boutons.

Sélection d'un dossier.


La première chose à faire est d'ajouter un listener d’évènement sur le bouton de sélection du dossier source.
Pour cela il suffit de double cliquer sur le bouton

Cela va faire 2 choses :

Créer la méthode suivante :
private void srcButton_Click(object sender, EventArgs e)
{

}

et ajouter la ligne suivante à la définition du bouton.

this.srcButton.Click += new System.EventHandler(this.srcButton_Click);

Il va maintenant falloir ajouter la selection du dossier source au clic sur le bouton. Pour cela nous allons utiliser la classe FolderBrowserDialog

private void srcButton_Click(object sender, EventArgs e)
{
    //Au clic, on créé le FolderBrowserDialog
    FolderBrowserDialog dialog = new FolderBrowserDialog();
    //on l'affiche
    dialog.ShowDialog();

    //on passe le dossier selectionné dans la valeur du champs text
    srcText.Text = dialog.SelectedPath;
}

Execution

Faire CTRL+F5 et la fenêtre suivante s'affiche.


Maintenant, nous allons cliquer sur le 1er bouton "Sélectionner" et la fenêtre suivante doit s'afficher.


Nous sélectionnons un dossier et l'on peut voir que le chemin s'affiche désormais dans le champs texte associé.


Nous allons répéter la même opération avec le 2e bouton afin de sélectionner le dossier cible.


private void destButton_Click(object sender, EventArgs e)
{

    //Au clic, on créé le FolderBrowserDialog
    FolderBrowserDialog dialog = new FolderBrowserDialog();
    //on l'affiche
    dialog.ShowDialog();

    //on passe le dossier selectionné dans la valeur du champs text
    destText.Text = dialog.SelectedPath;
}

Nous pouvons désormais sélectionner le dossier source et le dossier cible.

Création de l'IHM en C# - Etape 1


Création du projet.

C'est bien gentil d'avoir des méthodes, encore faut-il pouvoir les utiliser.
Pour cela nous allons créer un nouveau projet mais cette fois, pas en mode console mais en mode "Application Windows Forms" que l'on va nommer imagesBrowser.

Création de l'interface

Nous arrivons alors sur une page qui va nous permettre de "dessiner" l'interface.

Nous allons avoir besoin de :

  * 1 bouton pour selectionner le répertoire où se trouvent les images à copier.
  * 1 bouton pour selectionner le répertoire où nous allons copier les images.
  * 2 zones texte pour afficher les reprtoires selectionner.
  * 2 labels pour expliquer les zones.
  * 1 bouton pour lancer l'execution du code.

Pour cela il suffit d'aller dans la partie à droite nommée "Boite à outil" et déposer en drag'n drop les éléments nécéssaire.

Pour modifier les propriétés tel que défini ci-dessous, il faut faire un click droit sur l'élément et aller tout dans bas cliquer sur "Propriétés"

Button 1 : 
 - name : srcBtn
 - autoSize : true
 - text : Sélectionner
   
Button 2 : 
 - name : destBtn
 - autoSize : true
 - text : Sélectionner

Button 3 :

 - name : destBtn
 - autoSize : true
 - enable : false
 - text : Lancer l'import
 
Textbox 1 :
 
 - readonly : true
 - name : srcText

Textbox 2 : 
 
 - readonly : true
 - name : srcText 

Label 1 :

 - text : Dossier source
 
Label 2 :

 - text : Dossier cible
            
Je vous laisse faire mumuse avec l'outil pour obtenir un look proche de ceci.              


mardi 19 mars 2013

Etape intermédiaire

Voilà nous avons pour les 3 langages :

  • Une méthode de récupération des images.
  • Une méthode de lecture des données exif
  • Une méthode de copie de fichiers
Avec ces 3 méthodes on peut déjà commencer à faire une première application. Pour cela, il va falloir organiser tout cela et créer une première IHM

Copie des fichiers

L'étape suivante sera de copier (ou déplacer) les fichiers vers leur destination.

Java

Code

Je vais utiliser l'API common-IO d'apache qui permet de gérer simplement la copie de fichier. Cette API créé les dossiers si elle n'existe pas et gère correctement les exceptions.

for (String file : listImage) {
 File targetFile = fs.getImageNameFromExif(file);
 if (targetFile != null) {
  try {
   FileUtils.copyFile(new File(file), targetFile);
  } catch (IOException e) {
   fs.error.append(e.getMessage());
  }   
 }
}

Résultat

C'est long ! 12 minutes de copie. Il y a 10 Go de données. Je testerais par la suite combien de temps un simple copier / coller prendrais. 

PHP

Code

Pas besoin d'aller chercher loin. La fonction copy suffira.

//On parcours les images.
foreach ($fs->listImages as $file) {

  //On récupère le chemin cible et le nom de fichier
  $target = $fs->getImageNameFromExif($file);
  
  //On créé le dossier cible
  $dir = $targetBase."/".$target["dir"];
  if (!file_exists($dir)) {
    mkdir($dir, 0777, true);
  } 
  
  //On copy le fichier à proprement parlé
  $targetPath = $dir."/".$target["src"];
  if (!copy($file, $targetPath)) {
    array_push($err, "cannot copy ".$file." to ".$targetPath);
  } 
}


Résultat

Attention, avant d’exécuter  penser à bien supprimer les fichiers copiés par la précédente méthode en java, sans quoi le test serait différent.

C'est long aussi ! 11 minutes, c'est un peu mieux mais au final comme la récupération des données EXIF prenait 1 minutes de plus on arrive à la même performance.

C#

Code

Je vais utiliser la class FileSystem qui a l'avantage de créer les répertoires manquants.

foreach (string file in p.files)
{
    string target = p.getImageNameFromExif(file);
    FileSystem.CopyFile(file, target, true);
}

Résultat

C'est un peu mieux, on est à 8 minutes environ. Ca reste long mais c'est tout de même 1/3 de moins que le java.

Bilan

Au final le C# est le plus performant. Malgré un moins bon temps pour la lecture des données EXIF les performances liées aux accès file system ce langage est en tête même si les différences ne sont pas flagrante avec peut être le PHP en peu en retrait.

Pour info un copier / coller de l'ensemble de ces images a pris un peu plus de 7 minutes.

Bilan "Données EXIF"

J'ai passé ma fonction de récupération des données EXIF pour les 6850 fichiers listées par la précédente méthode.

Les résultats sont très variés.

  1. Java gagne avec un temps d'exécution de 75s
  2. PHP est deuxième avec un temps de 120s
  3. C# est bon dernier avec un temps de 350s
Honnêtement je pense que le mauvais temps de c# est plus lié à une mauvaise implémentation de ma part que d'un soucis de langage. Je pense que je charge l'image entière alors que seul le header suffirait. Je vais essayer de trouver une meilleure implémentation afin de refaire ce test, car dans ces conditions je serais obligé d'éliminer ce langage mais je doute que l'on ne puisse pas trouver mieux.

Mise à jour

J'ai trouvé un portage de l'API Metadata Extractor en C#
C'est mieux mais on reste à un temps d’exécution de 110s. Cela fait donc en moyenne 5ms de plus par image. Ce n'est pas énorme mais avec le grand nombre cela fait tout de même une différence significative.


lundi 18 mars 2013

[C#] - Données EXIF

Là j'ai un peu plus galéré. J'ai du pas mal chercher sur le net pour trouver comment récupérer les données exif.

J'ai trouvé quelques librairie mais la complexité était trop grande, que j'ai décidé de coder moi même (en m'aidant d'exemples du site msdn) la fonction de récupération.

Code

public void getImageNameFromExif(string imagePath)
        {

            //On charge la photo
            Bitmap photo = new Bitmap(imagePath);

            //On récupère les metadata
            PropertyItem[] pi = photo.PropertyItems;
            
            //On récupère la date (voir exif.org pour le code/tag Original DateTime)
            PropertyItem dateItem = photo.GetPropertyItem(36867);

            //On récupère la valeur de la propriété
            Encoding ascii=Encoding.ASCII;
            string dateString = ascii.GetString(dateItem.Value, 0, dateItem.Len - 1);
            
            //On convertit la chaine de caractère récupérée en DateTime
            string format = "yyyy:MM:dd hh:mm:ss";
            DateTime date = DateTime.ParseExact(dateString, format, CultureInfo.InvariantCulture);

            //On génère le nom du fichier. 
            string format_out = "{0:yyyy/MM/dd/yyyyMMdd_hhmmss}";
            String outFile = String.Format(format_out, date);
            String targetPath = this.basePath + "/"  + outFile + ".jpg";

            //On affiche pour debug
            Console.WriteLine(targetPath);
           
        }

Là non plus, ce n'est pas trop compliqué mais sans aide, il serait impossible de trouver seul certaines 'astuces'

[PHP] - Données EXIF

La lecture des données EXIF existent en php lorsque l'on active l'extension exif.

Le code pour récupérer la date est assez simple et efficace.


  function getImageNameFromExif ($imagePath) {
  
    //On récupère les données EXIF
    $exif = exif_read_data($imagePath, 'EXIF', true);
    //On récupère la donnée qui nous interesse
    $dateStr = $exif['EXIF']['DateTimeOriginal'];
    //on parse la date
    $arr_date = date_parse_from_format ( "Y:m:d H:i:s" , $dateStr );
    
    //on genere le nouveau nom de fichier.
    $file =  $arr_date["year"]."/".
            $this->formatNine($arr_date["month"])."/".
            $this->formatNine($arr_date["day"])."/".
            $this->formatNine($arr_date["year"]).$this->formatNine($arr_date["month"]).$this->formatNine($arr_date["day"])."_".
            $this->formatNine($arr_date["hour"]).$this->formatNine($arr_date["minute"]).$this->formatNine($arr_date["second"]).".jpg";

    print($file);            
    
  }
  
  function formatNine($num) {
    return ($num < 10)? "0".$num : $num;
  }

Le résultat est le même qu'en Java. Là encore des ajustements seront nécessaires afin de gérer les cas limites.

[Java] - Données EXIF


Il n'y a pas d'implémentation native des données EXIF en java (ou alors je ne la connais pas)

Je vais donc utiliser une librairie que j'ai déjà utilisé auparavant et qui m'a donné satisfaction : metadata-extractor

Je ne vais pas expliquer ici comment ajouter une librairie au build path mais vous trouvez cela sur l'ensemble des tutos débutants.

1ere Etape lecture des données EXIF

public void getImageNameFromExif(String imagePath) {
 
  //on récupère le metadata reader.
  File jpegFile = new File(imagePath);
  try {
   Metadata metadata = JpegMetadataReader.readMetadata(jpegFile);
   
   //On récupère le 'dossier exif' 
   ExifSubIFDDirectory directory = metadata.getDirectory(ExifSubIFDDirectory.class);
   
   //On récupère la date originale de prise de vue
   Date date = directory.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL);
   
   if (date == null) {
    System.out.println("no date");
   }
   
   //On formatte la date
   SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/yyyyMMdd_hhmmss");
   
   //On créé le fichier cible.
   File targetPath = new File(this.baseTarget + "/" 
     + 
     sdf.format(date)
     + ".jpg");
   
   System.out.println(targetPath.getAbsolutePath());
   
   
  } catch (ImageProcessingException e) {
   //e.printStackTrace();
   System.out.println("1 : " + e.getMessage());
  } catch (IOException e) {
   System.out.println("2 : " + e.getMessage());
  }
  
 }
L’exécution de cette méthode avec le code suivant :

fs.getImageNameFromExif("C:\\Users\\Reno\\Pictures\\2010-05-08\\IMG_0059.JPG");
retourne la valeur suivante :

C:\dev\export\2010\04\08\20100408_110249.jpg

Nous étions ici dans le cas parfait.

Essayons avec un fichier non jpeg (un simple fichier texte renommé jpg par exemple)

L'exception ImageProcessingException est levée avec le message "not a jpeg file"
Ce cas là est simple à gérer : Il suffit de ne rien faire. Ce sera la même chose si le fichier n'existe pas.

Maintenant essayons un fichier Jpeg qu'il n'a pas de données EXIF.
Dans ce cas la date sera null et nous aurons un nullPointerException. Dans ce cas il faudra récupérer les données autrement.


Lecture des données EXIF et renommage des fichiers.

Nous allons utiliser les données EXIF et en particulier la date originale de prise de vue pour générer une arborescence de type :

AAAA / MM / JJ ce qui permettra d'accèder facilement aux images par la suite.

Nous allons également renommer l'image AAAAMMJJ_HHmmSS.EXT

Exemple une photo prise à 11:33:45 le 18 Mars 2013 sera représentée de la façon suivante :

2013
  |_03
    |_18
      |_20130318_113345.JPG
      |_20130318_113427.JPG
      |_20130318_113512.JPG


Il faut prendre en compte plusieurs difficultés :

 - Les données EXIF pourraient ne pas exister. Il faudra dans ce cas utiliser la date de création du fichier qui est moins fiable, car modifiable.

 - Un fichier avec le même peut déjà exister. Plusieurs raisons peuvent expliquer cela :

    C'est le même fichier => Il ne faut pas le copier.
    Ce n'est pas le même fichier => il faut le copier.
 
Comme à chaque fois, je vais commencer en Java, pooursuivre en PHP et terminer en C#  

Bilan "Récupération des images"


Tout d'abord les 3 langages permettent assez simplement de récupérer les images en quelques lignes de code. Le C# est le langage qui permet de le faire le plus simplement à mon avis alors que c'est le langage que je connais le moins.

Code Java - Code PHP - Code C#

Bien entendu en Java il existe des librairies permettant la même chose (comme le common d'Apache) mais cela nécéssite une connaissance plus accrue du langage

Nous allons maintenant comparer les performances grace à des 'timer'

  JAVA  : 6847 fichiers JPG - 1469 ms
  PHP   : 6847 fichiers JPG - 2158 ms
  C#    : 6847 fichiers JPG - 213 ms
Alors déjà la bonne nouvelle c'est que les 3 langages retournent le même nombre de fichiers.

Ensuite le Java et le PHP sont assez rapide (1,5 à 2 s) mais sont littéralement explosés en terme de temps d'éxecution par le C#

Par curiosité, je vais tester l'API commons-IO d'Apache

public void fi(String basePath, boolean recursive) {
  
   this.itImages = FileUtils.listFiles(new File(basePath), new String[]{"jpg","JPG"}, recursive);
    
}
 

On arrive ici à une simplicité de code équivalente au C# mais le temps mesuré reste autour de 1,5s soit 7 fois plus qu'en C#

Je n'avais jamais testé mais je suis sidéré par ces différences !

Du point de vue de la simplicité et des performances, le C# sort grand gagnant de ce 1er match.

[C#] - Méthode de récupération des images.

Implémentation en C#


Pour moi c'est la grande inconnue. Après quelques craintes, je me suis aperçu qu'il était très simple de réaliser cette opération. (Plus simple même qu'en Java ou PHP)

Code


using System;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {

        private string[] files;
       

        public void listDir(string basePath, bool recursive)
        {
            //On récupère tous les fichiers de type JPG dans l'ensemble des sous répertoires.
            if (recursive)
            {
                this.files = Directory.GetFiles(basePath, "*.JPG", SearchOption.AllDirectories);
            }
            else
            {
                this.files = Directory.GetFiles(basePath, "*.JPG", SearchOption.TopDirectoryOnly);
            }
        }

        static void Main(string[] args)
        {
            Program p = new Program();
            p.listDir("C:\\Users\\Reno\\Pictures", false);
            foreach (string file in p.files)
            {
                Console.WriteLine(file);

            }
            Console.ReadKey();
        }
    }
}


[PHP] - Méthode de récupération des images.

Implémentation en PHP


Nous allons maintenant passer à la méthode en PHP. Utilisant PHP5 et faisant cette application en langage object nous allons également implémenter la méthode en POO en PHP, même si nous aurions pu le faire mode script.

Code

Nous allons essayer de coller au plus au code java précédemment codé.
class FilesService {

  public $listImages = array();
   
  function listDir($basePath, $recursive) {
    
    // on vérifie qu'il s'agit bien d'un répertoire.
    if (is_dir($basePath)) {  
      
      //On 'ouvre' le répertoire. (récupération d'un pointeur, lire la doc pour plus d'infos)
      $fs = opendir($basePath); 
      
      
      //On parcours maintenant les fichiers/répertoires 
      while (($file = readdir($fs)) !== false) {
        
        //Si on est sur un sous répertoire on appelle la fonction de manière récursive.
        $fullPath = $basePath."/".$file;        
        if (is_dir($fullPath) && $recursive) {
          
          //on évite ainsi les boucles infinies.
          if ($file != "." && $file != "..") {       
            $this->listDir($fullPath, $recursive);
          }
        }
        else {
          //on est dans le cas d'un fichier.
          //On vérifie qu'il s'agit bien d'une image jpeg.                   
          
          if (strtoupper(substr($file, strrpos($file,".")+1)) == "JPG") {
            //Alors on l'ajoute à la liste (array ici)
            array_push($this->listImages, $fullPath);        
          }
        }
      }
    }
  }
  
}

De la même manière qu'en java le test sur le type de fichier n'est pas très fiable mais cela est également suffisant pour commencer.

[JAVA] - Méthode de récupération des images.


Nous allons commencer l'implémentation de l'application de traitement des images. Le principe est assez simple : Nous allons faire une méthode prenant en entrée un chemin d'accès et parcourant les dossiers de manière récursive (ou non) afin d'y trouver les photos.

Implémentation en Java


Je commence en Java, car c'est pour moi le langage que je connais le mieux et pour lequel je ne vais pas rencontrer de problème de syntaxe ou de connaissance d'API.

Code


package com.tuto.services;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;

public class FilesService {
 
 private ArrayList listImages = new ArrayList();

 /**
  * 
  * @param basePath : Chemin où se trouvent les images.
  * @param recursive : Doit-on parcourir les sous-dossiers.
  * 
  */
 public void listDir(String basePath, boolean recursive) {
  
  //On créé un object File à partir du chemin en paramètre.
  File baseFile = new File(basePath);
  
  //On test l'existance physique du répertoire.
  if (!baseFile.exists() || !baseFile.isDirectory()) {
   return;
  }
  
  //On récupère les fichiers et les sous-répertoires du dossier courant
  File[] listFiles =  baseFile.listFiles(new FileFilter() {
   
   @Override
   public boolean accept(File f) {
    //On ne récupère que les fichiers jpg/JPG et les répertoires.
    return (f.isDirectory() || f.getName().toUpperCase().endsWith(".JPG"));
   }
   
  });
  
  //On parcours désormais la liste des File
  for (File file : listFiles) {
   
   //Si le File est un répertoire, alors on appelle 
   //récursivement la fonction avec le chemin du sous-répertoire.
   
   if (file.isDirectory()) {
    listDir(file.getAbsolutePath(), recursive);
   }
   else { //Sinon on ajoute l'image dans l'ArrayList
    listImages.add(file);
   }
   
  }
  
 }
 
 /**
  * Methode de test. 
  * @param args : not used
  * 
  */
 public static void main(String[] args) {
  FilesService fs = new FilesService();
  fs.listDir("C:\\Users\\Reno\\Pictures", true);
 }
 
}



Cette méthode va donc nous retourner une liste de fichier de type Jpeg. La méthode de vérification du type est à améliorer pour plusieurs raisons :

 - Un fichier avec une extension JPG/jpg n'est pas forcément une image
 - Il y a des images non JPG/jpg donc toutes les images ne seront pas listées.

Pour commencer, cela suffira, nous affinerons pas la suite.

C'est à partir de cette liste que nous allons renommer / copier et transférer les images.

dimanche 17 mars 2013

"Hello World" : Conclusion

Clairement, le PHP est le plus simple à prendre en main. 1 seule ligne de code, pas de compilation. Java et C# sont assez proche à prendre en main. Je connais mieux le Java et Eclipse donc c'est plus simple pour moi mais je ne pense pas qu'il y ait de réelle différence de complexité.

1er "Programme" C#

C#


Pour moi, là c'est une découverte totale donc je ne garantie pas que ce soit dans les règles de l'art.

Création du projet.

  • Dans visual C# aller dans Fichier > Nouveau Projet
  • Sélectionner Application Console

Code

Normalement, la structure de la classe est automatiquement créée. Il n'y a plus qu'a l'implémenter.

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World");
            Console.ReadKey();
        }
    }
}


Execution

Faire CTRL + F5
Une console DOS doit s'ouvrir, et Hello World s'afficher. La fenêtre se fermera dès la moindre touche pressée.

1er "Programme" - PHP

PHP

Création du projet


Pour créer notre "Hello World" en PHP après avoir installé EasyPHP et l'avoir lancé nous allons aller dans "Administration"

Là nous allons ajouter un Alias, qui pointera vers un répertoire où seront stockés nos fichiers.

Dans mon exemple mon Alias se nommera "tuto" et pointera vers "C:\dev\php\tuto"

Ensuite nous pourrons accéder à la webapp via l'adresse "http://localhost:8888/tuto"

Création du script

  • Créer le fichier HelloWorld.php
  • Entrez le code suivant

  • <?php
    
      print("Hello World");
    
    ?>
    
  • Sauvez le fichier.

Exécution 

entrez l'adresse : http://localhost:8888/tuto/HelloWord.php

1er "Programme" - Java

Afin de vérifier le bon fonctionnement de chaque environnement, nous allons créer un petit "Hello World" pour chaque langage.

Java

Création du projet

File > New > Java Project puis entrer le nom du nouveau projet. (Tuto ici)


Création de la classe Hello World

Dans l'explorateur de projet, selectionner "src" et faire un clic droit puis New > Class

et entrez : 
  • com.tuto.tests dans Package
  • HelloWorld dans Name

Code

Nous allons entrer ce simple code pour vérifier le bon fonctionnement de l'environnement.

package com.tuto.tests;

public class HelloWorld {

 public static void main(String[] args) {
  
  System.out.println("Hello World");
  
 }
}

Execution

Il suffit de faire un clic droit sur la class puis 'Run As' > 'Java Application'

Ensuite, la console s'ouvre et affiche "Hello World"

Voilà, l'environnement Java est fonctionnel.

Environnement C#

Pour C# je vais utiliser Visual C# 2010 Express

Comme les autres, c'est gratuit mais il faut d'identifier et enregistrer sa version. Le bonheur de bosser avec des outils Microsoft ...


Environnement PHP

Contrairement au 2 autres langages, le PHP ne permet de faire d'interface utilisateur (IHM) nativement, nous allons passer par une webapp pour gérer tout cela. 

Afin de me faciliter les taches d'installation, j'ai utilisé EasyPHP qui est un WAMP (Windows, Apache, Mysql, PHP) qui installe tout d'un coup.


Environnement Java

Pour l'environnement Java, je vais utiliser :


C'est pour l'instant tout ce dont je vais avoir besoin.
On peut bien évident faire d'autre choix, mais ayant déjà ces éléments installés je me contente de cela.


Concept


Je créé ce petit blog pour vous faire en temps réel l'implémentation d'une même application en 3 langages différents :

 - C# (c-sharpe) que je ne connais pas.
 - PHP que je connais un peu mais pas dans les profondeurs
 - Java, langage que j'utilise tous les jours dans mon boulot mais spécialisé en J2EE donc je ne maîtrise pas les IHM

Pourquoi me direz vous ? D'abord pour apprendre, à 37 ans il est parfois dur de se mettre un coup de pied aux fesses et d'essayer de repartir sur des technos que l'on ne maîtrise pas. Ayant actuellement un peu de temps je voudrais en profiter pour me refaire une santé technique un peu laissée au placard avec de la gestion de projet.

Le cahier des charges sera le suivant :

Créer une application qui :

  - récupérera les images d'un APN ou autre périphérique externe, les classera et les renommera en fonction des données EXIF.
  - Ne devra pas récupérer les images déjà récupérées.
  - Proposera l'option d'uploader ces images sur Flickr

Je ne vais bien entendu pas tout coder. Je vais utiliser des API ou Librairies existantes afin de ne pas réinventer la roue.

La première étape sera l'installation des environnements de développement.