petit push sprint 3 fini

This commit is contained in:
AlgaLaptop
2026-01-05 10:19:59 +01:00
parent d20ef2c406
commit 6ec6ac85a4
52 changed files with 1059 additions and 842 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
+68 -50
View File
@@ -32,12 +32,14 @@ all: \
# Compilation des classes main
$(BIN)/$(PKG_PATH)/Convertisseur.class: $(BIN) \
$(BIN)/$(PKG_PATH)/ConverterController.class \
$(BIN)/$(PKG_PATH)/vconverter/ConverterWindow.class \
$(BIN)/$(PKG_PATH)/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) \
$(BIN)/$(PKG_PATH)/ViewerWindow.class \
$(BIN)/$(PKG_PATH)/ViewerControleur.class \
$(SRC)/$(PKG_PATH)/Viewer.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/Viewer.java
@@ -50,9 +52,9 @@ $(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/DecodeNode.class: $(BIN) \
$(SRC)/$(PKG_PATH)/util/DecodeNode.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/util/DecodeNode.java
$(BIN)/$(PKG_PATH)/util/BitInputStream.class: $(BIN) \
$(SRC)/$(PKG_PATH)/util/BitInputStream.java
@@ -62,15 +64,19 @@ $(BIN)/$(PKG_PATH)/util/BitOutputStream.class: $(BIN) \
$(SRC)/$(PKG_PATH)/util/BitOutputStream.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/util/BitOutputStream.java
$(BIN)/$(PKG_PATH)/util/GestionErreur.class: $(BIN) \
$(SRC)/$(PKG_PATH)/util/GestionErreur.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/util/GestionErreur.java
$(BIN)/$(PKG_PATH)/util/HuffmanNode.class: $(BIN) \
$(SRC)/$(PKG_PATH)/util/HuffmanNode.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/util/HuffmanNode.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 \
@@ -78,93 +84,105 @@ $(BIN)/$(PKG_PATH)/mhuffman/CanonicalCode.class: $(BIN) \
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mhuffman/CanonicalCode.java
$(BIN)/$(PKG_PATH)/mhuffman/FrequencyTable.class: $(BIN) \
$(BIN)/$(PKG_PATH)/mimage/RGBImage.class \
$(BIN)/$(PKG_PATH)/mpif/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 \
$(BIN)/$(PKG_PATH)/util/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)/ImagePreviewPanel.class: $(BIN) \
$(SRC)/$(PKG_PATH)/ImagePreviewPanel.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/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)/FrequencyTablePanel.class: $(BIN) \
$(SRC)/$(PKG_PATH)/FrequencyTablePanel.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/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)/CodeTablePanel.class: $(BIN) \
$(SRC)/$(PKG_PATH)/CodeTablePanel.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/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
$(BIN)/$(PKG_PATH)/ViewerWindow.class: $(BIN) \
$(SRC)/$(PKG_PATH)/ViewerWindow.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/ViewerWindow.java
# Compilation PIFWriter
# Compilation des classe mpif
$(BIN)/$(PKG_PATH)/mpif/Pixel.class: $(BIN) \
$(SRC)/$(PKG_PATH)/mpif/Pixel.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mpif/Pixel.java
$(BIN)/$(PKG_PATH)/mpif/RGBImage.class: $(BIN) \
$(BIN)/$(PKG_PATH)/mpif/Pixel.class \
$(SRC)/$(PKG_PATH)/mpif/RGBImage.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mpif/RGBImage.java
$(BIN)/$(PKG_PATH)/mpif/PIFWriter.class: $(BIN) \
$(BIN)/$(PKG_PATH)/mimage/RGBImage.class \
$(BIN)/$(PKG_PATH)/mpif/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
$(BIN)/$(PKG_PATH)/mpif/PIFReader.class: $(BIN) \
$(BIN)/$(PKG_PATH)/mpif/RGBImage.class \
$(BIN)/$(PKG_PATH)/util/BitInputStream.class \
$(BIN)/$(PKG_PATH)/util/DecodeNode.class \
$(SRC)/$(PKG_PATH)/mpif/PIFReader.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/mpif/PIFReader.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: \
$(BIN)/$(PKG_PATH)/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 \
$(SRC)/$(PKG_PATH)/ConverterWindow.java \
$(BIN)/$(PKG_PATH)/mpif/Pixel.class \
$(BIN)/$(PKG_PATH)/mpif/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)/ImagePreviewPanel.class \
$(BIN)/$(PKG_PATH)/FrequencyTablePanel.class \
$(BIN)/$(PKG_PATH)/CodeTablePanel.class \
$(BIN)/$(PKG_PATH)/util/GestionErreur.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
$(SRC)/$(PKG_PATH)/ConverterWindow.java
#Controleur de viewer
$(BIN)/$(PKG_PATH)/ViewerControleur.class: $(BIN) \
$(BIN)/$(PKG_PATH)/mpif/RGBImage.class \
$(BIN)/$(PKG_PATH)/util/GestionErreur.class \
$(BIN)/$(PKG_PATH)/mpif/PIFReader.class \
$(SRC)/$(PKG_PATH)/ViewerControleur.java
$(JAVAC) -cp $(BIN) -d $(BIN) $(SRC)/$(PKG_PATH)/ViewerControleur.java
# Exécution
run-conv: all
$(JAVA) -cp $(BIN) $(MAIN_CONVERTER) $(ARGS)
run-view: all
$(JAVA) -cp $(BIN) $(MAIN_VIEWER)
run-view: $(BIN)/$(PKG_PATH)/Viewer.class
$(JAVA) -cp $(BIN) $(MAIN_VIEWER) $(ARGS)
# Documentation
doc: $(DOC)
@@ -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<Integer, String> rouge,
Map<Integer, String> vert,
Map<Integer, String> 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<Integer, String> rouge,
Map<Integer, String> vert,
Map<Integer, String> 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<Integer, String> codes) {
StringBuilder sb = new StringBuilder();
for (Map.Entry<Integer, String> entry : codes.entrySet()) {
sb.append(String.format("%3d : %s%n", entry.getKey(), entry.getValue()));
}
zone.setText(sb.toString());
}
package fr.iutfbleau.sae;
import java.awt.*;
import java.util.Map;
import javax.swing.*;
/**
* 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<Integer, String> rouge,
Map<Integer, String> vert,
Map<Integer, String> 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<Integer, String> rouge,
Map<Integer, String> vert,
Map<Integer, String> 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<Integer, String> codes) {
StringBuilder sb = new StringBuilder();
for (Map.Entry<Integer, String> entry : codes.entrySet()) {
sb.append(String.format("%3d : %s%n", entry.getKey(), entry.getValue()));
}
zone.setText(sb.toString());
}
}
+34 -43
View File
@@ -1,14 +1,15 @@
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 fr.iutfbleau.sae.mpif.Pixel;
import fr.iutfbleau.sae.mpif.RGBImage;
import fr.iutfbleau.sae.util.GestionErreur;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
/**
* Contrôleur pour la conversion d'images.
@@ -45,8 +46,6 @@ public class ConverterController {
this.fen = fen;
this.outputPath = out;
this.inputPath = in;
System.out.println(this.inputPath+" ==> "+this.outputPath);
}
@@ -76,24 +75,19 @@ public class ConverterController {
this.image.setPixel(x, y, new Pixel(r, g, b));
}
}
// Mettre à jour le GUI
this.fen.setImagePreview(buffimage);
} catch (Exception e) {
e.printStackTrace();
} catch (IOException e) {
GestionErreur.afficherErreur("Erreur lors du chargement : " + e.getMessage());
}
}
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();
if (this.image == null) {
System.out.println("Gros pepin");
}
this.frequencyTable.computeFromImage(this.image);
// Mettre à jour le GUI avec les fréquences
@@ -105,12 +99,6 @@ public class ConverterController {
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();
@@ -123,12 +111,7 @@ public class ConverterController {
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;
}
public void computeCanonical(){
CanonicalCode codeCanoniques = new CanonicalCode();
this.canonRED = codeCanoniques.generateCodes(this.abrHuffmanR);
this.canonGREEN = codeCanoniques.generateCodes(this.abrHuffmanG);
@@ -139,10 +122,11 @@ public class ConverterController {
}
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.");
// je vérifie que l'image et les codes canoniques sont disponibles
if(this.image == null || this.canonRED == null){
GestionErreur.afficherErreur("Impossible de sauvegarder : image ou codes canoniques manquants.");
return;
}
@@ -150,16 +134,15 @@ public class ConverterController {
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);
GestionErreur.afficherErreur("Erreur lors de l’écriture du fichier .pif : ");
}
}
public void saveViaBtn() {
try {
if (outputPath != null) {
saveAsPIF(outputPath);
System.out.println("Sauvegarde dans : " + outputPath);
GestionErreur.afficherInfo("Fichier sauvegardé avec succès. Chemin : " + outputPath);
return;
}
@@ -170,23 +153,31 @@ public class ConverterController {
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());
new Thread(() -> {
try {
saveAsPIF(chooser.getSelectedFile().getAbsolutePath());
GestionErreur.afficherInfo("Fichier sauvegardé avec succès : " + chooser.getSelectedFile().getName());
} catch (Exception e) {
GestionErreur.afficherErreur("Erreur lors de la sauvegarde : " + e.getMessage());
}
}).start();
}
System.out.println("Via BTN Sauvegarde terminée.");
} catch (Exception ex) {
System.out.println("Erreur lors de la sauvegarde : " + ex.getMessage());
} catch (Exception e) {
GestionErreur.afficherErreur("Erreur lors de la sauvegarde : ");
}
}
public void StartconvessionProcess(){
public void convessionProcess(){
// chragement
if (this.inputPath != null) {
// Chargement direct depuis les arguments
File file = new File(inputPath);
if (!file.exists()) {
GestionErreur.afficherErreur("Le fichier n'existe pas : " + inputPath);
System.exit(1);
return;
}
this.loadImage(file);
}else{
// Sinon JFileChooser pour choisir l'image
@@ -195,7 +186,7 @@ public class ConverterController {
if (choosser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
this.loadImage(choosser.getSelectedFile());
}else {
System.err.println("Aucune image choisie. Arrêt du programme.");
GestionErreur.afficherErreur("Aucune image choisie. Arrêt du programme.");
System.exit(1);
return;
}
@@ -209,7 +200,7 @@ public class ConverterController {
// Sauvegarder: un second argument est donné sauvegarde automatique
if (this.outputPath != null) {
this.saveAsPIF(this.outputPath);
System.out.println("Fichier sauvegardé automatiquement : " + this.outputPath);
GestionErreur.afficherInfo("Fichier sauvegardé automatiquement : " + this.outputPath);
}else{
// pas de deuxième argument j'ajoute un boutton pour choisir avec un jfilechoser
fen.addSaveButton(this);
@@ -1,161 +1,159 @@
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.
*
* <p>
* Cette classe correspond à la vue principale de lapplication.
* Elle centralise laffichage des informations liées à la conversion
* dune image (aperçu, fréquences, codes).
* </p>
*
*
* <p>
* Elle sert de point dentrée unique pour la partie graphique
* </p>
*/
public class ConverterWindow extends JFrame {
private ImagePreviewPanel imagePreviewPanel;
private FrequencyTablePanel frequencyTablePanel;
private CodeTablePanel codeTablePanel;
/**
* Crée la fenêtre principale du convertisseur.
*
* <p>
* Le constructeur initialise la fenêtre et met en place
* les différents panneaux graphiques utilisés pour laffichage.
* </p>
*/
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 limage affichée dans la zone daperçu.
*
* <p>
* Cette méthode est appelée lorsque limage à convertir
* a été chargée. La fenêtre ne modifie pas limage :
* elle la transmet simplement au panneau daperçu.
* </p>
*
* @param img image à afficher
*/
public void setImagePreview(BufferedImage img) {
imagePreviewPanel.setImage(img);
}
/**
* Met à jour laffichage des tables de fréquences.
*/
public void setFrequencyTable(int[] freqR,int[] freqG,int[] freqB) {
frequencyTablePanel.updateFrequencies(freqR,freqG,freqB);
}
/**
* Met à jour laffichage des codes Huffman.
*
* <p>
* Elle permet uniquement dafficher les codes
* qui ont été produits par la partie traitement.
* </p>
*/
public void setHuffmanTable(Map<Integer, String> codesRouge,
Map<Integer, String> codesVert,
Map<Integer, String> codesBleu) {
codeTablePanel.updateCodes(codesRouge, codesVert, codesBleu);
}
/**
* Met à jour laffichage des codes canoniques.
*
* <p>
* Les codes canoniques sont transmis au panneau
* chargé de leur affichage.
* </p>
*/
public void setCanonicalTable(Map<Integer, String> codesRouge,
Map<Integer, String> codesVert,
Map<Integer, String> 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;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Map;
import javax.swing.*;
/**
* Fenêtre principale du convertisseur.
*
* <p>
* Cette classe correspond à la vue principale de lapplication.
* Elle centralise laffichage des informations liées à la conversion
* dune image (aperçu, fréquences, codes).
* </p>
*
*
* <p>
* Elle sert de point dentrée unique pour la partie graphique
* </p>
*/
public class ConverterWindow extends JFrame {
private ImagePreviewPanel imagePreviewPanel;
private FrequencyTablePanel frequencyTablePanel;
private CodeTablePanel codeTablePanel;
/**
* Crée la fenêtre principale du convertisseur.
*
* <p>
* Le constructeur initialise la fenêtre et met en place
* les différents panneaux graphiques utilisés pour laffichage.
* </p>
*/
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);
}
/**
* Met à jour limage affichée dans la zone daperçu.
*
* <p>
* Cette méthode est appelée lorsque limage à convertir
* a été chargée. La fenêtre ne modifie pas limage :
* elle la transmet simplement au panneau daperçu.
* </p>
*
* @param img image à afficher
*/
public void setImagePreview(BufferedImage img) {
imagePreviewPanel.setImage(img);
}
/**
* Met à jour laffichage des tables de fréquences.
*/
public void setFrequencyTable(int[] freqR,int[] freqG,int[] freqB) {
frequencyTablePanel.updateFrequencies(freqR,freqG,freqB);
}
/**
* Met à jour laffichage des codes Huffman.
*
* <p>
* Elle permet uniquement dafficher les codes
* qui ont été produits par la partie traitement.
* </p>
*/
public void setHuffmanTable(Map<Integer, String> codesRouge,
Map<Integer, String> codesVert,
Map<Integer, String> codesBleu) {
codeTablePanel.updateCodes(codesRouge, codesVert, codesBleu);
}
/**
* Met à jour laffichage des codes canoniques.
*
* <p>
* Les codes canoniques sont transmis au panneau
* chargé de leur affichage.
* </p>
*/
public void setCanonicalTable(Map<Integer, String> codesRouge,
Map<Integer, String> codesVert,
Map<Integer, String> codesBleu) {
codeTablePanel.updateCanonicalCodes(codesRouge, codesVert, codesBleu);
this.setVisible(true); // je limage visible apre avoir tout ajouter
}
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();
}
}
+2 -3
View File
@@ -1,7 +1,5 @@
package fr.iutfbleau.sae;
import fr.iutfbleau.sae.vconverter.ConverterWindow;
public class Convertisseur {
public static void main(String[] args) {
@@ -20,6 +18,7 @@ public class Convertisseur {
// je la passe au controleur
ConverterController controller = new ConverterController(window, inpuPath, outputPath);
controller.StartconvessionProcess();
// je demare le programe de conversion
controller.convessionProcess();
}
}
@@ -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;
import java.awt.*;
import javax.swing.*;
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());
}
}
@@ -1,76 +1,76 @@
package fr.iutfbleau.sae.vconverter;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
import java.awt.*;
/**
* Le panneau daperçu de limage.
*
* <p>
* Ce panneau affiche un aperçu de limage en cours de conversion.
* </p>
*/
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;
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
/**
* Le panneau daperçu de limage.
*
* <p>
* Ce panneau affiche un aperçu de limage en cours de conversion.
* </p>
*/
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);
}
}
+15 -31
View File
@@ -1,36 +1,20 @@
<<<<<<< HEAD
package fr.iutfbleau.sae;
public class Viewer {
public static void main(String[] args) {
System.out.println("dqkdjqkdjqkdjqkdjqkdj");
}
}
=======
package fr.iutfbleau.sae;
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");
public class Viewer {
public static void main(String[] args) {
// chemins de l'image
String inpuPath = null;
if (args.length >= 1) {
inpuPath = args[0];
}
} 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);
ViewerWindow fen = new ViewerWindow();
ViewerControleur controleur = new ViewerControleur(fen,inpuPath);
controleur.loadPIF();
}
}
>>>>>>> 40f71dddd52fc07edc1d47d48d56fd65a2a79fe3
@@ -0,0 +1,98 @@
package fr.iutfbleau.sae;
import fr.iutfbleau.sae.mpif.PIFReader;
import fr.iutfbleau.sae.mpif.Pixel;
import fr.iutfbleau.sae.mpif.RGBImage;
import fr.iutfbleau.sae.util.GestionErreur;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.swing.JFileChooser;
public class ViewerControleur {
private RGBImage image; // L'image à décoder
private ViewerWindow window; // La fenêtre du visualiseur
private File file;
public ViewerControleur(ViewerWindow window, String path) {
this.window = window;
if (path != null) {
this.file = new File(path);
} else {
this.file = null;
}
}
public void loadPIF() {
File fichierPIF;
// Déterminer si on le charge avec jFilechoose ou pas
if (this.file != null) {
// Fichier fourni en argument
fichierPIF = this.file;
} else {
// Demander à l'utilisateur via JFileChooser
JFileChooser chooser = new JFileChooser();
chooser.setDialogTitle("Choisissez un fichier PIF");
if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
fichierPIF = chooser.getSelectedFile();
} else {
GestionErreur.afficherErreur("Aucun fichier sélectionné. Arrêt du programme.");
System.exit(1);
return;
}
}
// je Vérifi la conformiter du fichier avec isPIFFile
if (!PIFReader.isPIFFile(fichierPIF)) {
GestionErreur.afficherErreur("Le fichier fourni n'est pas au format PIF (.pif)");
return;
}
// je Charge et décoder le fichier PIF
try {
PIFReader lecteur = new PIFReader();
this.image = lecteur.decodePifFile(fichierPIF);
System.out.println("Image décodée : " + this.image.getWidth() + "x" + this.image.getHeight());
// je convertit RGBImage en BufferedImage
BufferedImage buffImg = convertToBufferedImage(this.image);
// j'affiche l'image
this.window.displayImage(buffImg);
} catch (Exception e) {
GestionErreur.afficherErreur("Erreur lors du chargement du fichier PIF : ");
}
}
/**
* Convertit une RGBImage en BufferedImage.
*
* @param rgbImage l'image à convertir
* @return l'image convertie
*/
private BufferedImage convertToBufferedImage(RGBImage rgbImage) {
int width = rgbImage.getWidth();
int height = rgbImage.getHeight();
BufferedImage buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// Copier tous les pixels
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
Pixel pixel = rgbImage.getPixel(x, y);
// Composer la couleur RGB la couleur est coder sur 32 bit argb chacun a 8 bit
int rgb = (pixel.getR() << 16) | (pixel.getG() << 8) | pixel.getB();
// Définir le pixel dans le BufferedImage
buffImg.setRGB(x, y, rgb);
}
}
return buffImg;
}
}
+91
View File
@@ -0,0 +1,91 @@
package fr.iutfbleau.sae;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class ViewerWindow extends JFrame implements MouseListener, MouseMotionListener {
private BufferedImage image;
private int offsetX = 0;
private int offsetY = 0;
private int lastX;
private int lastY;
public ViewerWindow() {
super("PIF Viewer");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(true);
this.addMouseListener(this);
this.addMouseMotionListener(this);
}
public void displayImage(BufferedImage img) {
this.image = img;
// je prend la taille de l'ecran
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
// je prend una taille de 90% pour etre raisonable
int maxW = (int)(screen.width * 0.9);
int maxH = (int)(screen.height * 0.9);
int w = Math.min(img.getWidth(), maxW);
int h = Math.min(img.getHeight(), maxH);
this.setSize(w, h);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
@Override
public void paint(Graphics g) {
super.paint(g);
if (image == null) return;
int panelW = getWidth();
int panelH = getHeight();
int imgW = image.getWidth();
int imgH = image.getHeight();
int drawX = offsetX;
int drawY = offsetY;
// centrage automatique si image plus petite
if (imgW < panelW) drawX = (panelW - imgW) / 2;
if (imgH < panelH) drawY = (panelH - imgH) / 2;
g.drawImage(image, drawX, drawY, null);
}
@Override
public void mousePressed(MouseEvent e) {
lastX = e.getX();
lastY = e.getY();
}
@Override
public void mouseDragged(MouseEvent e) {
offsetX += e.getX() - lastX;
offsetY += e.getY() - lastY;
lastX = e.getX();
lastY = e.getY();
repaint();
}
@Override public void mouseReleased(MouseEvent e) {}
@Override public void mouseClicked(MouseEvent e) {}
@Override public void mouseEntered(MouseEvent e) {}
@Override public void mouseExited(MouseEvent e) {}
@Override public void mouseMoved(MouseEvent e) {}
}
@@ -16,13 +16,7 @@ public class CanonicalCode{
List<Map.Entry<Integer, String>> liste = new ArrayList<>(codesHuffman.entrySet());
// ici on comparer par longueur de la valeur ou sinon par la clé
Collections.sort(liste, new ComparateurCanonique());
Map<Integer,String> 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
@@ -1,6 +1,6 @@
package fr.iutfbleau.sae.mhuffman;
import fr.iutfbleau.sae.mimage.Pixel;
import fr.iutfbleau.sae.mimage.RGBImage;
import fr.iutfbleau.sae.mpif.Pixel;
import fr.iutfbleau.sae.mpif.RGBImage;
/**
* Représente une table de fréquences pour une image RGB.
@@ -33,13 +33,13 @@ import fr.iutfbleau.sae.mimage.RGBImage;
public class FrequencyTable {
/** Tableau des fréquences pour la composante rouge (valeurs de 0 à 255). */
private int[] freqR;
private final int[] freqR;
/** Tableau des fréquences pour la composante verte (valeurs de 0 à 255). */
private int[] freqG;
private final int[] freqG;
/** Tableau des fréquences pour la composante bleue (valeurs de 0 à 255). */
private int[] freqB;
private final int[] freqB;
/**
* Construit une table de fréquences vide.
@@ -4,7 +4,7 @@ import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
// test
import fr.iutfbleau.sae.util.HuffmanNode;
/**
* Implémente un arbre de Huffman utilisé pour la compression de données.
@@ -59,14 +59,7 @@ public class HuffmanTree {
*/
// j'ai retirer le static car chaque arbre a ses propres codes et j'utilise string plutot que int pour stocker les codes car on construit une chaine de 0 et de 1
private Map<Integer, String> codes;
/**
* Chaine de caracteres qui va nous permettre de sauvegader le code Huffman
* Permet en d'autres termes de construire la chaine de 1 et de 0
*/
private String chaineCarac;
/**
* Construit un arbre de Huffman.
+225 -43
View File
@@ -1,9 +1,14 @@
package fr.iutfbleau.sae.mpif;
import fr.iutfbleau.sae.mimage.RGBImage;
import fr.iutfbleau.sae.util.BitInputStream;
import fr.iutfbleau.sae.util.BitInputStream;
import fr.iutfbleau.sae.util.DecodeNode;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -15,73 +20,250 @@ public class PIFReader {
private int[] lenG;
private int[] lenB;
public RGBImage read(String filepath)
throws Exception {
// j'Utilise d'un BufferedInputStream pour une meilleure performance
FileInputStream fis = new FileInputStream(filepath);
BufferedInputStream bis = new BufferedInputStream(fis);
BitInputStream lecteur = new BitInputStream(bis);
/**
* Lit et décode un fichier PIF.
*
* @param filepath chemin du fichier PIF
* @return l'image RGB décodée
* @throws Exception si erreur de lecture
*/
public RGBImage decodePifFile(File file) throws Exception {
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bos = new BufferedInputStream(fis);
BitInputStream lecteur = new BitInputStream(bos);
// je lis l'entête et les tables canoniques
// Je lis l'en-tête et les tables canoniques
this.readHeader(lecteur);
this.readCanonicalTables(lecteur);
// je reconstructe les tables canoniques car dans le fichier on a juste les longueurs en bits
// Je reconstruis les tables canoniques car dans le fichier on a juste les longueurs en bits
Map<String, Integer> canonR = rebuildCanonical(lenR);
Map<String, Integer> canonG = rebuildCanonical(lenG);
Map<String, Integer> canonB = rebuildCanonical(lenB);
// Je construis les arbres de décodage
DecodeNode trieR = buildDecodageTree(canonR);
DecodeNode trieG = buildDecodageTree(canonG);
DecodeNode trieB = buildDecodageTree(canonB);
// Je décode les pixels
RGBImage img = decodePixels(lecteur, trieR, trieG, trieB);
lecteur.closeFlux();
System.out.println("Fichier PIF lu avec succès : " + width + "x" + height);
return img;
}
public void readHeader(BitInputStream in) {
// La largeur et l'hauteur de l'image occupe chaqun deux octets soit 16 bits :
/**
* Lit l'en-tête du fichier PIF (largeur et hauteur sur 16 bits chacune).
* @throws IOException si erreur de lecture
*/
public void readHeader(BitInputStream in) throws IOException {
this.width = in.readBits(16);
this.height = in.readBits(16);
System.out.println("Dimensions lues : " + this.width + "x" + this.height);
}
public void readCanonicalTables(BitInputStream in) {
this.lenR = new int[256];
this.lenG = new int[256];
this.lenB = new int[256];
/**
* Lit les trois tables de longueurs (R, G, B).
* Chaque table contient 256 valeurs sur 5 bits.
* @throws IOException si erreur de lecture
*/
public void readCanonicalTables(BitInputStream in) throws IOException {
// Table Rouge
this.lenR = new int[256];
for (int i = 0; i < 256; i++){
lenR[i] = in.readBits(8);
this.lenR[i] = in.readBits(8);
}
for (int j = 0; j < 256; j++){
lenG[j] = in.readBits(8);
// Table Vert
this.lenG = new int[256];
for (int i = 0; i < 256; i++){
this.lenG[i] = in.readBits(8);
}
// Table Bleu
this.lenB = new int[256];
for (int i = 0; i < 256; i++){
this.lenB[i] = in.readBits(8);
}
System.out.println("Tables de longueurs lues");
}
/**
* Reconstruit les codes canoniques à partir des longueurs.
*
* @param lengths tableau de 256 longueurs
* @return Map<code, symbole> pour le décodage
*/
public Map<String, Integer> rebuildCanonical(int[] lengths) {
// je cree une liste de paires (symbole, longueur)
List<Map.Entry<Integer, Integer>> entiers = new ArrayList<>();
for (int i = 0; i < lengths.length; i++) {
if (lengths[i] > 0) {
entiers.add(new java.util.AbstractMap.SimpleEntry<>(i, lengths[i]));
}
}
// Je trie par longueur croissante, puis par symbole croissant
entiers.sort((a, b) -> {
int cmp = a.getValue().compareTo(b.getValue());
if (cmp != 0) return cmp;
return a.getKey().compareTo(b.getKey());
});
// je genere les codes canoniques
Map<String, Integer> codes = new HashMap<>();
int code = 0;
int previousLength = 0;
for (Map.Entry<Integer, Integer> entry : entiers) {
int symbol = entry.getKey();
int length = entry.getValue();
// Decalage pour aligner le code sur la longueur courante
code <<= (length - previousLength);
// je convertit ce code en texte binaire
String codeStr = Integer.toBinaryString(code);
// On s'assure que la chaîne a la bonne longueur en ajoutant des zéros à gauche si nécessaire
while (codeStr.length() < length) {
codeStr = "0" + codeStr;
}
// je restocke le code + symbole en inversant car la map est inverse dans l'encodage
codes.put(codeStr, symbol);
code++;
previousLength = length;
}
return codes;
}
/**
* Construit l'arbre de décodage à partir des codes canoniques.
*
* @param codes Map<String (code binaire), symbole> les codes canoniques avec les bits comme clés et les symboles comme valeurs
* @return la racine de l'arbre de décodage
*/
public DecodeNode buildDecodageTree(Map<String,Integer> codes) {
DecodeNode root = new DecodeNode(); // la racine de larbre
for (Map.Entry<String, Integer> entry : codes.entrySet()) {
String code = entry.getKey(); // 101011101110 par exemple
int symbol = entry.getValue(); // 0,1,2,3 etc. par exemple
DecodeNode current = root;
// je parcours le code bit à bit
for (int i = 0; i < code.length(); i++) {
char bit = code.charAt(i);
if(i == code.length() - 1) {
// Dernier bit: je cree une feuille avec la valeur du symbol
if(bit == '0') {
current.left = new DecodeNode(null, null, symbol);
} else {
current.right = new DecodeNode(null, null, symbol);
}
} else {
// Si c'est pas le dernier bit : je creer un node interne
if(bit == '0') {
if(current.left == null) {
current.left = new DecodeNode(); // Node interne
}
current = current.left;
} else {
if(current.right == null) {
current.right = new DecodeNode(); // node intern
}
current = current.right;
}
}
}
}
return root;
}
/**
* Décode les pixels à partir des arbres de décodage.
*
* @param in flux d'entrée binaire
* @param red arbre de décodage pour la composante rouge
* @param green arbre de décodage pour la composante verte
* @param blue arbre de décodage pour la composante bleue
* @return l'image reconstruite
*/
public RGBImage decodePixels(BitInputStream in, DecodeNode red, DecodeNode green, DecodeNode blue) throws IOException{
RGBImage image = new RGBImage(width, height);
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
// je decode chaque composante en parcourant son arbre
int r = decodeSymbole(in, red);
int g = decodeSymbole(in, green);
int b = decodeSymbole(in, blue);
// je cree et je place le pixel
Pixel pixel = new Pixel(r, g, b);
image.setPixel(x, y, pixel);
}
}
return image;
}
/**
* Décode un symbole en parcourant l'arbre bit par bit
* @param in le flux d'entrée binaire
* @param root la racine de l'arbre de décodage
* @return le symbole décodé (valeur entre 0 et 255)
* @throws IOException si une erreur d'entrée/sortie se produit
*/
private int decodeSymbole(BitInputStream in, DecodeNode root) throws IOException {
DecodeNode current = root;
// je parcours l'arbre en suivant les bits du flux jusqu'à atteindre une feuille
while (!current.isLeaf()) {
int bit = in.readBit();
if (bit == 0) {
current = current.left;
} else {
current = current.right;
}
if (current == null) {
throw new IOException("code invalide: noeud null rencontre");
}
}
// si on est arrivé à une feuille, on retourne la valeur
if (current.value == -1) {
throw new IOException("Feuille sans valeur assignée");
}
return current.value;
}
public static boolean isPIFFile(File f) {
if (f == null){
return false;
}
if (!f.exists() || !f.isFile()){
return false;
}
//je verifi l'extension
String name = f.getName().toLowerCase();
if (!name.endsWith(".pif")) {
return false;
}
for (int k = 0; k < 256; k++){
lenB[k] = in.readBits(8);
}
}
public Map<String,Integer> rebuildCanonical(int[] lengths) {
// TODO: Implement canonical table reconstruction
return null;
return f.length() >= 772; // taille minimal pour un fichier pif longueur largeur et tables de frequance
}
public RGBImage decodePixels(BitInputStream in, DecodeNode red, DecodeNode green, DecodeNode blue) {
// TODO: Implement pixel decoding
return null;
}
public DecodeNode buildDecodageTree(Map<String,Integer> codes) {
// TODO: Implement trie building
return null;
}
}
+4 -33
View File
@@ -1,7 +1,5 @@
package fr.iutfbleau.sae.mpif;
import fr.iutfbleau.sae.mimage.RGBImage;
import fr.iutfbleau.sae.mimage.Pixel;
import fr.iutfbleau.sae.util.BitOutputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
@@ -31,17 +29,15 @@ public class PIFWriter {
encodePixels(ecriveur, image, canonR, canonG, canonB);
ecriveur.fermerFlux();
System.out.println("Fichier PIF écrit avec succès");
}
// Ecriture de l'en-tête du fichier PIF (largeur et hauteur)
public void writeHeader(BitOutputStream out, int width, int height) {
try {
out.writeBits(width, 16); // ✅ Simplifié : 16 bits d'un coup
out.writeBits(height, 16); // ✅ Simplifié : 16 bits d'un coup
} catch (Exception e) {
System.err.println("Erreur lors de l'écriture de l'en-tête du fichier PIF");
out.writeBits(width, 16);
out.writeBits(height, 16);
} catch (IOException e) {
System.err.println("Erreur lors de l'écriture de l'en-tête du fichier PIF: " + e.getMessage());
}
}
@@ -82,31 +78,6 @@ public class PIFWriter {
} catch (IOException e) {
System.err.println("Erreur lors de l'écriture des tables de fréquences dans le fichier PIF");
}
// Debug pour compter les symboles utilisés et calculer les longueurs moyennes
int totalBitsR = 0, totalBitsG = 0, totalBitsB = 0;
int countR = 0, countG = 0, countB = 0;
for (int i = 0; i < 256; i++) {
if (canonR.containsKey(i)) {
totalBitsR += canonR.get(i).length();
countR++;
}
if (canonG.containsKey(i)) {
totalBitsG += canonG.get(i).length();
countG++;
}
if (canonB.containsKey(i)) {
totalBitsB += canonB.get(i).length();
countB++;
}
}
System.out.println("Longueur moyenne Rouge : " + (totalBitsR / (double)countR));
System.out.println("Longueur moyenne Vert : " + (totalBitsG / (double)countG));
System.out.println("Longueur moyenne Bleu : " + (totalBitsB / (double)countB));
System.out.println("Symboles utilisés - R:" + countR + " G:" + countG + " B:" + countB);
}
// Méthode pour encoder les pixels de l'image en utilisant les codes canoniques
@@ -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.mpif;
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;
}
}
@@ -1,30 +1,31 @@
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.mpif;
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];
}
}
-89
View File
@@ -1,89 +0,0 @@
package fr.iutfbleau.sae.util;
/**
* Classe utilitaire regroupant des opérations de conversion entre
* entiers et octets.
* <p>
* Elle est utilisée pour encoder et décoder les champs binaires
* du format PIF (largeur, hauteur, tailles, etc.).
* </p>
*
* <p>
* Cette classe :
* <ul>
* <li>ne lit aucun fichier</li>
* <li>n'écrit aucun fichier</li>
* <li>ne manipule pas les bits individuellement</li>
* </ul>
* Elle fournit uniquement des conversions octets ↔ entiers.
* </p>
*/
public final class ByteUtils {
/**
* Constructeur privé empêchant l'instanciation.
* <p>
* Cette classe est purement utilitaire et ne doit pas être instanciée.
* </p>
*/
private ByteUtils() {
// j'empêche l'instanciation
}
/**
* Convertit un entier non négatif en deux octets (ordre big-endian).
* <p>
* L'octet de poids fort est placé en première position,
* suivi de l'octet de poids faible.
* </p>
*
* @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).
* <p>
* L'octet de poids fort est replacé dans les bits 15 à 8,
* puis combiné avec l'octet de poids faible.
* </p>
*
* @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);
}
}
@@ -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.util;
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 = -1; // valeur non initialisée
}
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;
}
}
@@ -1,8 +0,0 @@
package fr.iutfbleau.sae.util;
public class GestErreur {
public static void erreur(String message) {
System.err.println("Erreur : " + message);
System.exit(1);
}
}
@@ -0,0 +1,12 @@
package fr.iutfbleau.sae.util;
import javax.swing.*;
public class GestionErreur {
public static void afficherErreur(String message) {
JOptionPane.showMessageDialog(null, message, "Erreur", JOptionPane.ERROR_MESSAGE);
}
public static void afficherInfo(String message) {
JOptionPane.showMessageDialog(null, message, "Information", JOptionPane.INFORMATION_MESSAGE);
}
}
@@ -1,4 +1,4 @@
package fr.iutfbleau.sae.mhuffman;
package fr.iutfbleau.sae.util;
/**
* Représente un nœud de l'arbre de Huffman.
@@ -1,7 +0,0 @@
package fr.iutfbleau.sae.vviewer;
public class ImagePanel extends JPanel{
}
@@ -1,11 +0,0 @@
package fr.iutfbleau.sae.vviewer;
public class ViewerWindow extends JFrame{
}
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More