diff --git a/PlaningDeTavail.md b/PlaningDeTavail.md index de5c589..c2281f2 100644 --- a/PlaningDeTavail.md +++ b/PlaningDeTavail.md @@ -1,3 +1,197 @@ +<<<<<<< HEAD +# Sprint Planning – Projet PIF + +## Légende +AD → Algassimou +AA → Ayoub +YB → Youness + +🟥 TODO = À faire +🟨 DOING = En cours +🟩 DONE = Terminé + + +# --------------------------------------- +# SPRINT 1 (13–20 décembre 2025) +# --------------------------------------- +Objectif : Mise en place des fondations techniques +(image, binaire, Huffman, canoniques) + +| US | Assigné | Statut | | Description | +|-------|---------|--------|----|----------------------------------------------------| +| US-D1 | AD | DONE | 🟩 | Implémenter BitInputStream (lecture bit par bit) | +| US-D2 | AD | DONE | 🟩 | Implémenter BitOutputStream (écriture bit par bit) | +| US-D3 | AD | DONE | 🟩 | Générer les tables de fréquences RGB | +| US-D4 | AD | DONE | 🟩 | Construire l’arbre Huffman | +| US-D5 | AA | DONE | 🟩 | Générer les codes Huffman | +| US-D6 | AA | DONE | 🟩 | Générer les codes canoniques | +| US-U5 | YB | DONE | 🟩 | Chargement d’image via ImageIO | +| US-D8 | YB | DONE | 🟩 | Structure RGBImage + Pixel | +| US-P1 | AA | DONE | 🟩 | Interface simple d’affichage des fréquences | +| US-P2 | AD | DONE | 🟩 | Interface simple d’affichage codes Huffman | +| US-P3 | AA | DONE | 🟩 | Interface simple d’affichage codes canoniques | + +## Fichiers à créer – Sprint 1 + +### `src/mimage/` +| Nom du fichier | Rôle | US | +|----------------|-------|----| +| `Pixel.java` | Représente un pixel (r, g, b) | US-D8 | +| `RGBImage.java` | Matrice de pixels + utilitaires | US-D8, US-U5 | + +### `src/mhuffman/` +| Nom du fichier | Rôle | US | +|----------------|-------|----| +| `FrequencyTable.java` | Stocke les fréquences R/G/B | US-D3 | +| `HuffmanNode.java` | Nœud d’arbre Huffman | US-D4 | +| `HuffmanTree.java` | Construction arbre + génération des codes | US-D4, US-D5 | +| `CanonicalCode.java` | Génération des codes canoniques | US-D6 | + +### `src/util/` +| Nom du fichier | Rôle | US | +|----------------|-------|----| +| `BitInputStream.java` | Lecture bit par bit | US-D1 | +| `BitOutputStream.java` | Écriture bit par bit | US-D2 | +| `ByteUtils.java` | Conversion int octets | US-D3 et plus | +| `FileUtils.java` | Méthodes utilitaires fichiers | US-U5 (indirect) | + +### `src/vconverter/` +| Nom du fichier | Rôle | US | +|----------------|-------|----| +| `ConverterWindow.java` | Fenêtre du convertisseur | US-P1, US-P2, US-P3 | +| `PreviewPanel.java` | Aperçu de l’image chargée | US-U5 | +| `FrequencyTablePanel.java` | Affichage fréquences RGB | US-P1 | +| `CodeTablePanel.java` | Affichage Huffman + canoniques | US-P2, US-P3 | + +### `src/` (racine) +| Nom du fichier | Rôle | US | +|----------------|-------|----| +| `ConverterController.java` | Contrôleur du convertisseur | US-U5, US-D3..D6, US-P1..P3 | +| `Convertisseur.java` | Lancement du convertisseur | — | +--- + +### Résultat attendu Sprint 1 +- Compression entièrement fonctionnelle +- Import d’image opérationnel +- GUI minimaliste affichant fréquences / Huffman / canoniques +- Aucun fichier `.pif` encore écrit + + +# --------------------------------------- +# SPRINT 2 (20–27 décembre 2025) +# --------------------------------------- +Objectif : Écriture du format `.pif` + finalisation convertisseur + +| US | Assigné | Statut | | Description | +|------------|---------|--------|-----|-------------| +| US-D2 | AA | DONE | 🟩 | Vérifier BitOutputStream avec flux réel | +| US-C5 | AD | DONE | 🟩 | Implémenter PIFWriter (header + tables + pixels compressés) | +| US-U6 | AD | DONE | 🟩 | Exporter une image en `.pif` | +| US-P1 | AA | DONE | 🟩 | Finaliser affichage des fréquences | +| US-P2 | AA | DONE | 🟩 | Finaliser affichage codes Huffman | +| US-P3 | AA | DONE | 🟩 | Finaliser affichage codes canoniques | +| US-U7 | AD | DONE | 🟩 | Implémenter l’aperçu (PreviewPanel) | + +## Fichiers à créer – Sprint 2 + +### `src/mpif/` +| Nom du fichier | Rôle | US | +|----------------|-------|----| +| `PIFWriter.java` | Écriture du fichier `.pif` | US-C5, US-U6 | + +### `src/vconverter/` (complément) +| Nom du fichier | Rôle | US | +|----------------|-------|----| +| `SavePanel.java` en option a voir | Interface de sauvegarde `.pif` | US-U6 | + + +--- + +### Résultat attendu Sprint 2 +- `.pif` généré correctement +- Convertisseur fonctionnel à 80 % +- UI complète pour la consultation des tables +- Aperçu image fonctionnel + + +# --------------------------------------- +# SPRINT 3 (27 décembre 2025 – 3 janvier 2026) +# --------------------------------------- +Objectif : Lecture du fichier `.pif` + visualisateur opérationnel + +| US | Assigné | Statut | | Description | +|----------|---------|--------|-----|-------------| +| US-D7 | AD | DONE | 🟩 | Reconstruire les codes canoniques depuis fichier | +| US-D8 | AD | DONE | 🟩 | Décoder pixels (implémenter PIFReader) | +| US-U1 | YB | TODO | 🟥 | Ouvrir `.pif` via argument ou JFileChooser | +| US-U2 | AA | TODO | 🟥 | Afficher l’image dans une fenêtre | +| US-U3 | AA | TODO | 🟥 | Centrer l’image si elle est petite | +| US-U4 | AD | TODO | 🟥 | Déplacement de l’image à la souris | +| US-P6 | AA | TODO | 🟥 | Préparer diagrammes UML | + +## Fichiers à créer – Sprint 3 + +### `src/mpif/` +| Nom du fichier | Rôle | US | +|----------------|-------|----| +| `PIFReader.java` | Lecture et décodage du `.pif` | US-D7, US-D8 | + +### `src/vviewer/` +| Nom du fichier | Rôle | US | +|----------------|-------|----| +| `ViewerWindow.java` | Fenêtre visualisation | US-U2 | +| `ImagePanel.java` | Affichage + déplacement image | US-U2, US-U3, US-U4 | + +### `src/` +| Nom du fichier | Rôle | US | +|----------------|-------|----| +| `ViewerController.java` | Contrôle du visualisateur | US-U1..U4 | +| `Viewer.java` | Programme principal du visualisateur | US-U1 | + +--- + +### Résultat attendu Sprint 3 +- Visualisateur 100 % fonctionnel +- Lecture complète du format `.pif` +- Image affichée, centrée, déplaçable +- UML structurel prêt pour rapport + + +# --------------------------------------- +# SPRINT 4 (3–10 janvier 2026) +# --------------------------------------- +Objectif : Finalisation complète + livrable final + +| US | Assigné | Statut | | Description | +|------------|---------|--------|-----|-------------| +| US-P5 | AD | TODO | 🟥 | Javadoc complète | +| US-P7 | AD | TODO | 🟥 | Makefile (compilation + jar + exécution) | +| US-P6 | AA | TODO | 🟥 | Finalisation des diagrammes UML | +| Tests | YB | TODO | 🟥 | Tests convertisseur + visualisateur | +| Rapport | AD/AA/YB| TODO | 🟥 | Rédaction rapport complet | +| Livraison | AD/AA/YB| TODO | 🟥 | Vérification dépôt Gitea + JAR exécutables | + +## Fichiers à créer – Sprint 4 + +### Racine creee tout au long +| Nom du fichier | Rôle | +|----------------|-------| +| `Makefile` | Compilation + génération `.jar` | + +### `/doc` +| Nom du fichier | Rôle | +|----------------|-------| +| `rapport.pdf` | Livrable final | +| `UML/___.plantuml` | Sources de diagrammes | + +--- + +### Résultat attendu Sprint 4 +- Rapport PDF validé +- Diagrammes UML terminés +- Makefile opérationnel +- Projet soumis proprement sur Gitea +======= # Sprint Planning – Projet PIF ## Légende @@ -122,7 +316,7 @@ Objectif : Lecture du fichier `.pif` + visualisateur opérationnel |----------|---------|--------|-----|-------------| | US-D7 | AD | DONE | 🟩 | Reconstruire les codes canoniques depuis fichier | | US-D8 | AD | DONE | 🟩 | Décoder pixels (implémenter PIFReader) | -| US-U1 | YB | TODO | 🟥 | Ouvrir `.pif` via argument ou JFileChooser | +| US-U1 | YB | WP | 🟨 | Ouvrir `.pif` via argument ou JFileChooser | | US-U2 | AA | TODO | 🟥 | Afficher l’image dans une fenêtre | | US-U3 | AA | TODO | 🟥 | Centrer l’image si elle est petite | | US-U4 | AD | TODO | 🟥 | Déplacement de l’image à la souris | @@ -190,3 +384,4 @@ Objectif : Finalisation complète + livrable final - Diagrammes UML terminés - Makefile opérationnel - Projet soumis proprement sur Gitea +>>>>>>> 40f71dddd52fc07edc1d47d48d56fd65a2a79fe3 diff --git a/ProductBacklog.MD b/ProductBacklog.MD index 7e3e48e..7e78c61 100644 --- a/ProductBacklog.MD +++ b/ProductBacklog.MD @@ -1,90 +1,90 @@ -# PRODUCT BACKLOG — Projet PIF - - -# 1. US UTILISATEUR -Ce sont les besoins réels d’un utilisateur final qui voudrait simplement visualiser ou convertir une image. - ---- - -### **US-U1 — Ouvrir un fichier PIF** -En tant qu’utilisateur, je veux pouvoir ouvrir un fichier `.pif` via un argument ou un sélecteur de fichiers, afin d’afficher l’image. - -### **US-U2 — Afficher l’image dans une fenêtre** -En tant qu’utilisateur, je veux voir l’image affichée dans une fenêtre redimensionnable. - -### **US-U3 — Centrage automatique** -En tant qu’utilisateur, je veux que l’image soit centrée si elle est plus petite que la fenêtre, pour une meilleure visibilité. - -### **US-U4 — Déplacement de l’image** -En tant qu’utilisateur, je veux pouvoir déplacer l’image à la souris si elle dépasse la taille de la fenêtre. - -### **US-U5 — Charger une image RGB (PNG/JPEG)** -En tant qu’utilisateur, je veux charger une image standard afin de la convertir en `.pif`. - -### **US-U6 — Exporter une image au format PIF** -En tant qu’utilisateur, je veux enregistrer l’image sous format `.pif`. - -### **US-U7 — Aperçu de l’image avant conversion** -En tant qu’utilisateur, je veux voir une miniature de l’image chargée. - ---- - -# 2. US DÉVELOPPEUR -Ce sont les besoins techniques indispensables au fonctionnement interne du format PIF. - ---- - -### **US-D1 — Lire des bits depuis un flux** -Le système doit permettre la lecture bit par bit depuis un fichier PIF. - -### **US-D2 — Écrire des bits dans un fichier** -Le système doit permettre l’écriture de bits pour générer un fichier PIF. - -### **US-D3 — Construire les tables de fréquences RGB** -Le système doit analyser l’image pour obtenir les fréquences des valeurs R, G, B. - -### **US-D4 — Construire un arbre de Huffman** -Le système doit créer un arbre à partir des fréquences d’une composante. - -### **US-D5 — Générer les codes Huffman** -Le système doit produire les codes initiaux à partir de l’arbre. - -### **US-D6 — Générer les codes canoniques** -Le système doit transformer les codes Huffman en codes canoniques. - -### **US-D7 — Reconstruire les codes canoniques en lecture** -Le système doit pouvoir reconstruire les codes à partir des longueurs contenues dans le fichier .pif. - -### **US-D8 — Décoder un fichier PIF** -Le système doit pouvoir reconstituer l’image RGB à partir des données compressées. - ---- - -# 3. US PROFESSEUR (PEDAGOGIQUE) -Ces fonctionnalités n’ont **aucune utilité pour un utilisateur réel**, mais sont demandées par le professeur pour vérifier le bon fonctionnement de notre projet. - ---- - -### **US-P1 — Affichage des tables de fréquences** -En tant que professeur, je veux consulter la table de fréquences R, G et B pour vérifier que le calcul est correct. - -### **US-P2 — Affichage des codes Huffman** -En tant que professeur, je veux voir les codes Huffman générés afin de valider votre algorithme. - -### **US-P3 — Affichage des codes canoniques** -En tant que professeur, je veux visualiser les codes canoniques afin d’évaluer votre compréhension de leur construction. - -### **US-P4 — Affichage de l’arbre Huffman (optionnel)** -En tant que professeur, je veux pouvoir inspecter la structure de l’arbre pour vérifier votre implémentation. - -### **US-P5 — Documentation Javadoc pour chaque classe** -En tant que professeur, je veux avoir une documentation claire auto-générable. - -### **US-P6 — Diagrammes UML dans le rapport** -En tant que professeur, je veux retrouver un diagramme de classes et un diagramme d’objets dans le rapport. - -### **US-P7 — Makefile complet** -En tant que professeur, je veux pouvoir compiler les deux programmes en .jar exécutables avec un Makefile clair. - - - +# PRODUCT BACKLOG — Projet PIF + + +# 1. US UTILISATEUR +Ce sont les besoins réels d’un utilisateur final qui voudrait simplement visualiser ou convertir une image. + +--- + +### **US-U1 — Ouvrir un fichier PIF** +En tant qu’utilisateur, je veux pouvoir ouvrir un fichier `.pif` via un argument ou un sélecteur de fichiers, afin d’afficher l’image. + +### **US-U2 — Afficher l’image dans une fenêtre** +En tant qu’utilisateur, je veux voir l’image affichée dans une fenêtre redimensionnable. + +### **US-U3 — Centrage automatique** +En tant qu’utilisateur, je veux que l’image soit centrée si elle est plus petite que la fenêtre, pour une meilleure visibilité. + +### **US-U4 — Déplacement de l’image** +En tant qu’utilisateur, je veux pouvoir déplacer l’image à la souris si elle dépasse la taille de la fenêtre. + +### **US-U5 — Charger une image RGB (PNG/JPEG)** +En tant qu’utilisateur, je veux charger une image standard afin de la convertir en `.pif`. + +### **US-U6 — Exporter une image au format PIF** +En tant qu’utilisateur, je veux enregistrer l’image sous format `.pif`. + +### **US-U7 — Aperçu de l’image avant conversion** +En tant qu’utilisateur, je veux voir une miniature de l’image chargée. + +--- + +# 2. US DÉVELOPPEUR +Ce sont les besoins techniques indispensables au fonctionnement interne du format PIF. + +--- + +### **US-D1 — Lire des bits depuis un flux** +Le système doit permettre la lecture bit par bit depuis un fichier PIF. + +### **US-D2 — Écrire des bits dans un fichier** +Le système doit permettre l’écriture de bits pour générer un fichier PIF. + +### **US-D3 — Construire les tables de fréquences RGB** +Le système doit analyser l’image pour obtenir les fréquences des valeurs R, G, B. + +### **US-D4 — Construire un arbre de Huffman** +Le système doit créer un arbre à partir des fréquences d’une composante. + +### **US-D5 — Générer les codes Huffman** +Le système doit produire les codes initiaux à partir de l’arbre. + +### **US-D6 — Générer les codes canoniques** +Le système doit transformer les codes Huffman en codes canoniques. + +### **US-D7 — Reconstruire les codes canoniques en lecture** +Le système doit pouvoir reconstruire les codes à partir des longueurs contenues dans le fichier .pif. + +### **US-D8 — Décoder un fichier PIF** +Le système doit pouvoir reconstituer l’image RGB à partir des données compressées. + +--- + +# 3. US PROFESSEUR (PEDAGOGIQUE) +Ces fonctionnalités n’ont **aucune utilité pour un utilisateur réel**, mais sont demandées par le professeur pour vérifier le bon fonctionnement de notre projet. + +--- + +### **US-P1 — Affichage des tables de fréquences** +En tant que professeur, je veux consulter la table de fréquences R, G et B pour vérifier que le calcul est correct. + +### **US-P2 — Affichage des codes Huffman** +En tant que professeur, je veux voir les codes Huffman générés afin de valider votre algorithme. + +### **US-P3 — Affichage des codes canoniques** +En tant que professeur, je veux visualiser les codes canoniques afin d’évaluer votre compréhension de leur construction. + +### **US-P4 — Affichage de l’arbre Huffman (optionnel)** +En tant que professeur, je veux pouvoir inspecter la structure de l’arbre pour vérifier votre implémentation. + +### **US-P5 — Documentation Javadoc pour chaque classe** +En tant que professeur, je veux avoir une documentation claire auto-générable. + +### **US-P6 — Diagrammes UML dans le rapport** +En tant que professeur, je veux retrouver un diagramme de classes et un diagramme d’objets dans le rapport. + +### **US-P7 — Makefile complet** +En tant que professeur, je veux pouvoir compiler les deux programmes en .jar exécutables avec un Makefile clair. + + + diff --git a/README.md b/README.md index 655dda9..49f7856 100644 --- a/README.md +++ b/README.md @@ -1,174 +1,174 @@ -# Projet : Primitive Image Format (PIF) - -## Description générale - -Ce projet consiste à implémenter un nouveau format d’image compressé sans perte, appelé **PIF (Primitive Image Format)**, inspiré du format JFIF. -Il s'appuie sur la création de tables de fréquences, de codes de Huffman, de codes canoniques et sur la manipulation binaire afin de réduire la taille des images. - -Deux programmes Java doivent être développés : - -1. **Visualisateur PIF** - Programme capable d’ouvrir un fichier `.pif` et d’afficher l’image dans une interface graphique. - -2. **Convertisseur vers PIF** - Programme permettant de charger une image classique (ImageIO), de générer ses tables de fréquences et codes associés, puis de produire un fichier `.pif`. - -Ce travail doit être réalisé en binôme ou trinôme. - ---- - -## Deadline - -**Date limite de rendu : dimanche 11 janvier 2025 à 23h59.** -Toutes les sources doivent être présentes sur le serveur Gitea du département dans un dépôt privé nommé **SAE32_2025**. - ---- - -## Fonctionnalités attendues - -### 1. Visualisateur `.pif` - -- Lecture du fichier `.pif` via argument de ligne de commande ou `JFileChooser`. -- Décodage : - - de l’en-tête (largeur, hauteur), - - des trois tables canoniques (R, G, B), - - des données binaires des pixels. -- Affichage graphique sous Swing : - - fenêtre redimensionnable, - - image centrée si petite, - - image déplaçable à la souris si trop grande. - ---- - -### 2. Convertisseur vers format `.pif` - -- Chargement d'une image via `ImageIO.read()`. -- Extraction : - - des tables de fréquences, - - des codes Huffman initiaux, - - des codes canoniques triés. -- Affichage des tables pour inspection. -- Génération du fichier `.pif` : - - en-tête, - - tables canoniques compactes, - - données binaires des pixels encodés. -- Le deuxième argument de ligne de commande peut définir le nom du fichier `.pif`. - ---- - -## Structure du format PIF - -Un fichier `.pif` contient trois sections : - -1. **En-tête (4 octets)** - - largeur (2 octets) - - hauteur (2 octets) - -2. **Tables canoniques (768 octets)** - Trois tables successives de 256 octets : rouge, vert, bleu. - Chaque octet indique la longueur du code canonique d’une valeur entre 0 et 255. - -3. **Section pixels (à partir du 773e octet)** - Les trois composantes (R, G, B) sont encodées via leurs codes canoniques respectifs. - Les bits sont packés de manière contiguë. - ---- - -## Processus de compression - -### 1. Création des tables de fréquences - -Pour R, G et B : compter combien de fois chaque valeur apparaît dans l’image. - -### 2. Construction des codes Huffman - -- Un arbre est construit par composante. -- Les valeurs les plus fréquentes reçoivent les codes les plus courts. -- Les codes initiaux peuvent varier en longueur. - -### 3. Génération des codes canoniques - -- Tri des valeurs par longueur de code puis par valeur. -- Premier code : rempli de zéros. -- Les suivants sont obtenus par incrément binaire. -- Permet une reconstruction simple côté visualisateur. - ---- - -## Architecture logicielle - -Le projet doit inclure : - -- un package Java unique, -- toutes les classes nécessaires au traitement : - - gestion du fichier PIF, - - lecture/écriture binaire, - - génération des fréquences, - - Huffman, - - codes canoniques, - - interface graphique, - - programme principal du visualisateur, - - programme principal du convertisseur. -- un `Makefile` générant deux exécutables `.jar`. - ---- - -## Classes Java - -Les classes Java utilisées dans le projet : - -- [BitinputStream](src/fr/iutfbleau/sae/util/BitinputStream.java) -- [BitOutputStream](src/fr/iutfbleau/sae/util/BitOutputStream.java) -- [ByteUtils](src/fr/iutfbleau/sae/util/ByteUtils.java) -- [CanonicalCode](src/fr/iutfbleau/sae/mhuffman/CanonicalCode.java) -- [FrequencyTable](src/fr/iutfbleau/sae/mhuffman/FrequencyTable.java) -- [HuffmanNode](src/fr/iutfbleau/sae/mhuffman/HuffmanNode.java) -- [HuffmanTree](src/fr/iutfbleau/sae/mhuffman/HuffmanTree.java) - ---- - -## Rapport à produire - -Un rapport PDF doit contenir : - -- noms des membres du groupe, -- introduction résumant le sujet, -- description des fonctionnalités du programme, -- captures d’écran, -- diagrammes UML simplifiés, -- explication du compresseur (Huffman, canoniques, structure du fichier), -- explication du décompresseur, -- conclusion personnelle de chaque membre. - -Le rapport ne doit pas contenir de code source. - ---- - -## Compilation et exécution - -### Visualisateur - java -jar pif-viewer.jar chemin/image.pif - - -### Convertisseur - java -jar pif-converter.jar image.png sortie.pif - - -Si aucun argument n’est fourni, un `JFileChooser` est ouvert. - ---- - - -- Les commits, leur fréquence et la collaboration seront pris en compte dans la note. - ---- - -## Auteurs - -- Algassimou Pellel DIALLO -- Ayoub ANHDIRE -- Youness BOULALAME - -## Enseignant -- Luc HERNANDEZ - +# Projet : Primitive Image Format (PIF) + +## Description générale + +Ce projet consiste à implémenter un nouveau format d’image compressé sans perte, appelé **PIF (Primitive Image Format)**, inspiré du format JFIF. +Il s'appuie sur la création de tables de fréquences, de codes de Huffman, de codes canoniques et sur la manipulation binaire afin de réduire la taille des images. + +Deux programmes Java doivent être développés : + +1. **Visualisateur PIF** + Programme capable d’ouvrir un fichier `.pif` et d’afficher l’image dans une interface graphique. + +2. **Convertisseur vers PIF** + Programme permettant de charger une image classique (ImageIO), de générer ses tables de fréquences et codes associés, puis de produire un fichier `.pif`. + +Ce travail doit être réalisé en binôme ou trinôme. + +--- + +## Deadline + +**Date limite de rendu : dimanche 11 janvier 2025 à 23h59.** +Toutes les sources doivent être présentes sur le serveur Gitea du département dans un dépôt privé nommé **SAE32_2025**. + +--- + +## Fonctionnalités attendues + +### 1. Visualisateur `.pif` + +- Lecture du fichier `.pif` via argument de ligne de commande ou `JFileChooser`. +- Décodage : + - de l’en-tête (largeur, hauteur), + - des trois tables canoniques (R, G, B), + - des données binaires des pixels. +- Affichage graphique sous Swing : + - fenêtre redimensionnable, + - image centrée si petite, + - image déplaçable à la souris si trop grande. + +--- + +### 2. Convertisseur vers format `.pif` + +- Chargement d'une image via `ImageIO.read()`. +- Extraction : + - des tables de fréquences, + - des codes Huffman initiaux, + - des codes canoniques triés. +- Affichage des tables pour inspection. +- Génération du fichier `.pif` : + - en-tête, + - tables canoniques compactes, + - données binaires des pixels encodés. +- Le deuxième argument de ligne de commande peut définir le nom du fichier `.pif`. + +--- + +## Structure du format PIF + +Un fichier `.pif` contient trois sections : + +1. **En-tête (4 octets)** + - largeur (2 octets) + - hauteur (2 octets) + +2. **Tables canoniques (768 octets)** + Trois tables successives de 256 octets : rouge, vert, bleu. + Chaque octet indique la longueur du code canonique d’une valeur entre 0 et 255. + +3. **Section pixels (à partir du 773e octet)** + Les trois composantes (R, G, B) sont encodées via leurs codes canoniques respectifs. + Les bits sont packés de manière contiguë. + +--- + +## Processus de compression + +### 1. Création des tables de fréquences + +Pour R, G et B : compter combien de fois chaque valeur apparaît dans l’image. + +### 2. Construction des codes Huffman + +- Un arbre est construit par composante. +- Les valeurs les plus fréquentes reçoivent les codes les plus courts. +- Les codes initiaux peuvent varier en longueur. + +### 3. Génération des codes canoniques + +- Tri des valeurs par longueur de code puis par valeur. +- Premier code : rempli de zéros. +- Les suivants sont obtenus par incrément binaire. +- Permet une reconstruction simple côté visualisateur. + +--- + +## Architecture logicielle + +Le projet doit inclure : + +- un package Java unique, +- toutes les classes nécessaires au traitement : + - gestion du fichier PIF, + - lecture/écriture binaire, + - génération des fréquences, + - Huffman, + - codes canoniques, + - interface graphique, + - programme principal du visualisateur, + - programme principal du convertisseur. +- un `Makefile` générant deux exécutables `.jar`. + +--- + +## Classes Java + +Les classes Java utilisées dans le projet : + +- [BitinputStream](src/fr/iutfbleau/sae/util/BitinputStream.java) +- [BitOutputStream](src/fr/iutfbleau/sae/util/BitOutputStream.java) +- [ByteUtils](src/fr/iutfbleau/sae/util/ByteUtils.java) +- [CanonicalCode](src/fr/iutfbleau/sae/mhuffman/CanonicalCode.java) +- [FrequencyTable](src/fr/iutfbleau/sae/mhuffman/FrequencyTable.java) +- [HuffmanNode](src/fr/iutfbleau/sae/mhuffman/HuffmanNode.java) +- [HuffmanTree](src/fr/iutfbleau/sae/mhuffman/HuffmanTree.java) + +--- + +## Rapport à produire + +Un rapport PDF doit contenir : + +- noms des membres du groupe, +- introduction résumant le sujet, +- description des fonctionnalités du programme, +- captures d’écran, +- diagrammes UML simplifiés, +- explication du compresseur (Huffman, canoniques, structure du fichier), +- explication du décompresseur, +- conclusion personnelle de chaque membre. + +Le rapport ne doit pas contenir de code source. + +--- + +## Compilation et exécution + +### Visualisateur + java -jar pif-viewer.jar chemin/image.pif + + +### Convertisseur + java -jar pif-converter.jar image.png sortie.pif + + +Si aucun argument n’est fourni, un `JFileChooser` est ouvert. + +--- + + +- Les commits, leur fréquence et la collaboration seront pris en compte dans la note. + +--- + +## Auteurs + +- Algassimou Pellel DIALLO +- Ayoub ANHDIRE +- Youness BOULALAME + +## Enseignant +- Luc HERNANDEZ + diff --git a/build/fr/iutfbleau/sae/mhuffman/CanonicalCode$1.class b/build/fr/iutfbleau/sae/mhuffman/CanonicalCode$1.class deleted file mode 100644 index c337e61..0000000 Binary files a/build/fr/iutfbleau/sae/mhuffman/CanonicalCode$1.class and /dev/null differ diff --git a/build/fr/iutfbleau/sae/mhuffman/CanonicalCode.class b/build/fr/iutfbleau/sae/mhuffman/CanonicalCode.class index 28611d9..d49fd34 100644 Binary files a/build/fr/iutfbleau/sae/mhuffman/CanonicalCode.class and b/build/fr/iutfbleau/sae/mhuffman/CanonicalCode.class differ diff --git a/build/fr/iutfbleau/sae/mhuffman/ComparateurCanonique.class b/build/fr/iutfbleau/sae/mhuffman/ComparateurCanonique.class new file mode 100644 index 0000000..abe71ac Binary files /dev/null and b/build/fr/iutfbleau/sae/mhuffman/ComparateurCanonique.class differ diff --git a/makefile b/makefile index 9a018f1..d0e1e42 100644 --- a/makefile +++ b/makefile @@ -1,166 +1,175 @@ -# Outils -JAVAC = javac -JAVA = java -JAVADOC = javadoc -ARGS = - -# Dossiers -SRC = src -BIN = build -DOC = docjava -LIB = lib/ - -# Package -PKG_PATH = fr/iutfbleau/sae - -# Points d’entrée -MAIN_CONVERTER = fr.iutfbleau.sae.Convertisseur -MAIN_VIEWER = fr.iutfbleau.sae.Viewer - -# Séparateur classpath -ifeq ($(OS),Windows_NT) - SEP = ; -else - SEP = : -endif - -# Règle par défaut -all: \ - $(BIN)/$(PKG_PATH)/Convertisseur.class \ - $(BIN)/$(PKG_PATH)/Viewer.class - -# Compilation des classes main -$(BIN)/$(PKG_PATH)/Convertisseur.class: $(BIN) \ - $(BIN)/$(PKG_PATH)/ConverterController.class \ - $(BIN)/$(PKG_PATH)/vconverter/ConverterWindow.class \ - $(BIN)/$(PKG_PATH)/ExportButtonListener.class \ - $(SRC)/$(PKG_PATH)/Convertisseur.java - $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/Convertisseur.java - -$(BIN)/$(PKG_PATH)/Viewer.class: $(BIN) \ - $(SRC)/$(PKG_PATH)/Viewer.java - $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/Viewer.java - -# Dossiers -$(BIN): - mkdir -p $(BIN) - -$(DOC): - mkdir -p $(DOC) - - -# Compilation des classes util -$(BIN)/$(PKG_PATH)/util/ByteUtils.class: $(BIN) \ - $(SRC)/$(PKG_PATH)/util/ByteUtils.java - $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/util/ByteUtils.java - -$(BIN)/$(PKG_PATH)/util/BitInputStream.class: $(BIN) \ - $(SRC)/$(PKG_PATH)/util/BitInputStream.java - $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/util/BitInputStream.java - -$(BIN)/$(PKG_PATH)/util/BitOutputStream.class: $(BIN) \ - $(SRC)/$(PKG_PATH)/util/BitOutputStream.java - $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/util/BitOutputStream.java - - -# Compilation des classes mhuffman -$(BIN)/$(PKG_PATH)/mhuffman/CanonicalCode.class: $(BIN) \ - $(SRC)/$(PKG_PATH)/mhuffman/CanonicalCode.java - $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mhuffman/CanonicalCode.java - -$(BIN)/$(PKG_PATH)/mhuffman/FrequencyTable.class: $(BIN) \ - $(BIN)/$(PKG_PATH)/mimage/RGBImage.class \ - $(SRC)/$(PKG_PATH)/mhuffman/FrequencyTable.java - $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mhuffman/FrequencyTable.java - -$(BIN)/$(PKG_PATH)/mhuffman/HuffmanNode.class: $(BIN) \ - $(SRC)/$(PKG_PATH)/mhuffman/HuffmanNode.java - $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mhuffman/HuffmanNode.java - -$(BIN)/$(PKG_PATH)/mhuffman/HuffmanTree.class: $(BIN) \ - $(BIN)/$(PKG_PATH)/mhuffman/HuffmanNode.class \ - $(SRC)/$(PKG_PATH)/mhuffman/HuffmanTree.java - $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mhuffman/HuffmanTree.java - - -# Compilation des classes mimage -$(BIN)/$(PKG_PATH)/mimage/Pixel.class: $(BIN) \ - $(SRC)/$(PKG_PATH)/mimage/Pixel.java - $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mimage/Pixel.java - -$(BIN)/$(PKG_PATH)/mimage/RGBImage.class: $(BIN) \ - $(BIN)/$(PKG_PATH)/mimage/Pixel.class \ - $(SRC)/$(PKG_PATH)/mimage/RGBImage.java - $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mimage/RGBImage.java - - -# Interface graphique -$(BIN)/$(PKG_PATH)/vconverter/ImagePreviewPanel.class: $(BIN) \ - $(SRC)/$(PKG_PATH)/vconverter/ImagePreviewPanel.java - $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/vconverter/ImagePreviewPanel.java - -$(BIN)/$(PKG_PATH)/vconverter/FrequencyTablePanel.class: $(BIN) \ - $(SRC)/$(PKG_PATH)/vconverter/FrequencyTablePanel.java - $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/vconverter/FrequencyTablePanel.java - -$(BIN)/$(PKG_PATH)/vconverter/CodeTablePanel.class: $(BIN) \ - $(SRC)/$(PKG_PATH)/vconverter/CodeTablePanel.java - $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/vconverter/CodeTablePanel.java - -# $(BIN)/$(PKG_PATH)/vconverter/ConverterWindow.class: $(BIN) \ -# $(BIN)/$(PKG_PATH)/ConverterController.class \ -# $(BIN)/$(PKG_PATH)/vconverter/ImagePreviewPanel.class \ -# $(BIN)/$(PKG_PATH)/vconverter/FrequencyTablePanel.class \ -# $(BIN)/$(PKG_PATH)/vconverter/CodeTablePanel.class \ -# $(SRC)/$(PKG_PATH)/vconverter/ConverterWindow.java -# $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/vconverter/ConverterWindow.java - - - -# Compilation PIFWriter -$(BIN)/$(PKG_PATH)/mpif/PIFWriter.class: $(BIN) \ - $(BIN)/$(PKG_PATH)/mimage/RGBImage.class \ - $(BIN)/$(PKG_PATH)/util/BitOutputStream.class \ - $(SRC)/$(PKG_PATH)/mpif/PIFWriter.java - $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mpif/PIFWriter.java - - -# GROSSE compilation du listener + ConvertController + ConvertWindow + PIFSaverTask car il y a une dependance cirulaire -$(BIN)/$(PKG_PATH)/ConverterController.class \ -$(BIN)/$(PKG_PATH)/ExportButtonListener.class \ -$(BIN)/$(PKG_PATH)/PIFSaveTask.class \ -$(BIN)/$(PKG_PATH)/vconverter/ConverterWindow.class: \ -$(SRC)/$(PKG_PATH)/ConverterController.java \ -$(SRC)/$(PKG_PATH)/ExportButtonListener.java \ -$(SRC)/$(PKG_PATH)/PIFSaveTask.java \ -$(SRC)/$(PKG_PATH)/vconverter/ConverterWindow.java \ -$(BIN)/$(PKG_PATH)/mimage/Pixel.class \ -$(BIN)/$(PKG_PATH)/mimage/RGBImage.class \ -$(BIN)/$(PKG_PATH)/mhuffman/FrequencyTable.class \ -$(BIN)/$(PKG_PATH)/mhuffman/HuffmanTree.class \ -$(BIN)/$(PKG_PATH)/mhuffman/CanonicalCode.class \ -$(BIN)/$(PKG_PATH)/vconverter/ImagePreviewPanel.class \ -$(BIN)/$(PKG_PATH)/vconverter/FrequencyTablePanel.class \ -$(BIN)/$(PKG_PATH)/vconverter/CodeTablePanel.class \ -$(BIN)/$(PKG_PATH)/mpif/PIFWriter.class | $(BIN) - @$(JAVAC) -cp $(BIN) -d $(BIN) \ - $(SRC)/$(PKG_PATH)/ConverterController.java \ - $(SRC)/$(PKG_PATH)/ExportButtonListener.java \ - $(SRC)/$(PKG_PATH)/PIFSaveTask.java \ - $(SRC)/$(PKG_PATH)/vconverter/ConverterWindow.java - - -# Exécution -run-conv: all - $(JAVA) -cp $(BIN) $(MAIN_CONVERTER) $(ARGS) - -run-view: all - $(JAVA) -cp $(BIN) $(MAIN_VIEWER) - -# Documentation -doc: $(DOC) - $(JAVADOC) -d $(DOC) $(SRC)/fr/iutfbleau/sae/**/*.java - -# Nettoyage -clean: - rm -rf $(BIN) $(DOC) +# Outils +JAVAC = javac +JAVA = java +JAVADOC = javadoc +ARGS = + +# Dossiers +SRC = src +BIN = build +DOC = docjava +LIB = lib/ + +# Package +PKG_PATH = fr/iutfbleau/sae + +# Points d’entrée +MAIN_CONVERTER = fr.iutfbleau.sae.Convertisseur +MAIN_VIEWER = fr.iutfbleau.sae.Viewer + +# Séparateur classpath +ifeq ($(OS),Windows_NT) + SEP = ; +else + SEP = : +endif + +# Règle par défaut +all: \ + $(BIN)/$(PKG_PATH)/Convertisseur.class \ + $(BIN)/$(PKG_PATH)/Viewer.class + +# Compilation des classes main +$(BIN)/$(PKG_PATH)/Convertisseur.class: $(BIN) \ + $(BIN)/$(PKG_PATH)/ConverterController.class \ + $(BIN)/$(PKG_PATH)/vconverter/ConverterWindow.class \ + $(BIN)/$(PKG_PATH)/ExportButtonListener.class \ + $(SRC)/$(PKG_PATH)/Convertisseur.java + $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/Convertisseur.java + +$(BIN)/$(PKG_PATH)/Viewer.class: $(BIN) \ + $(SRC)/$(PKG_PATH)/Viewer.java + $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/Viewer.java + +# Dossiers +$(BIN): + mkdir -p $(BIN) + +$(DOC): + mkdir -p $(DOC) + + +# Compilation des classes util +$(BIN)/$(PKG_PATH)/util/ByteUtils.class: $(BIN) \ + $(SRC)/$(PKG_PATH)/util/ByteUtils.java + $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/util/ByteUtils.java + +$(BIN)/$(PKG_PATH)/util/BitInputStream.class: $(BIN) \ + $(SRC)/$(PKG_PATH)/util/BitInputStream.java + $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/util/BitInputStream.java + +$(BIN)/$(PKG_PATH)/util/BitOutputStream.class: $(BIN) \ + $(SRC)/$(PKG_PATH)/util/BitOutputStream.java + $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/util/BitOutputStream.java + + +# Compilation des classes mhuffman + +# Ajout de la classe ComparateurCanonique : +$(BIN)/$(PKG_PATH)/mhuffman/ComparateurCanonique.class: $(BIN) \ + $(SRC)/$(PKG_PATH)/mhuffman/ComparateurCanonique.java + $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mhuffman/ComparateurCanonique.java +# + + +$(BIN)/$(PKG_PATH)/mhuffman/CanonicalCode.class: $(BIN) \ + $(SRC)/$(PKG_PATH)/mhuffman/CanonicalCode.java \ + $(BIN)/$(PKG_PATH)/mhuffman/ComparateurCanonique.class + $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mhuffman/CanonicalCode.java + +$(BIN)/$(PKG_PATH)/mhuffman/FrequencyTable.class: $(BIN) \ + $(BIN)/$(PKG_PATH)/mimage/RGBImage.class \ + $(SRC)/$(PKG_PATH)/mhuffman/FrequencyTable.java + $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mhuffman/FrequencyTable.java + +$(BIN)/$(PKG_PATH)/mhuffman/HuffmanNode.class: $(BIN) \ + $(SRC)/$(PKG_PATH)/mhuffman/HuffmanNode.java + $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mhuffman/HuffmanNode.java + +$(BIN)/$(PKG_PATH)/mhuffman/HuffmanTree.class: $(BIN) \ + $(BIN)/$(PKG_PATH)/mhuffman/HuffmanNode.class \ + $(SRC)/$(PKG_PATH)/mhuffman/HuffmanTree.java + $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mhuffman/HuffmanTree.java + + +# Compilation des classes mimage +$(BIN)/$(PKG_PATH)/mimage/Pixel.class: $(BIN) \ + $(SRC)/$(PKG_PATH)/mimage/Pixel.java + $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mimage/Pixel.java + +$(BIN)/$(PKG_PATH)/mimage/RGBImage.class: $(BIN) \ + $(BIN)/$(PKG_PATH)/mimage/Pixel.class \ + $(SRC)/$(PKG_PATH)/mimage/RGBImage.java + $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mimage/RGBImage.java + + +# Interface graphique +$(BIN)/$(PKG_PATH)/vconverter/ImagePreviewPanel.class: $(BIN) \ + $(SRC)/$(PKG_PATH)/vconverter/ImagePreviewPanel.java + $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/vconverter/ImagePreviewPanel.java + +$(BIN)/$(PKG_PATH)/vconverter/FrequencyTablePanel.class: $(BIN) \ + $(SRC)/$(PKG_PATH)/vconverter/FrequencyTablePanel.java + $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/vconverter/FrequencyTablePanel.java + +$(BIN)/$(PKG_PATH)/vconverter/CodeTablePanel.class: $(BIN) \ + $(SRC)/$(PKG_PATH)/vconverter/CodeTablePanel.java + $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/vconverter/CodeTablePanel.java + +# $(BIN)/$(PKG_PATH)/vconverter/ConverterWindow.class: $(BIN) \ +# $(BIN)/$(PKG_PATH)/ConverterController.class \ +# $(BIN)/$(PKG_PATH)/vconverter/ImagePreviewPanel.class \ +# $(BIN)/$(PKG_PATH)/vconverter/FrequencyTablePanel.class \ +# $(BIN)/$(PKG_PATH)/vconverter/CodeTablePanel.class \ +# $(SRC)/$(PKG_PATH)/vconverter/ConverterWindow.java +# $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/vconverter/ConverterWindow.java + + + +# Compilation PIFWriter +$(BIN)/$(PKG_PATH)/mpif/PIFWriter.class: $(BIN) \ + $(BIN)/$(PKG_PATH)/mimage/RGBImage.class \ + $(BIN)/$(PKG_PATH)/util/BitOutputStream.class \ + $(SRC)/$(PKG_PATH)/mpif/PIFWriter.java + $(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mpif/PIFWriter.java + + +# GROSSE compilation du listener + ConvertController + ConvertWindow + PIFSaverTask car il y a une dependance cirulaire +$(BIN)/$(PKG_PATH)/ConverterController.class \ +$(BIN)/$(PKG_PATH)/ExportButtonListener.class \ +$(BIN)/$(PKG_PATH)/PIFSaveTask.class \ +$(BIN)/$(PKG_PATH)/vconverter/ConverterWindow.class: \ +$(SRC)/$(PKG_PATH)/ConverterController.java \ +$(SRC)/$(PKG_PATH)/ExportButtonListener.java \ +$(SRC)/$(PKG_PATH)/PIFSaveTask.java \ +$(SRC)/$(PKG_PATH)/vconverter/ConverterWindow.java \ +$(BIN)/$(PKG_PATH)/mimage/Pixel.class \ +$(BIN)/$(PKG_PATH)/mimage/RGBImage.class \ +$(BIN)/$(PKG_PATH)/mhuffman/FrequencyTable.class \ +$(BIN)/$(PKG_PATH)/mhuffman/HuffmanTree.class \ +$(BIN)/$(PKG_PATH)/mhuffman/CanonicalCode.class \ +$(BIN)/$(PKG_PATH)/vconverter/ImagePreviewPanel.class \ +$(BIN)/$(PKG_PATH)/vconverter/FrequencyTablePanel.class \ +$(BIN)/$(PKG_PATH)/vconverter/CodeTablePanel.class \ +$(BIN)/$(PKG_PATH)/mpif/PIFWriter.class | $(BIN) + @$(JAVAC) -cp $(BIN) -d $(BIN) \ + $(SRC)/$(PKG_PATH)/ConverterController.java \ + $(SRC)/$(PKG_PATH)/ExportButtonListener.java \ + $(SRC)/$(PKG_PATH)/PIFSaveTask.java \ + $(SRC)/$(PKG_PATH)/vconverter/ConverterWindow.java + + +# Exécution +run-conv: all + $(JAVA) -cp $(BIN) $(MAIN_CONVERTER) $(ARGS) + +run-view: all + $(JAVA) -cp $(BIN) $(MAIN_VIEWER) + +# Documentation +doc: $(DOC) + $(JAVADOC) -d $(DOC) $(SRC)/fr/iutfbleau/sae/**/*.java + +# Nettoyage +clean: + rm -rf $(BIN) $(DOC) diff --git a/src/fr/iutfbleau/sae/ConverterController.java b/src/fr/iutfbleau/sae/ConverterController.java index 82d7ae8..82db243 100644 --- a/src/fr/iutfbleau/sae/ConverterController.java +++ b/src/fr/iutfbleau/sae/ConverterController.java @@ -1,225 +1,225 @@ -package fr.iutfbleau.sae; -import fr.iutfbleau.sae.mhuffman.*; -import fr.iutfbleau.sae.mimage.*; -import fr.iutfbleau.sae.mpif.PIFWriter; -import fr.iutfbleau.sae.vconverter.ConverterWindow; -import java.awt.image.BufferedImage; -import java.io.File; -import java.util.Map; -import javax.imageio.ImageIO; -import javax.swing.JFileChooser; -import javax.swing.JOptionPane; - -/** - * Contrôleur pour la conversion d'images. - *

