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+ * 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- * 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 : - *
- * 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 : + *
+ * 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- * 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- * Les codes canoniques sont transmis au panneau - * chargé de leur affichage. - *
- */ - public void setCanonicalTable(Map+ * 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+ * Les codes canoniques sont transmis au panneau + * chargé de leur affichage. + *
+ */ + public void setCanonicalTable(Map- * 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