- * Cette classe gère le chargement des fichiers image et les opérations - * de conversion associées. tel que - *

- * - */ -public class ConverterController { - // Image convertie en RGBImage - private RGBImage image; - - // Table de fréquences pour chaque composante - private FrequencyTable frequencyTable; - - // Arbres de Huffman pour chaque composante - private Map abrHuffmanR; - private Map abrHuffmanG; - private Map abrHuffmanB; - - // Codes canoniques pour chaque composante - private Map canonRED; - private Map canonGREEN; - private Map canonBLUE; - - // La fenêtre du convertisseur - private ConverterWindow fen; - - String outputPath; - String inputPath; - - public ConverterController(ConverterWindow fen, String in, String out) { - this.fen = fen; - this.outputPath = out; - this.inputPath = in; - - System.out.println(this.inputPath+" ==> "+this.outputPath); - } - - - // charger une image depuis un fichier avec bufferedImage et la convertir en RGBImage - public void loadImage(File file) { - try{ - // Lire l'image avec BufferedImage - BufferedImage buffimage = ImageIO.read(file); - if (buffimage == null) { - throw new IllegalArgumentException("Le fichier spécifié n'est pas une image valide."); - } - - int w = buffimage.getWidth(); - int h = buffimage.getHeight(); - - // Créer une RGBImage de la même taille - this.image = new RGBImage(w, h); - // remplir la RGBImage avec les pixels de BufferedImage - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - int rgb = buffimage.getRGB(x, y); // obtenir la valeur RGB du pixel - // Extraire les composantes R, G, B - int r = (rgb >> 16) & 0xFF; - int g = (rgb >> 8) & 0xFF; - int b = rgb & 0xFF; - // Créer un pixel et l'ajouter à la RGBImage - this.image.setPixel(x, y, new Pixel(r, g, b)); - } - } - - // Mettre à jour le GUI - this.fen.setImagePreview(buffimage); - - } catch (Exception e) { - e.printStackTrace(); - } - } - - - public void computeFrequencies() { - - if (this.image == null) { - System.err.println("Aucune image chargée pour le calcul des fréquences."); - return; - } - - this.frequencyTable = new FrequencyTable(); - this.frequencyTable.computeFromImage(this.image); - - // Mettre à jour le GUI avec les fréquences - int[] freqR = this.frequencyTable.getRed(); - int[] freqG = this.frequencyTable.getGreen(); - int[] freqB = this.frequencyTable.getBlue(); - this.fen.setFrequencyTable(freqR, freqG, freqB); - } - - - public void computeHuffman() { - - if (this.frequencyTable == null) { - System.err.println("Les fréquences ne sont pas encore calculées."); - return; - } - - // Génération des arbres de Huffman pour chaque composante et stockage des codes - HuffmanTree arbreR = new HuffmanTree(this.frequencyTable.getRed()); - this.abrHuffmanR = arbreR.generateCodes(); - HuffmanTree arbreG = new HuffmanTree(this.frequencyTable.getGreen()); - this.abrHuffmanG = arbreG.generateCodes(); - HuffmanTree arbreB = new HuffmanTree(this.frequencyTable.getBlue()); - this.abrHuffmanB = arbreB.generateCodes(); - - // Mettre à jour le GUI avec les codes de Huffman - this.fen.setHuffmanTable(this.abrHuffmanR, this.abrHuffmanG, this.abrHuffmanB); - } - - public void computeCanonical() { - if (this.abrHuffmanR == null || this.abrHuffmanG == null || this.abrHuffmanB == null) { - System.err.println("Les codes de Huffman doivent être générés d'abord."); - return; - } - - CanonicalCode codeCanoniques = new CanonicalCode(); - this.canonRED = codeCanoniques.generateCodes(this.abrHuffmanR); - this.canonGREEN = codeCanoniques.generateCodes(this.abrHuffmanG); - this.canonBLUE = codeCanoniques.generateCodes(this.abrHuffmanB); - - // Mettre à jour le GUI avec les codes canoniques - this.fen.setCanonicalTable(this.canonRED, this.canonGREEN, this.canonBLUE); - - } - - public void saveAsPIF(String pathfile) { - // je Vérifie que l'image et les codes canoniques sont disponibles - if(this.image == null || this.canonRED == null){ - System.err.println("Impossible d'ecrire le fichier PIF : données manquantes."); - return; - } - - try { - PIFWriter ecriveur = new PIFWriter(); - ecriveur.writeTOFile(pathfile, this.image, this.canonRED, this.canonGREEN, this.canonBLUE); - } catch (Exception e) { - System.err.println("Erreur lors de l’écriture du fichier .pif : " + pathfile); - } - } - - - public void saveViaBtn() { - try { - if (outputPath != null) { - saveAsPIF(outputPath); - System.out.println("Sauvegarde dans : " + outputPath); - return; - } - - // Sinon JFileChooser - JFileChooser chooser = new JFileChooser(); - chooser.setDialogTitle("Enregistrer le fichier .pif"); - - if (chooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) { - //saveAsPIF(chooser.getSelectedFile().getAbsolutePath()); - // On lance la sauvegarde lourde dans un thread séparé - new Thread(() -> saveAsPIF(chooser.getSelectedFile().getAbsolutePath())).start(); - System.out.println("Fichier sauvegardé : " + chooser.getSelectedFile().getAbsolutePath()); - JOptionPane.showMessageDialog(null, "Fichier sauvegardé avec succès : " + chooser.getSelectedFile().getName()); - } - - System.out.println("Via BTN Sauvegarde terminée."); - - } catch (Exception ex) { - System.out.println("Erreur lors de la sauvegarde : " + ex.getMessage()); - } - } - - public void StartconvessionProcess(){ - // chragement - if (this.inputPath != null) { - // Chargement direct depuis les arguments - File file = new File(inputPath); - this.loadImage(file); - }else{ - // Sinon JFileChooser pour choisir l'image - JFileChooser choosser =new JFileChooser(); - choosser.setDialogTitle("Choisissez une image"); - if (choosser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { - this.loadImage(choosser.getSelectedFile()); - }else { - System.err.println("Aucune image choisie. Arrêt du programme."); - System.exit(1); - return; - } - } - - // je place la logique de conversion dans lordre - computeFrequencies(); - computeHuffman(); - computeCanonical(); - - // Sauvegarder: un second argument est donné sauvegarde automatique - if (this.outputPath != null) { - this.saveAsPIF(this.outputPath); - System.out.println("Fichier sauvegardé automatiquement : " + this.outputPath); - }else{ - // pas de deuxième argument j'ajoute un boutton pour choisir avec un jfilechoser - fen.addSaveButton(this); - } - } - - - - - public RGBImage getImage(){ - return this.image; - } -} +package fr.iutfbleau.sae; +import fr.iutfbleau.sae.mhuffman.*; +import fr.iutfbleau.sae.mimage.*; +import fr.iutfbleau.sae.mpif.PIFWriter; +import fr.iutfbleau.sae.vconverter.ConverterWindow; +import java.awt.image.BufferedImage; +import java.io.File; +import java.util.Map; +import javax.imageio.ImageIO; +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; + +/** + * Contrôleur pour la conversion d'images. + *

+ * Cette classe gère le chargement des fichiers image et les opérations + * de conversion associées. tel que + *

+ * + */ +public class ConverterController { + // Image convertie en RGBImage + private RGBImage image; + + // Table de fréquences pour chaque composante + private FrequencyTable frequencyTable; + + // Arbres de Huffman pour chaque composante + private Map abrHuffmanR; + private Map abrHuffmanG; + private Map abrHuffmanB; + + // Codes canoniques pour chaque composante + private Map canonRED; + private Map canonGREEN; + private Map canonBLUE; + + // La fenêtre du convertisseur + private ConverterWindow fen; + + String outputPath; + String inputPath; + + public ConverterController(ConverterWindow fen, String in, String out) { + this.fen = fen; + this.outputPath = out; + this.inputPath = in; + + System.out.println(this.inputPath+" ==> "+this.outputPath); + } + + + // charger une image depuis un fichier avec bufferedImage et la convertir en RGBImage + public void loadImage(File file) { + try{ + // Lire l'image avec BufferedImage + BufferedImage buffimage = ImageIO.read(file); + if (buffimage == null) { + throw new IllegalArgumentException("Le fichier spécifié n'est pas une image valide."); + } + + int w = buffimage.getWidth(); + int h = buffimage.getHeight(); + + // Créer une RGBImage de la même taille + this.image = new RGBImage(w, h); + // remplir la RGBImage avec les pixels de BufferedImage + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + int rgb = buffimage.getRGB(x, y); // obtenir la valeur RGB du pixel + // Extraire les composantes R, G, B + int r = (rgb >> 16) & 0xFF; + int g = (rgb >> 8) & 0xFF; + int b = rgb & 0xFF; + // Créer un pixel et l'ajouter à la RGBImage + this.image.setPixel(x, y, new Pixel(r, g, b)); + } + } + + // Mettre à jour le GUI + this.fen.setImagePreview(buffimage); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + + public void computeFrequencies() { + + if (this.image == null) { + System.err.println("Aucune image chargée pour le calcul des fréquences."); + return; + } + + this.frequencyTable = new FrequencyTable(); + this.frequencyTable.computeFromImage(this.image); + + // Mettre à jour le GUI avec les fréquences + int[] freqR = this.frequencyTable.getRed(); + int[] freqG = this.frequencyTable.getGreen(); + int[] freqB = this.frequencyTable.getBlue(); + this.fen.setFrequencyTable(freqR, freqG, freqB); + } + + + public void computeHuffman() { + + if (this.frequencyTable == null) { + System.err.println("Les fréquences ne sont pas encore calculées."); + return; + } + + // Génération des arbres de Huffman pour chaque composante et stockage des codes + HuffmanTree arbreR = new HuffmanTree(this.frequencyTable.getRed()); + this.abrHuffmanR = arbreR.generateCodes(); + HuffmanTree arbreG = new HuffmanTree(this.frequencyTable.getGreen()); + this.abrHuffmanG = arbreG.generateCodes(); + HuffmanTree arbreB = new HuffmanTree(this.frequencyTable.getBlue()); + this.abrHuffmanB = arbreB.generateCodes(); + + // Mettre à jour le GUI avec les codes de Huffman + this.fen.setHuffmanTable(this.abrHuffmanR, this.abrHuffmanG, this.abrHuffmanB); + } + + public void computeCanonical() { + if (this.abrHuffmanR == null || this.abrHuffmanG == null || this.abrHuffmanB == null) { + System.err.println("Les codes de Huffman doivent être générés d'abord."); + return; + } + + CanonicalCode codeCanoniques = new CanonicalCode(); + this.canonRED = codeCanoniques.generateCodes(this.abrHuffmanR); + this.canonGREEN = codeCanoniques.generateCodes(this.abrHuffmanG); + this.canonBLUE = codeCanoniques.generateCodes(this.abrHuffmanB); + + // Mettre à jour le GUI avec les codes canoniques + this.fen.setCanonicalTable(this.canonRED, this.canonGREEN, this.canonBLUE); + + } + + public void saveAsPIF(String pathfile) { + // je Vérifie que l'image et les codes canoniques sont disponibles + if(this.image == null || this.canonRED == null){ + System.err.println("Impossible d'ecrire le fichier PIF : données manquantes."); + return; + } + + try { + PIFWriter ecriveur = new PIFWriter(); + ecriveur.writeTOFile(pathfile, this.image, this.canonRED, this.canonGREEN, this.canonBLUE); + } catch (Exception e) { + System.err.println("Erreur lors de l’écriture du fichier .pif : " + pathfile); + } + } + + + public void saveViaBtn() { + try { + if (outputPath != null) { + saveAsPIF(outputPath); + System.out.println("Sauvegarde dans : " + outputPath); + return; + } + + // Sinon JFileChooser + JFileChooser chooser = new JFileChooser(); + chooser.setDialogTitle("Enregistrer le fichier .pif"); + + if (chooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) { + //saveAsPIF(chooser.getSelectedFile().getAbsolutePath()); + // On lance la sauvegarde lourde dans un thread séparé + new Thread(() -> saveAsPIF(chooser.getSelectedFile().getAbsolutePath())).start(); + System.out.println("Fichier sauvegardé : " + chooser.getSelectedFile().getAbsolutePath()); + JOptionPane.showMessageDialog(null, "Fichier sauvegardé avec succès : " + chooser.getSelectedFile().getName()); + } + + System.out.println("Via BTN Sauvegarde terminée."); + + } catch (Exception ex) { + System.out.println("Erreur lors de la sauvegarde : " + ex.getMessage()); + } + } + + public void StartconvessionProcess(){ + // chragement + if (this.inputPath != null) { + // Chargement direct depuis les arguments + File file = new File(inputPath); + this.loadImage(file); + }else{ + // Sinon JFileChooser pour choisir l'image + JFileChooser choosser =new JFileChooser(); + choosser.setDialogTitle("Choisissez une image"); + if (choosser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { + this.loadImage(choosser.getSelectedFile()); + }else { + System.err.println("Aucune image choisie. Arrêt du programme."); + System.exit(1); + return; + } + } + + // je place la logique de conversion dans lordre + computeFrequencies(); + computeHuffman(); + computeCanonical(); + + // Sauvegarder: un second argument est donné sauvegarde automatique + if (this.outputPath != null) { + this.saveAsPIF(this.outputPath); + System.out.println("Fichier sauvegardé automatiquement : " + this.outputPath); + }else{ + // pas de deuxième argument j'ajoute un boutton pour choisir avec un jfilechoser + fen.addSaveButton(this); + } + } + + + + + public RGBImage getImage(){ + return this.image; + } +} diff --git a/src/fr/iutfbleau/sae/Convertisseur.java b/src/fr/iutfbleau/sae/Convertisseur.java index 8d7a19d..717df12 100644 --- a/src/fr/iutfbleau/sae/Convertisseur.java +++ b/src/fr/iutfbleau/sae/Convertisseur.java @@ -1,25 +1,25 @@ -package fr.iutfbleau.sae; - -import fr.iutfbleau.sae.vconverter.ConverterWindow; - -public class Convertisseur { - public static void main(String[] args) { - - // chemins de l'image - String inpuPath = null; - String outputPath = null; - if (args.length >= 1) { - inpuPath = args[0]; - } - if (args.length >= 2) { - outputPath = args[1]; - } - - // Créer et stocker la référence à la fenêtre - ConverterWindow window = new ConverterWindow(); - // je la passe au controleur - ConverterController controller = new ConverterController(window, inpuPath, outputPath); - - controller.StartconvessionProcess(); - } +package fr.iutfbleau.sae; + +import fr.iutfbleau.sae.vconverter.ConverterWindow; + +public class Convertisseur { + public static void main(String[] args) { + + // chemins de l'image + String inpuPath = null; + String outputPath = null; + if (args.length >= 1) { + inpuPath = args[0]; + } + if (args.length >= 2) { + outputPath = args[1]; + } + + // Créer et stocker la référence à la fenêtre + ConverterWindow window = new ConverterWindow(); + // je la passe au controleur + ConverterController controller = new ConverterController(window, inpuPath, outputPath); + + controller.StartconvessionProcess(); + } } \ No newline at end of file diff --git a/src/fr/iutfbleau/sae/ExportButtonListener.java b/src/fr/iutfbleau/sae/ExportButtonListener.java index bffc4e5..ebb3223 100644 --- a/src/fr/iutfbleau/sae/ExportButtonListener.java +++ b/src/fr/iutfbleau/sae/ExportButtonListener.java @@ -1,17 +1,17 @@ -package fr.iutfbleau.sae; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import javax.swing.SwingUtilities; - -public class ExportButtonListener implements ActionListener { - private PIFSaveTask saveTask; - - public ExportButtonListener(ConverterController controller){ - this.saveTask = new PIFSaveTask(controller); - } - - @Override - public void actionPerformed(ActionEvent e){ - SwingUtilities.invokeLater(saveTask); - } -} +package fr.iutfbleau.sae; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.SwingUtilities; + +public class ExportButtonListener implements ActionListener { + private PIFSaveTask saveTask; + + public ExportButtonListener(ConverterController controller){ + this.saveTask = new PIFSaveTask(controller); + } + + @Override + public void actionPerformed(ActionEvent e){ + SwingUtilities.invokeLater(saveTask); + } +} diff --git a/src/fr/iutfbleau/sae/PIFSaveTask.java b/src/fr/iutfbleau/sae/PIFSaveTask.java index a3ed696..ad8cd2b 100644 --- a/src/fr/iutfbleau/sae/PIFSaveTask.java +++ b/src/fr/iutfbleau/sae/PIFSaveTask.java @@ -1,13 +1,13 @@ -package fr.iutfbleau.sae; -public class PIFSaveTask implements Runnable{ - private ConverterController controller; - - public PIFSaveTask(ConverterController c) { - this.controller = c; - } - - @Override - public void run() { - controller.saveViaBtn(); - } -} +package fr.iutfbleau.sae; +public class PIFSaveTask implements Runnable{ + private ConverterController controller; + + public PIFSaveTask(ConverterController c) { + this.controller = c; + } + + @Override + public void run() { + controller.saveViaBtn(); + } +} diff --git a/src/fr/iutfbleau/sae/Viewer.java b/src/fr/iutfbleau/sae/Viewer.java index 8a8f41a..97446a7 100644 --- a/src/fr/iutfbleau/sae/Viewer.java +++ b/src/fr/iutfbleau/sae/Viewer.java @@ -1,7 +1,36 @@ +<<<<<<< HEAD +package fr.iutfbleau.sae; + +public class Viewer { + public static void main(String[] args) { + System.out.println("dqkdjqkdjqkdjqkdjqkdj"); + } +} +======= package fr.iutfbleau.sae; -public class Viewer { - public static void main(String[] args) { - System.out.println("dqkdjqkdjqkdjqkdjqkdj"); +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; + +//teste avec ia +private void chargerFichier() { + JTextArea zoneTexte = new JTextArea(); + zoneTexte.setEditable(false); + + try (BufferedReader br = new BufferedReader(new FileReader(fichierPif))) { + String ligne; + while ((ligne = br.readLine()) != null) { + zoneTexte.append(ligne + "\n"); + } + } catch (IOException e) { + JOptionPane.showMessageDialog(this, + "Erreur lors de l'ouverture du fichier", + "Erreur", + JOptionPane.ERROR_MESSAGE); } + + add(new JScrollPane(zoneTexte), BorderLayout.CENTER); + setVisible(true); } +>>>>>>> 40f71dddd52fc07edc1d47d48d56fd65a2a79fe3 diff --git a/src/fr/iutfbleau/sae/mhuffman/CanonicalCode.java b/src/fr/iutfbleau/sae/mhuffman/CanonicalCode.java index 06a2497..af8c9f7 100644 --- a/src/fr/iutfbleau/sae/mhuffman/CanonicalCode.java +++ b/src/fr/iutfbleau/sae/mhuffman/CanonicalCode.java @@ -1,72 +1,61 @@ -package fr.iutfbleau.sae.mhuffman; -import java.util.*; - -public class CanonicalCode{ - //private Map codeLengths = new HashMap<>(); - //private Map canonicalCodes = new HashMap<>(); - - - - public Map generateCodes(Map codesHuffman){ - // 1 ere chose à faire : on regarde uniquement la longueur des codes initiaux(Huffman) - // 2eme chose à faire : remettre dans l'ordre des longueurs : si meme taille ==> regarder valeur - // 3eme chose à faire : ecriture des codes canoniques - - // on recupere les entrées des codes Huffman pour pouvoir les triés - List> liste = new ArrayList<>(codesHuffman.entrySet()); - - // ici on comparer par longueur de la valeur ou sinon par la clé - - - - // =============== ATTENTION CLASSE ANONYME !!!!!!! ================ - Collections.sort(liste, new Comparator>() { - @Override - public int compare(Map.Entry arg1 ,Map.Entry arg2) { - - int length1 = arg1.getValue().length(); - int length2 = arg2.getValue().length(); - - if (length1 != length2) { - return length1 - length2; - } - return arg1.getKey() - arg2.getKey(); - } - }); - - Map canonicalCodes = new HashMap<>(); - int code = 0; // code canonique à attribuer - int temp = 0; //garde la longueur du code précedent , pour gérer le décalage - - for (Map.Entry entree : liste ) { - int valeur = entree.getKey(); // symbole actuel - int longueur = entree.getValue().length(); // longueur du code actuel - - code <<= (longueur - temp); // permet de décaler le code actuel si la longueur augmente - String codeBinaire = Integer.toBinaryString(code); - - // permet d'ajouter des zeros si nécessaire !!! - while (codeBinaire.length() < longueur) { - codeBinaire = "0" + codeBinaire; - } - - canonicalCodes.put(valeur,codeBinaire); // ajout dans le dictionnaire - code++; // incrémentation pour la valeur qui suit - temp = longueur; // mise à jour de la longueur précedente - } - - return canonicalCodes; - } - - - public String getCode(Map canonicalCodes,int value){ - return canonicalCodes.get(value); - } - - public int getLength(Map codesH,int value){ - return codesH.get(value).length(); - } - -} - - +package fr.iutfbleau.sae.mhuffman; +import java.util.*; + +public class CanonicalCode{ + //private Map codeLengths = new HashMap<>(); + //private Map canonicalCodes = new HashMap<>(); + + + + public Map generateCodes(Map codesHuffman){ + // 1 ere chose à faire : on regarde uniquement la longueur des codes initiaux(Huffman) + // 2eme chose à faire : remettre dans l'ordre des longueurs : si meme taille ==> regarder valeur + // 3eme chose à faire : ecriture des codes canoniques + + // on recupere les entrées des codes Huffman pour pouvoir les triés + List> liste = new ArrayList<>(codesHuffman.entrySet()); + + // ici on comparer par longueur de la valeur ou sinon par la clé + + + + Collections.sort(liste, new ComparateurCanonique()); + + + + Map canonicalCodes = new HashMap<>(); + int code = 0; // code canonique à attribuer + int temp = 0; //garde la longueur du code précedent , pour gérer le décalage + + for (Map.Entry entree : liste ) { + int valeur = entree.getKey(); // symbole actuel + int longueur = entree.getValue().length(); // longueur du code actuel + + code <<= (longueur - temp); // permet de décaler le code actuel si la longueur augmente + String codeBinaire = Integer.toBinaryString(code); + + // permet d'ajouter des zeros si nécessaire !!! + while (codeBinaire.length() < longueur) { + codeBinaire = "0" + codeBinaire; + } + + canonicalCodes.put(valeur,codeBinaire); // ajout dans le dictionnaire + code++; // incrémentation pour la valeur qui suit + temp = longueur; // mise à jour de la longueur précedente + } + + return canonicalCodes; + } + + + public String getCode(Map canonicalCodes,int value){ + return canonicalCodes.get(value); + } + + public int getLength(Map codesH,int value){ + return codesH.get(value).length(); + } + +} + + diff --git a/src/fr/iutfbleau/sae/mhuffman/ComparateurCanonique.java b/src/fr/iutfbleau/sae/mhuffman/ComparateurCanonique.java new file mode 100644 index 0000000..a493726 --- /dev/null +++ b/src/fr/iutfbleau/sae/mhuffman/ComparateurCanonique.java @@ -0,0 +1,19 @@ +package fr.iutfbleau.sae.mhuffman; +import java.util.Comparator; +import java.util.Map; + +public class ComparateurCanonique implements Comparator> { + + @Override + public int compare(Map.Entry entree1,Map.Entry entree2) { + + int longueur1 = entree1.getValue().length(); + int longueur2 = entree2.getValue().length(); + + if (longueur1 != longueur2) { + return longueur1 - longueur2; + } + + return entree1.getKey() - entree2.getKey(); + } +} \ No newline at end of file diff --git a/src/fr/iutfbleau/sae/mimage/Pixel.java b/src/fr/iutfbleau/sae/mimage/Pixel.java index 0619e06..eb8db1a 100644 --- a/src/fr/iutfbleau/sae/mimage/Pixel.java +++ b/src/fr/iutfbleau/sae/mimage/Pixel.java @@ -1,38 +1,38 @@ -package fr.iutfbleau.sae.mimage; - -public class Pixel{ - private int r; - private int g; - private int b; - - //à completer - public Pixel(int red, int green, int blue){ - this.r=red; - this.g=green; - this.b=blue; - } - - public int getB() { - return b; - } - - public int getG() { - return g; - } - - public int getR() { - return r; - } - - public void setR(int r) { - this.r = r; - } - - public void setB(int b) { - this.b = b; - } - - public void setG(int g) { - this.g = g; - } +package fr.iutfbleau.sae.mimage; + +public class Pixel{ + private int r; + private int g; + private int b; + + //à completer + public Pixel(int red, int green, int blue){ + this.r=red; + this.g=green; + this.b=blue; + } + + public int getB() { + return b; + } + + public int getG() { + return g; + } + + public int getR() { + return r; + } + + public void setR(int r) { + this.r = r; + } + + public void setB(int b) { + this.b = b; + } + + public void setG(int g) { + this.g = g; + } } \ No newline at end of file diff --git a/src/fr/iutfbleau/sae/mimage/RGBImage.java b/src/fr/iutfbleau/sae/mimage/RGBImage.java index 8808505..a92b2f0 100644 --- a/src/fr/iutfbleau/sae/mimage/RGBImage.java +++ b/src/fr/iutfbleau/sae/mimage/RGBImage.java @@ -1,30 +1,30 @@ -package fr.iutfbleau.sae.mimage; - -public class RGBImage { - - private int width; - private int height; - private Pixel [][] pixels; - - public RGBImage (int lar, int haut){ - this.width=lar; - this.height=haut; - this.pixels = new Pixel[this.width][this.height]; - } - - public int getWidth() { - return width; - } - - public int getHeight() { - return height; - } - - public void setPixel(int x, int y, Pixel p) { - this.pixels[x][y] = p; - } - - public Pixel getPixel(int x, int y) { - return this.pixels[x][y]; - } +package fr.iutfbleau.sae.mimage; + +public class RGBImage { + + private int width; + private int height; + private Pixel [][] pixels; + + public RGBImage (int lar, int haut){ + this.width=lar; + this.height=haut; + this.pixels = new Pixel[this.width][this.height]; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public void setPixel(int x, int y, Pixel p) { + this.pixels[x][y] = p; + } + + public Pixel getPixel(int x, int y) { + return this.pixels[x][y]; + } } \ No newline at end of file diff --git a/src/fr/iutfbleau/sae/mpif/DecodeNode.java b/src/fr/iutfbleau/sae/mpif/DecodeNode.java index c995ed8..800852d 100644 --- a/src/fr/iutfbleau/sae/mpif/DecodeNode.java +++ b/src/fr/iutfbleau/sae/mpif/DecodeNode.java @@ -1,23 +1,23 @@ -package fr.iutfbleau.sae.mpif; - -public class DecodeNode { - public DecodeNode left; - public DecodeNode right; - public Integer value; // null si pas une feuille - - public DecodeNode() { - this.left = null; - this.right = null; - this.value = null; - } - - public DecodeNode(DecodeNode left, DecodeNode right, Integer value) { - this.left = left; - this.right = right; - this.value = value; - } - - public boolean isLeaf() { - return this.left == null && this.right == null; - } -} +package fr.iutfbleau.sae.mpif; + +public class DecodeNode { + public DecodeNode left; + public DecodeNode right; + public Integer value; // null si pas une feuille + + public DecodeNode() { + this.left = null; + this.right = null; + this.value = null; + } + + public DecodeNode(DecodeNode left, DecodeNode right, Integer value) { + this.left = left; + this.right = right; + this.value = value; + } + + public boolean isLeaf() { + return this.left == null && this.right == null; + } +} diff --git a/src/fr/iutfbleau/sae/mpif/PIFReader.java b/src/fr/iutfbleau/sae/mpif/PIFReader.java index 1bfbeab..596da0b 100644 --- a/src/fr/iutfbleau/sae/mpif/PIFReader.java +++ b/src/fr/iutfbleau/sae/mpif/PIFReader.java @@ -44,11 +44,27 @@ public class PIFReader { public void readHeader(BitInputStream in) { + // La largeur et l'hauteur de l'image occupe chaqun deux octets soit 16 bits : + this.width = in.readBits(16); + this.height = in.readBits(16); } public void readCanonicalTables(BitInputStream in) { - // TODO: Implement canonical table reading - } + this.lenR = new int[256]; + this.lenG = new int[256]; + this.lenB = new int[256]; + + for (int i = 0; i < 256; i++){ + lenR[i] = in.readBits(8); + } + for (int j = 0; j < 256; j++){ + lenG[j] = in.readBits(8); + } + + for (int k = 0; k < 256; k++){ + lenB[k] = in.readBits(8); + } +} public Map rebuildCanonical(int[] lengths) { // TODO: Implement canonical table reconstruction diff --git a/src/fr/iutfbleau/sae/util/BitinputStream.java b/src/fr/iutfbleau/sae/util/BitinputStream.java index 06ce9ca..0054036 100644 --- a/src/fr/iutfbleau/sae/util/BitinputStream.java +++ b/src/fr/iutfbleau/sae/util/BitinputStream.java @@ -1,115 +1,115 @@ -package fr.iutfbleau.sae.util; -import java.io.IOException; -import java.io.InputStream; - -/** - * Décorateur de flux permettant la lecture binaire à granularité du bit. - *

- * Cette classe encapsule un {@link InputStream} existant et fournit - * des opérations de lecture bit par bit ou par groupes de bits. - * Elle ne gère ni l'ouverture ni la sélection du fichier source. - *

- * - *

- * Utilisée notamment pour le décodage des fichiers compressés - * (ex : format PIF utilisant des codes de Huffman). - *

- * - * - * - * @author Algassimou Pellel Diallo - * @version 1.0 - * @since 2025-12-13 - */ -public class BitInputStream { - - /** Flux d'entrée sous-jacent */ - private final InputStream fluxEntree; - - /** Octet actuellement chargé depuis le flux */ - private int octetCourant; - - /** Position du bit courant dans l'octet (du bit 7 au bit 0) */ - private int positionBit; - - /** Indique si la fin du flux a été atteinte */ - private boolean finDeFlux; - - /** - * Construit un lecteur binaire à partir d'un flux existant. - * - * @param fluxEntree flux d'entrée à décorer - * @throws IllegalArgumentException si le flux est nul - */ - public BitInputStream(InputStream fluxEntree) { - if (fluxEntree == null) { - throw new IllegalArgumentException("Le flux d'entrée ne peut pas être nul"); - } - this.fluxEntree = fluxEntree; - this.octetCourant = 0; - this.positionBit = -1; // force la lecture d'un nouvel octet - this.finDeFlux = false; - } - - /** - * Lit un bit depuis le flux binaire. - * - * @return 0 ou 1 si un bit est lu, -1 si la fin du flux est atteinte - * @throws IOException si une erreur de lecture survient - */ - public int readBit() throws IOException { - if (finDeFlux) { - return -1; - } - - if (this.positionBit < 0) { - int octetLu = this.fluxEntree.read(); - if (octetLu == -1) { - this.finDeFlux = true; - } else { - this.octetCourant = octetLu; - this.positionBit = 7; - } - } - - if (finDeFlux) { - return -1; - } - - int bit = (this.octetCourant >> this.positionBit) & 1; - this.positionBit--; - return bit; - } - - /** - * Lit une séquence de bits consécutifs et les assemble dans un entier. - * - * @param nombreBits nombre de bits à lire (strictement positif) - * @return valeur entière correspondant aux bits lus, - * ou -1 si la fin du flux est atteinte prématurément - * @throws IOException si une erreur de lecture survient - */ - public int readBits(int nombreBits) throws IOException { - int res=0; - for (int i = 0; i < nombreBits; i++) { - int bit = readBit(); - if (bit == -1) { - return -1; - } - res = (res << 1) | bit; - } - return res; - } - - /** - * Ferme le flux d'entrée sous-jacent. - * - * @throws IOException si une erreur survient lors de la fermeture - */ - public void closeFlux() throws IOException { - this.fluxEntree.close(); - } - - - -} +package fr.iutfbleau.sae.util; +import java.io.IOException; +import java.io.InputStream; + +/** + * Décorateur de flux permettant la lecture binaire à granularité du bit. + *

+ * Cette classe encapsule un {@link InputStream} existant et fournit + * des opérations de lecture bit par bit ou par groupes de bits. + * Elle ne gère ni l'ouverture ni la sélection du fichier source. + *

+ * + *

+ * Utilisée notamment pour le décodage des fichiers compressés + * (ex : format PIF utilisant des codes de Huffman). + *

+ * + * + * + * @author Algassimou Pellel Diallo + * @version 1.0 + * @since 2025-12-13 + */ +public class BitInputStream { + + /** Flux d'entrée sous-jacent */ + private final InputStream fluxEntree; + + /** Octet actuellement chargé depuis le flux */ + private int octetCourant; + + /** Position du bit courant dans l'octet (du bit 7 au bit 0) */ + private int positionBit; + + /** Indique si la fin du flux a été atteinte */ + private boolean finDeFlux; + + /** + * Construit un lecteur binaire à partir d'un flux existant. + * + * @param fluxEntree flux d'entrée à décorer + * @throws IllegalArgumentException si le flux est nul + */ + public BitInputStream(InputStream fluxEntree) { + if (fluxEntree == null) { + throw new IllegalArgumentException("Le flux d'entrée ne peut pas être nul"); + } + this.fluxEntree = fluxEntree; + this.octetCourant = 0; + this.positionBit = -1; // force la lecture d'un nouvel octet + this.finDeFlux = false; + } + + /** + * Lit un bit depuis le flux binaire. + * + * @return 0 ou 1 si un bit est lu, -1 si la fin du flux est atteinte + * @throws IOException si une erreur de lecture survient + */ + public int readBit() throws IOException { + if (finDeFlux) { + return -1; + } + + if (this.positionBit < 0) { + int octetLu = this.fluxEntree.read(); + if (octetLu == -1) { + this.finDeFlux = true; + } else { + this.octetCourant = octetLu; + this.positionBit = 7; + } + } + + if (finDeFlux) { + return -1; + } + + int bit = (this.octetCourant >> this.positionBit) & 1; + this.positionBit--; + return bit; + } + + /** + * Lit une séquence de bits consécutifs et les assemble dans un entier. + * + * @param nombreBits nombre de bits à lire (strictement positif) + * @return valeur entière correspondant aux bits lus, + * ou -1 si la fin du flux est atteinte prématurément + * @throws IOException si une erreur de lecture survient + */ + public int readBits(int nombreBits) throws IOException { + int res=0; + for (int i = 0; i < nombreBits; i++) { + int bit = readBit(); + if (bit == -1) { + return -1; + } + res = (res << 1) | bit; + } + return res; + } + + /** + * Ferme le flux d'entrée sous-jacent. + * + * @throws IOException si une erreur survient lors de la fermeture + */ + public void closeFlux() throws IOException { + this.fluxEntree.close(); + } + + + +} diff --git a/src/fr/iutfbleau/sae/util/ByteUtils.java b/src/fr/iutfbleau/sae/util/ByteUtils.java index 8f0f8e4..864363b 100644 --- a/src/fr/iutfbleau/sae/util/ByteUtils.java +++ b/src/fr/iutfbleau/sae/util/ByteUtils.java @@ -1,89 +1,89 @@ -package fr.iutfbleau.sae.util; - -/** - * Classe utilitaire regroupant des opérations de conversion entre - * entiers et octets. - *

- * Elle est utilisée pour encoder et décoder les champs binaires - * du format PIF (largeur, hauteur, tailles, etc.). - *

- * - *

- * Cette classe : - *

    - *
  • ne lit aucun fichier
  • - *
  • n'écrit aucun fichier
  • - *
  • ne manipule pas les bits individuellement
  • - *
- * Elle fournit uniquement des conversions octets ↔ entiers. - *

- */ -public final class ByteUtils { - - /** - * Constructeur privé empêchant l'instanciation. - *

- * Cette classe est purement utilitaire et ne doit pas être instanciée. - *

- */ - private ByteUtils() { - // j'empêche l'instanciation - } - - /** - * Convertit un entier non négatif en deux octets (ordre big-endian). - *

- * L'octet de poids fort est placé en première position, - * suivi de l'octet de poids faible. - *

- * - * @param value valeur entière à convertir (0 ≤ value ≤ 65535) - * @return tableau de deux octets : [octetFort, octetFaible] M - * @throws IllegalArgumentException si la valeur ne tient pas sur 2 octets - */ - public static byte[] toBytes(int value) { - if (value < 0 || value > 0xFFFF) { - throw new IllegalArgumentException( - "La valeur doit être comprise entre 0 et 65535" - ); - } - - byte[] result = new byte[2]; - - /* - * Extraction de l'octet de poids fort : - * - décalage de 8 bits vers la droite - * - masquage pour ne conserver que les 8 bits utiles - */ - result[0] = (byte) ((value >>> 8) & 0xFF); - - /* - * Extraction de l'octet de poids faible : - * - aucun décalage nécessaire - * - masquage pour conserver les 8 bits de droite - */ - result[1] = (byte) (value & 0xFF); - - return result; - } - - /** - * Reconstruit un entier à partir de deux octets (ordre big-endian). - *

- * L'octet de poids fort est replacé dans les bits 15 à 8, - * puis combiné avec l'octet de poids faible. - *

- * - * @param high octet de poids fort - * @param low octet de poids faible - * @return entier reconstruit à partir des deux octets - */ - public static int toInt(byte high, byte low) { - /* - * - masquage pour supprimer le signe des octets Java - * - décalage de l'octet fort vers la gauche - * - combinaison des deux octets par un OU binaire - */ - return ((high & 0xFF) << 8) | (low & 0xFF); - } -} +package fr.iutfbleau.sae.util; + +/** + * Classe utilitaire regroupant des opérations de conversion entre + * entiers et octets. + *

+ * Elle est utilisée pour encoder et décoder les champs binaires + * du format PIF (largeur, hauteur, tailles, etc.). + *

+ * + *

+ * Cette classe : + *

    + *
  • ne lit aucun fichier
  • + *
  • n'écrit aucun fichier
  • + *
  • ne manipule pas les bits individuellement
  • + *
+ * Elle fournit uniquement des conversions octets ↔ entiers. + *

+ */ +public final class ByteUtils { + + /** + * Constructeur privé empêchant l'instanciation. + *

+ * Cette classe est purement utilitaire et ne doit pas être instanciée. + *

+ */ + private ByteUtils() { + // j'empêche l'instanciation + } + + /** + * Convertit un entier non négatif en deux octets (ordre big-endian). + *

+ * L'octet de poids fort est placé en première position, + * suivi de l'octet de poids faible. + *

+ * + * @param value valeur entière à convertir (0 ≤ value ≤ 65535) + * @return tableau de deux octets : [octetFort, octetFaible] M + * @throws IllegalArgumentException si la valeur ne tient pas sur 2 octets + */ + public static byte[] toBytes(int value) { + if (value < 0 || value > 0xFFFF) { + throw new IllegalArgumentException( + "La valeur doit être comprise entre 0 et 65535" + ); + } + + byte[] result = new byte[2]; + + /* + * Extraction de l'octet de poids fort : + * - décalage de 8 bits vers la droite + * - masquage pour ne conserver que les 8 bits utiles + */ + result[0] = (byte) ((value >>> 8) & 0xFF); + + /* + * Extraction de l'octet de poids faible : + * - aucun décalage nécessaire + * - masquage pour conserver les 8 bits de droite + */ + result[1] = (byte) (value & 0xFF); + + return result; + } + + /** + * Reconstruit un entier à partir de deux octets (ordre big-endian). + *

+ * L'octet de poids fort est replacé dans les bits 15 à 8, + * puis combiné avec l'octet de poids faible. + *

+ * + * @param high octet de poids fort + * @param low octet de poids faible + * @return entier reconstruit à partir des deux octets + */ + public static int toInt(byte high, byte low) { + /* + * - masquage pour supprimer le signe des octets Java + * - décalage de l'octet fort vers la gauche + * - combinaison des deux octets par un OU binaire + */ + return ((high & 0xFF) << 8) | (low & 0xFF); + } +} diff --git a/src/fr/iutfbleau/sae/util/GestErreur.java b/src/fr/iutfbleau/sae/util/GestErreur.java index da4779a..be95dd0 100644 --- a/src/fr/iutfbleau/sae/util/GestErreur.java +++ b/src/fr/iutfbleau/sae/util/GestErreur.java @@ -1,8 +1,8 @@ -package fr.iutfbleau.sae.util; - -public class GestErreur { - public static void erreur(String message) { - System.err.println("Erreur : " + message); - System.exit(1); - } +package fr.iutfbleau.sae.util; + +public class GestErreur { + public static void erreur(String message) { + System.err.println("Erreur : " + message); + System.exit(1); + } } \ No newline at end of file diff --git a/src/fr/iutfbleau/sae/vconverter/CodeTablePanel.java b/src/fr/iutfbleau/sae/vconverter/CodeTablePanel.java index 340a228..836d949 100644 --- a/src/fr/iutfbleau/sae/vconverter/CodeTablePanel.java +++ b/src/fr/iutfbleau/sae/vconverter/CodeTablePanel.java @@ -1,110 +1,110 @@ -package fr.iutfbleau.sae.vconverter; - -import javax.swing.*; -import java.awt.*; -import java.util.Map; - -/** - * Panneau d'affichage des codes Huffman et canoniques. - * Affiche les codes pour chaque composante de couleur (rouge, vert, bleu). - * @author Algassimou - */ -public class CodeTablePanel extends JPanel { - - // Zones de texte pour les codes Huffman - private JTextArea textHuffRouge, textHuffVert, textHuffBleu; - - // Zones de texte pour les codes canoniques - private JTextArea textCanonRouge, textCanonVert, textCanonBleu; - - /** - * Constructeur qui initialise l'interface utilisateur. - */ - public CodeTablePanel() { - setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15)); - - // Titre pour les codes Huffman - JLabel titreHuff = new JLabel("Codes Huffman"); - titreHuff.setFont(new Font("SansSerif", Font.BOLD, 16)); - add(titreHuff); - add(Box.createVerticalStrut(10)); - - // Création des zones de texte pour les codes Huffman - textHuffRouge = creerZoneTexte("Rouge"); - textHuffVert = creerZoneTexte("Vert"); - textHuffBleu = creerZoneTexte("Bleu"); - - // Séparateur - add(Box.createVerticalStrut(20)); - - // Titre pour les codes canoniques - JLabel titreCanon = new JLabel("Codes Canoniques"); - titreCanon.setFont(new Font("SansSerif", Font.BOLD, 16)); - add(titreCanon); - add(Box.createVerticalStrut(10)); - - // Création des zones de texte pour les codes canoniques - textCanonRouge = creerZoneTexte("Rouge (Canonique)"); - textCanonVert = creerZoneTexte("Vert (Canonique)"); - textCanonBleu = creerZoneTexte("Bleu (Canonique)"); - } - - /** - * Crée une zone de texte avec une étiquette. - * @param titre Le titre à afficher au-dessus de la zone de texte - * @return La zone de texte configurée - */ - private JTextArea creerZoneTexte(String titre) { - add(new JLabel(titre + ":")); - JTextArea zone = new JTextArea(8, 30); - zone.setEditable(false); - zone.setFont(new Font("Monospaced", Font.PLAIN, 12)); - JScrollPane scroll = new JScrollPane(zone); - scroll.setPreferredSize(new Dimension(300, 120)); - add(scroll); - add(Box.createVerticalStrut(10)); - return zone; - } - - /** - * Met à jour l'affichage des codes Huffman. - * @param rouge Les codes pour la composante rouge - * @param vert Les codes pour la composante verte - * @param bleu Les codes pour la composante bleue - */ - public void updateCodes(Map rouge, - Map vert, - Map bleu) { - mettreAJourZoneTexte(textHuffRouge, rouge); - mettreAJourZoneTexte(textHuffVert, vert); - mettreAJourZoneTexte(textHuffBleu, bleu); - } - - /** - * Met à jour l'affichage des codes canoniques. - * @param rouge Les codes pour la composante rouge - * @param vert Les codes pour la composante verte - * @param bleu Les codes pour la composante bleue - */ - public void updateCanonicalCodes(Map rouge, - Map vert, - Map bleu) { - mettreAJourZoneTexte(textCanonRouge, rouge); - mettreAJourZoneTexte(textCanonVert, vert); - mettreAJourZoneTexte(textCanonBleu, bleu); - } - - /** - * Met à jour le contenu d'une zone de texte avec les codes fournis. - * @param zone La zone de texte à mettre à jour - * @param codes Les codes à afficher - */ - private void mettreAJourZoneTexte(JTextArea zone, Map codes) { - StringBuilder sb = new StringBuilder(); - for (Map.Entry entry : codes.entrySet()) { - sb.append(String.format("%3d : %s%n", entry.getKey(), entry.getValue())); - } - zone.setText(sb.toString()); - } +package fr.iutfbleau.sae.vconverter; + +import javax.swing.*; +import java.awt.*; +import java.util.Map; + +/** + * Panneau d'affichage des codes Huffman et canoniques. + * Affiche les codes pour chaque composante de couleur (rouge, vert, bleu). + * @author Algassimou + */ +public class CodeTablePanel extends JPanel { + + // Zones de texte pour les codes Huffman + private JTextArea textHuffRouge, textHuffVert, textHuffBleu; + + // Zones de texte pour les codes canoniques + private JTextArea textCanonRouge, textCanonVert, textCanonBleu; + + /** + * Constructeur qui initialise l'interface utilisateur. + */ + public CodeTablePanel() { + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15)); + + // Titre pour les codes Huffman + JLabel titreHuff = new JLabel("Codes Huffman"); + titreHuff.setFont(new Font("SansSerif", Font.BOLD, 16)); + add(titreHuff); + add(Box.createVerticalStrut(10)); + + // Création des zones de texte pour les codes Huffman + textHuffRouge = creerZoneTexte("Rouge"); + textHuffVert = creerZoneTexte("Vert"); + textHuffBleu = creerZoneTexte("Bleu"); + + // Séparateur + add(Box.createVerticalStrut(20)); + + // Titre pour les codes canoniques + JLabel titreCanon = new JLabel("Codes Canoniques"); + titreCanon.setFont(new Font("SansSerif", Font.BOLD, 16)); + add(titreCanon); + add(Box.createVerticalStrut(10)); + + // Création des zones de texte pour les codes canoniques + textCanonRouge = creerZoneTexte("Rouge (Canonique)"); + textCanonVert = creerZoneTexte("Vert (Canonique)"); + textCanonBleu = creerZoneTexte("Bleu (Canonique)"); + } + + /** + * Crée une zone de texte avec une étiquette. + * @param titre Le titre à afficher au-dessus de la zone de texte + * @return La zone de texte configurée + */ + private JTextArea creerZoneTexte(String titre) { + add(new JLabel(titre + ":")); + JTextArea zone = new JTextArea(8, 30); + zone.setEditable(false); + zone.setFont(new Font("Monospaced", Font.PLAIN, 12)); + JScrollPane scroll = new JScrollPane(zone); + scroll.setPreferredSize(new Dimension(300, 120)); + add(scroll); + add(Box.createVerticalStrut(10)); + return zone; + } + + /** + * Met à jour l'affichage des codes Huffman. + * @param rouge Les codes pour la composante rouge + * @param vert Les codes pour la composante verte + * @param bleu Les codes pour la composante bleue + */ + public void updateCodes(Map rouge, + Map vert, + Map bleu) { + mettreAJourZoneTexte(textHuffRouge, rouge); + mettreAJourZoneTexte(textHuffVert, vert); + mettreAJourZoneTexte(textHuffBleu, bleu); + } + + /** + * Met à jour l'affichage des codes canoniques. + * @param rouge Les codes pour la composante rouge + * @param vert Les codes pour la composante verte + * @param bleu Les codes pour la composante bleue + */ + public void updateCanonicalCodes(Map rouge, + Map vert, + Map bleu) { + mettreAJourZoneTexte(textCanonRouge, rouge); + mettreAJourZoneTexte(textCanonVert, vert); + mettreAJourZoneTexte(textCanonBleu, bleu); + } + + /** + * Met à jour le contenu d'une zone de texte avec les codes fournis. + * @param zone La zone de texte à mettre à jour + * @param codes Les codes à afficher + */ + private void mettreAJourZoneTexte(JTextArea zone, Map codes) { + StringBuilder sb = new StringBuilder(); + for (Map.Entry entry : codes.entrySet()) { + sb.append(String.format("%3d : %s%n", entry.getKey(), entry.getValue())); + } + zone.setText(sb.toString()); + } } \ No newline at end of file diff --git a/src/fr/iutfbleau/sae/vconverter/ConverterWindow.java b/src/fr/iutfbleau/sae/vconverter/ConverterWindow.java index 9fab33b..09df126 100644 --- a/src/fr/iutfbleau/sae/vconverter/ConverterWindow.java +++ b/src/fr/iutfbleau/sae/vconverter/ConverterWindow.java @@ -1,161 +1,161 @@ -package fr.iutfbleau.sae.vconverter; -import java.awt.image.BufferedImage; -import java.util.Map; -import java.awt.*; -import javax.swing.*; - -import fr.iutfbleau.sae.ConverterController; -import fr.iutfbleau.sae.ExportButtonListener; - -/** - * Fenêtre principale du convertisseur. - * - *

- * Cette classe correspond à la vue principale de l’application. - * Elle centralise l’affichage des informations liées à la conversion - * d’une image (aperçu, fréquences, codes). - *

- * - * - *

- * Elle sert de point d’entrée unique pour la partie graphique - *

- */ -public class ConverterWindow extends JFrame { - - private ImagePreviewPanel imagePreviewPanel; - private FrequencyTablePanel frequencyTablePanel; - private CodeTablePanel codeTablePanel; - - - - /** - * Crée la fenêtre principale du convertisseur. - * - *

- * Le constructeur initialise la fenêtre et met en place - * les différents panneaux graphiques utilisés pour l’affichage. - *

- */ - - public ConverterWindow() { - // Configuration de la fenetre - this.setTitle("Convertisseur PIF - Visualisation des données"); - this.setSize(900, 600); - this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - this.setLocationRelativeTo(null); // Centre la fenêtre - this.setResizable(true); // on autorise le - this.setLayout(new BorderLayout()); - - - - // Initialisation des panels - this.imagePreviewPanel = new ImagePreviewPanel(); - this.frequencyTablePanel = new FrequencyTablePanel(); - this.codeTablePanel = new CodeTablePanel(); - - // Je gere le panel principal - JPanel contentPanel = new JPanel(); - contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.Y_AXIS)); - //contentPanel.setBackground(new Color(255, 0, 0)); // rouge vif pour demo - contentPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - - // Titre - JLabel header = new JLabel(" Convertisseur PIF – Visualisation des données "); - header.setFont(new Font("SansSerif", Font.BOLD, 18)); - header.setAlignmentX(Component.CENTER_ALIGNMENT); - contentPanel.add(header); - - contentPanel.add(Box.createRigidArea(new Dimension(0, 5))); // espace - - // Ajout du panel d'aperçu - contentPanel.add(imagePreviewPanel); - contentPanel.add(Box.createRigidArea(new Dimension(0, 5))); - // Ajout du panel des fréquences - contentPanel.add(frequencyTablePanel); - contentPanel.add(Box.createRigidArea(new Dimension(0, 5))); - // Ajout panel des codes - contentPanel.add(codeTablePanel); - contentPanel.add(Box.createRigidArea(new Dimension(0, 5))); - // la section du scrollpane - JScrollPane scrollPane = new JScrollPane(contentPanel); - scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); - scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); - scrollPane.getVerticalScrollBar().setUnitIncrement(16); // scroll plus adouci fluide - - this.add(scrollPane, BorderLayout.CENTER); - this.setVisible(true); - } - - - - /** - * Met à jour l’image affichée dans la zone d’aperçu. - * - *

- * Cette méthode est appelée lorsque l’image à convertir - * a été chargée. La fenêtre ne modifie pas l’image : - * elle la transmet simplement au panneau d’aperçu. - *

- * - * @param img image à afficher - */ - public void setImagePreview(BufferedImage img) { - imagePreviewPanel.setImage(img); - } - - /** - * Met à jour l’affichage des tables de fréquences. - */ - public void setFrequencyTable(int[] freqR,int[] freqG,int[] freqB) { - frequencyTablePanel.updateFrequencies(freqR,freqG,freqB); - } - - /** - * Met à jour l’affichage des codes Huffman. - * - *

- * Elle permet uniquement d’afficher les codes - * qui ont été produits par la partie traitement. - *

- */ - public void setHuffmanTable(Map codesRouge, - Map codesVert, - Map codesBleu) { - codeTablePanel.updateCodes(codesRouge, codesVert, codesBleu); - } - - /** - * Met à jour l’affichage des codes canoniques. - * - *

- * Les codes canoniques sont transmis au panneau - * chargé de leur affichage. - *

- */ - public void setCanonicalTable(Map codesRouge, - Map codesVert, - Map codesBleu) { - codeTablePanel.updateCanonicalCodes(codesRouge, codesVert, codesBleu); - } - - public void addSaveButton(ConverterController controller) { - JButton saveBtn = new JButton("Exporter en .pif"); - ExportButtonListener ecouteur =new ExportButtonListener(controller); - saveBtn.addActionListener(ecouteur); - - // panneau du bas - JPanel bottomPanel = new JPanel(); - bottomPanel.setLayout(new FlowLayout(FlowLayout.CENTER)); - bottomPanel.add(saveBtn); - - // ajoute au bas de la fenêtre - this.add(bottomPanel, BorderLayout.SOUTH); - - // rafraîchir l'affichage - this.revalidate(); - this.repaint(); -} - - -} +package fr.iutfbleau.sae.vconverter; +import java.awt.image.BufferedImage; +import java.util.Map; +import java.awt.*; +import javax.swing.*; + +import fr.iutfbleau.sae.ConverterController; +import fr.iutfbleau.sae.ExportButtonListener; + +/** + * Fenêtre principale du convertisseur. + * + *

+ * Cette classe correspond à la vue principale de l’application. + * Elle centralise l’affichage des informations liées à la conversion + * d’une image (aperçu, fréquences, codes). + *

+ * + * + *

+ * Elle sert de point d’entrée unique pour la partie graphique + *

+ */ +public class ConverterWindow extends JFrame { + + private ImagePreviewPanel imagePreviewPanel; + private FrequencyTablePanel frequencyTablePanel; + private CodeTablePanel codeTablePanel; + + + + /** + * Crée la fenêtre principale du convertisseur. + * + *

+ * Le constructeur initialise la fenêtre et met en place + * les différents panneaux graphiques utilisés pour l’affichage. + *

+ */ + + public ConverterWindow() { + // Configuration de la fenetre + this.setTitle("Convertisseur PIF - Visualisation des données"); + this.setSize(900, 600); + this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + this.setLocationRelativeTo(null); // Centre la fenêtre + this.setResizable(true); // on autorise le + this.setLayout(new BorderLayout()); + + + + // Initialisation des panels + this.imagePreviewPanel = new ImagePreviewPanel(); + this.frequencyTablePanel = new FrequencyTablePanel(); + this.codeTablePanel = new CodeTablePanel(); + + // Je gere le panel principal + JPanel contentPanel = new JPanel(); + contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.Y_AXIS)); + //contentPanel.setBackground(new Color(255, 0, 0)); // rouge vif pour demo + contentPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + + // Titre + JLabel header = new JLabel(" Convertisseur PIF – Visualisation des données "); + header.setFont(new Font("SansSerif", Font.BOLD, 18)); + header.setAlignmentX(Component.CENTER_ALIGNMENT); + contentPanel.add(header); + + contentPanel.add(Box.createRigidArea(new Dimension(0, 5))); // espace + + // Ajout du panel d'aperçu + contentPanel.add(imagePreviewPanel); + contentPanel.add(Box.createRigidArea(new Dimension(0, 5))); + // Ajout du panel des fréquences + contentPanel.add(frequencyTablePanel); + contentPanel.add(Box.createRigidArea(new Dimension(0, 5))); + // Ajout panel des codes + contentPanel.add(codeTablePanel); + contentPanel.add(Box.createRigidArea(new Dimension(0, 5))); + // la section du scrollpane + JScrollPane scrollPane = new JScrollPane(contentPanel); + scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); + scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + scrollPane.getVerticalScrollBar().setUnitIncrement(16); // scroll plus adouci fluide + + this.add(scrollPane, BorderLayout.CENTER); + this.setVisible(true); + } + + + + /** + * Met à jour l’image affichée dans la zone d’aperçu. + * + *

+ * Cette méthode est appelée lorsque l’image à convertir + * a été chargée. La fenêtre ne modifie pas l’image : + * elle la transmet simplement au panneau d’aperçu. + *

+ * + * @param img image à afficher + */ + public void setImagePreview(BufferedImage img) { + imagePreviewPanel.setImage(img); + } + + /** + * Met à jour l’affichage des tables de fréquences. + */ + public void setFrequencyTable(int[] freqR,int[] freqG,int[] freqB) { + frequencyTablePanel.updateFrequencies(freqR,freqG,freqB); + } + + /** + * Met à jour l’affichage des codes Huffman. + * + *

+ * Elle permet uniquement d’afficher les codes + * qui ont été produits par la partie traitement. + *

+ */ + public void setHuffmanTable(Map codesRouge, + Map codesVert, + Map codesBleu) { + codeTablePanel.updateCodes(codesRouge, codesVert, codesBleu); + } + + /** + * Met à jour l’affichage des codes canoniques. + * + *

+ * Les codes canoniques sont transmis au panneau + * chargé de leur affichage. + *

+ */ + public void setCanonicalTable(Map codesRouge, + Map codesVert, + Map codesBleu) { + codeTablePanel.updateCanonicalCodes(codesRouge, codesVert, codesBleu); + } + + public void addSaveButton(ConverterController controller) { + JButton saveBtn = new JButton("Exporter en .pif"); + ExportButtonListener ecouteur =new ExportButtonListener(controller); + saveBtn.addActionListener(ecouteur); + + // panneau du bas + JPanel bottomPanel = new JPanel(); + bottomPanel.setLayout(new FlowLayout(FlowLayout.CENTER)); + bottomPanel.add(saveBtn); + + // ajoute au bas de la fenêtre + this.add(bottomPanel, BorderLayout.SOUTH); + + // rafraîchir l'affichage + this.revalidate(); + this.repaint(); +} + + +} diff --git a/src/fr/iutfbleau/sae/vconverter/FrequencyTablePanel.java b/src/fr/iutfbleau/sae/vconverter/FrequencyTablePanel.java index 0d0f1ca..dbe1f95 100644 --- a/src/fr/iutfbleau/sae/vconverter/FrequencyTablePanel.java +++ b/src/fr/iutfbleau/sae/vconverter/FrequencyTablePanel.java @@ -1,70 +1,70 @@ -package fr.iutfbleau.sae.vconverter; - -import javax.swing.*; -import java.awt.*; - - -public class FrequencyTablePanel extends JPanel { - // 3 Zone de texte pour la fréquence du rouge , du vert et du bleu - private JTextArea freqRouge , freqVert , freqBleu; - - public FrequencyTablePanel() { - setLayout(new BoxLayout(this , BoxLayout.Y_AXIS)); - setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15)); - - // Premiere étiquette pour les fréquences en géneral - JLabel etiquette1 = new JLabel("Frequence"); - etiquette1.setFont(new Font("SansSerif", Font.BOLD, 16)); - super.add(etiquette1); - super.add(Box.createVerticalStrut(10)); - - - // Puis création de zone de texte pour le rouge , le vert et le bleu - this.freqRouge = creationZoneText("Rouge"); - this.freqVert = creationZoneText("Vert"); - this.freqBleu = creationZoneText("Bleu"); - - - - - } - - private JTextArea creationZoneText(String t) { - super.add(new JLabel(t + ":")); - GridLayout gestionnaire_mise_en_page = new GridLayout(5,5,10,10); - JTextArea zone = new JTextArea(8, 30); - zone.setLayout(gestionnaire_mise_en_page); - zone.setEditable(false); - zone.setFont(new Font("Monospaced", Font.PLAIN, 12)); - JScrollPane scroll = new JScrollPane(zone); - scroll.setPreferredSize(new Dimension(300, 120)); - add(scroll); - add(Box.createVerticalStrut(10)); - return zone; - } - - - public void updateFrequencies(int[] freqR,int[] freqG,int[] freqB) { - mettreAJour(freqRouge,freqR); - mettreAJour(freqVert,freqG); - mettreAJour(freqBleu,freqB); - - } - - - public void mettreAJour(JTextArea zone,int[] frequence){ - StringBuilder string = new StringBuilder(); - - for(int i = 0 ; i < frequence.length ; i++){ - string.append(String.format("%3d : %s%n", i, frequence[i])); - - if(i%10 == 0 && i!=0){ - string.append("\n"); - } - - } - - - zone.setText(string.toString()); - } -} +package fr.iutfbleau.sae.vconverter; + +import javax.swing.*; +import java.awt.*; + + +public class FrequencyTablePanel extends JPanel { + // 3 Zone de texte pour la fréquence du rouge , du vert et du bleu + private JTextArea freqRouge , freqVert , freqBleu; + + public FrequencyTablePanel() { + setLayout(new BoxLayout(this , BoxLayout.Y_AXIS)); + setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15)); + + // Premiere étiquette pour les fréquences en géneral + JLabel etiquette1 = new JLabel("Frequence"); + etiquette1.setFont(new Font("SansSerif", Font.BOLD, 16)); + super.add(etiquette1); + super.add(Box.createVerticalStrut(10)); + + + // Puis création de zone de texte pour le rouge , le vert et le bleu + this.freqRouge = creationZoneText("Rouge"); + this.freqVert = creationZoneText("Vert"); + this.freqBleu = creationZoneText("Bleu"); + + + + + } + + private JTextArea creationZoneText(String t) { + super.add(new JLabel(t + ":")); + GridLayout gestionnaire_mise_en_page = new GridLayout(5,5,10,10); + JTextArea zone = new JTextArea(8, 30); + zone.setLayout(gestionnaire_mise_en_page); + zone.setEditable(false); + zone.setFont(new Font("Monospaced", Font.PLAIN, 12)); + JScrollPane scroll = new JScrollPane(zone); + scroll.setPreferredSize(new Dimension(300, 120)); + add(scroll); + add(Box.createVerticalStrut(10)); + return zone; + } + + + public void updateFrequencies(int[] freqR,int[] freqG,int[] freqB) { + mettreAJour(freqRouge,freqR); + mettreAJour(freqVert,freqG); + mettreAJour(freqBleu,freqB); + + } + + + public void mettreAJour(JTextArea zone,int[] frequence){ + StringBuilder string = new StringBuilder(); + + for(int i = 0 ; i < frequence.length ; i++){ + string.append(String.format("%3d : %s%n", i, frequence[i])); + + if(i%10 == 0 && i!=0){ + string.append("\n"); + } + + } + + + zone.setText(string.toString()); + } +} diff --git a/src/fr/iutfbleau/sae/vconverter/ImagePreviewPanel.java b/src/fr/iutfbleau/sae/vconverter/ImagePreviewPanel.java index 803e11c..5123983 100644 --- a/src/fr/iutfbleau/sae/vconverter/ImagePreviewPanel.java +++ b/src/fr/iutfbleau/sae/vconverter/ImagePreviewPanel.java @@ -1,76 +1,76 @@ -package fr.iutfbleau.sae.vconverter; - -import java.awt.image.BufferedImage; -import javax.swing.JPanel; -import java.awt.*; - /** - * Le panneau d’aperçu de l’image. - * - *

- * Ce panneau affiche un aperçu de l’image en cours de conversion. - *

- */ - - -public class ImagePreviewPanel extends JPanel { - - private BufferedImage image; - - // je donne une taille préférée au panel - public ImagePreviewPanel() { - this.setPreferredSize(new Dimension(600, 800)); - this.setMinimumSize(new Dimension(600, 800)); - } - - - public void setImage(BufferedImage img) { - this.image = img; - repaint(); - - } - - @Override - protected void paintComponent(Graphics pinceau) { - // Appel de la méthode parente pour effacer l'arrière-plan - super.paintComponent(pinceau); - - if (image == null) { - return; - } - - // Recuperer les dimensions du panel pour centrer l'image - int panelWidth = this.getWidth(); - int panelHeight = this.getHeight(); - - // Recuperer les dimensions de l'image - int imgWidth = image.getWidth(); - int imgHeight = image.getHeight(); - - // Je calcule le facteur du reduction (si l'image est trop grande) en gros le dezoom - double scale = Math.min( - (double) panelWidth / imgWidth, - (double) panelHeight / imgHeight - ); - - // Si l'image est plus petite que le panel, on ne la redimensionne pas donc scale = 1 - if (scale > 1.0) { - scale = 1.0; - } - - // je recalcule les dimensions de l'image à dessiner - int drawWidth = (int) (imgWidth * scale); - int drawHeight = (int) (imgHeight * scale); - - // Centrage de l'image dans le panel - int x = (panelWidth - drawWidth) / 2; - int y = (panelHeight - drawHeight) / 2; - - Graphics2D pinceau2D = (Graphics2D) pinceau; - pinceau2D.setRenderingHint( - RenderingHints.KEY_INTERPOLATION, - RenderingHints.VALUE_INTERPOLATION_BILINEAR - ); - - pinceau2D.drawImage(image, x, y, drawWidth, drawHeight, this); - } +package fr.iutfbleau.sae.vconverter; + +import java.awt.image.BufferedImage; +import javax.swing.JPanel; +import java.awt.*; + /** + * Le panneau d’aperçu de l’image. + * + *

+ * Ce panneau affiche un aperçu de l’image en cours de conversion. + *

+ */ + + +public class ImagePreviewPanel extends JPanel { + + private BufferedImage image; + + // je donne une taille préférée au panel + public ImagePreviewPanel() { + this.setPreferredSize(new Dimension(600, 800)); + this.setMinimumSize(new Dimension(600, 800)); + } + + + public void setImage(BufferedImage img) { + this.image = img; + repaint(); + + } + + @Override + protected void paintComponent(Graphics pinceau) { + // Appel de la méthode parente pour effacer l'arrière-plan + super.paintComponent(pinceau); + + if (image == null) { + return; + } + + // Recuperer les dimensions du panel pour centrer l'image + int panelWidth = this.getWidth(); + int panelHeight = this.getHeight(); + + // Recuperer les dimensions de l'image + int imgWidth = image.getWidth(); + int imgHeight = image.getHeight(); + + // Je calcule le facteur du reduction (si l'image est trop grande) en gros le dezoom + double scale = Math.min( + (double) panelWidth / imgWidth, + (double) panelHeight / imgHeight + ); + + // Si l'image est plus petite que le panel, on ne la redimensionne pas donc scale = 1 + if (scale > 1.0) { + scale = 1.0; + } + + // je recalcule les dimensions de l'image à dessiner + int drawWidth = (int) (imgWidth * scale); + int drawHeight = (int) (imgHeight * scale); + + // Centrage de l'image dans le panel + int x = (panelWidth - drawWidth) / 2; + int y = (panelHeight - drawHeight) / 2; + + Graphics2D pinceau2D = (Graphics2D) pinceau; + pinceau2D.setRenderingHint( + RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR + ); + + pinceau2D.drawImage(image, x, y, drawWidth, drawHeight, this); + } } \ No newline at end of file diff --git a/src/fr/iutfbleau/sae/vviewer/ImagePanel.java b/src/fr/iutfbleau/sae/vviewer/ImagePanel.java new file mode 100644 index 0000000..17f6cda --- /dev/null +++ b/src/fr/iutfbleau/sae/vviewer/ImagePanel.java @@ -0,0 +1,7 @@ +package fr.iutfbleau.sae.vviewer; + +public class ImagePanel extends JPanel{ + + + +} \ No newline at end of file diff --git a/src/fr/iutfbleau/sae/vviewer/ViewerWindow.java b/src/fr/iutfbleau/sae/vviewer/ViewerWindow.java new file mode 100644 index 0000000..9df89f0 --- /dev/null +++ b/src/fr/iutfbleau/sae/vviewer/ViewerWindow.java @@ -0,0 +1,11 @@ +package fr.iutfbleau.sae.vviewer; + +public class ViewerWindow extends JFrame{ + + + + + + + +} \ No newline at end of file diff --git a/temp/learning-Log.txt b/temp/learning-Log.txt index b85448d..ec1e78d 100644 --- a/temp/learning-Log.txt +++ b/temp/learning-Log.txt @@ -1,50 +1,50 @@ -Learning log – Problème de blocage de la fenêtre après la sauvegarde: - - Après avoir implémenté la fonctionnalité d’export au format PIF depuis l’interface du convertisseur, - j’ai rencontré un problème important : une fois que je cliquais sur le bouton d’exportation, - la fenêtre se figeait complètement. Elle restait visible, mais impossible à fermer ou à interagir avec. - Le programme semblait bloqué. - - En analysant le comportement et en utilisant des impressions de debug, j’ai constaté que le blocage n’était pas lié à l’écriture du - fichier ni à la logique du convertisseur, mais bien à un problème de gestion des threads dans Swing. - - Swing repose sur un fonctionnement particulier : toute l’interface graphique est gérée par un seul thread dédié, - appelé l’Event Dispatch Thread (EDT). Ce thread est responsable de tout ce qui concerne l’interface utilisateur : - la gestion des clics, le rafraîchissement de la fenêtre, la fermeture, le dessin et l’affichage en général. - Tant que ce thread tourne correctement, l’application reste réactive. - - L’EDT ne démarre réellement qu’après l’appel à la méthode permettant d’afficher la fenêtre. À partir de ce moment, - toutes les opérations qui modifient l’interface devraient strictement être exécutées sur ce thread. - C’est une règle fondamentale pour éviter les blocages. - - En examinant mon programme, je me suis rendu compte que le problème venait de la manière dont j’avais structuré mon point d’entrée. - Mon programme principal créait la fenêtre, le contrôleur, puis lançait immédiatement tout le processus de conversion, - qui incluait le chargement du fichier image, le calcul des fréquences, la construction des arbres de Huffman, - la génération des codes canoniques, et éventuellement l’écriture du fichier PIF. - Ce sont des opérations potentiellement longues et qui se déroulaient sur le thread principal, - avant même que l’EDT ne prenne le relais pour gérer l’interface. - - Cela avait pour conséquences que Swing se retrouvait dans un état instable, puisque certaines opérations graphiques avaient été réalisées - hors du thread dédié. - C’est exactement ce qui provoquait le gel de l’interface : une fois le fichier enregistré, la fenêtre ne répondait plus car - l’EDT était bloqué ou interrompu, empêchant toute interaction, y compris la fermeture de la fenêtre. - - Une fois le problème identifié, les solutions étaient claires. Il fallait s’assurer que toutes les opérations qui touchent - a l’interface graphique soient exécutées sur l’Event Dispatch Thread. Cela signifie que toute interaction, y compris l’ouverture - d’un sélecteur de fichiers, doit obligatoirement être déclenchée dans ce contexte. De plus, il fallait veiller à ne pas exécuter - de longues opérations synchrones avant le démarrage complet de l’EDT. - - La solution consiste donc à déléguer l’appel du processus de conversion au thread graphique, en utilisant le mécanisme fourni par - Swing pour garantir que le code s’exécute sur l’EDT. Une autre possibilité serait d’exécuter les opérations lourdes dans un thread en - arrière-plan pour éviter de bloquer l’interface, mais dans tous les cas le respect strict de la séparation entre traitements et interface - est essentiel. - - Grâce à cette analyse, j’ai mieux compris la manière dont Swing gère les threads et j’ai pu corriger la structure de mon programme - afin qu’il reste totalement réactif, même après l’export. Cette expérience m’a rappelé l’importance de maîtriser les principes fondamentaux - des bibliothèques graphiques et leurs contraintes en matière de multithreading. - - - - - +Learning log – Problème de blocage de la fenêtre après la sauvegarde: + + Après avoir implémenté la fonctionnalité d’export au format PIF depuis l’interface du convertisseur, + j’ai rencontré un problème important : une fois que je cliquais sur le bouton d’exportation, + la fenêtre se figeait complètement. Elle restait visible, mais impossible à fermer ou à interagir avec. + Le programme semblait bloqué. + + En analysant le comportement et en utilisant des impressions de debug, j’ai constaté que le blocage n’était pas lié à l’écriture du + fichier ni à la logique du convertisseur, mais bien à un problème de gestion des threads dans Swing. + + Swing repose sur un fonctionnement particulier : toute l’interface graphique est gérée par un seul thread dédié, + appelé l’Event Dispatch Thread (EDT). Ce thread est responsable de tout ce qui concerne l’interface utilisateur : + la gestion des clics, le rafraîchissement de la fenêtre, la fermeture, le dessin et l’affichage en général. + Tant que ce thread tourne correctement, l’application reste réactive. + + L’EDT ne démarre réellement qu’après l’appel à la méthode permettant d’afficher la fenêtre. À partir de ce moment, + toutes les opérations qui modifient l’interface devraient strictement être exécutées sur ce thread. + C’est une règle fondamentale pour éviter les blocages. + + En examinant mon programme, je me suis rendu compte que le problème venait de la manière dont j’avais structuré mon point d’entrée. + Mon programme principal créait la fenêtre, le contrôleur, puis lançait immédiatement tout le processus de conversion, + qui incluait le chargement du fichier image, le calcul des fréquences, la construction des arbres de Huffman, + la génération des codes canoniques, et éventuellement l’écriture du fichier PIF. + Ce sont des opérations potentiellement longues et qui se déroulaient sur le thread principal, + avant même que l’EDT ne prenne le relais pour gérer l’interface. + + Cela avait pour conséquences que Swing se retrouvait dans un état instable, puisque certaines opérations graphiques avaient été réalisées + hors du thread dédié. + C’est exactement ce qui provoquait le gel de l’interface : une fois le fichier enregistré, la fenêtre ne répondait plus car + l’EDT était bloqué ou interrompu, empêchant toute interaction, y compris la fermeture de la fenêtre. + + Une fois le problème identifié, les solutions étaient claires. Il fallait s’assurer que toutes les opérations qui touchent + a l’interface graphique soient exécutées sur l’Event Dispatch Thread. Cela signifie que toute interaction, y compris l’ouverture + d’un sélecteur de fichiers, doit obligatoirement être déclenchée dans ce contexte. De plus, il fallait veiller à ne pas exécuter + de longues opérations synchrones avant le démarrage complet de l’EDT. + + La solution consiste donc à déléguer l’appel du processus de conversion au thread graphique, en utilisant le mécanisme fourni par + Swing pour garantir que le code s’exécute sur l’EDT. Une autre possibilité serait d’exécuter les opérations lourdes dans un thread en + arrière-plan pour éviter de bloquer l’interface, mais dans tous les cas le respect strict de la séparation entre traitements et interface + est essentiel. + + Grâce à cette analyse, j’ai mieux compris la manière dont Swing gère les threads et j’ai pu corriger la structure de mon programme + afin qu’il reste totalement réactif, même après l’export. Cette expérience m’a rappelé l’importance de maîtriser les principes fondamentaux + des bibliothèques graphiques et leurs contraintes en matière de multithreading. + + + + + le proble aussi avec mon flush infini \ No newline at end of file diff --git a/temp/test.pif b/temp/test.pif new file mode 100644 index 0000000..49ed9a3 Binary files /dev/null and b/temp/test.pif differ