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,8 +1,8 @@
package fr.iutfbleau.sae.vconverter;
package fr.iutfbleau.sae;
import javax.swing.*;
import java.awt.*;
import java.util.Map;
import javax.swing.*;
/**
* Panneau d'affichage des codes Huffman et canoniques.
+32 -41
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();
@@ -124,11 +112,6 @@ public class ConverterController {
}
public void computeCanonical(){
if (this.abrHuffmanR == null || this.abrHuffmanG == null || this.abrHuffmanB == null) {
System.err.println("Les codes de Huffman doivent être générés d'abord.");
return;
}
CanonicalCode codeCanoniques = new CanonicalCode();
this.canonRED = codeCanoniques.generateCodes(this.abrHuffmanR);
this.canonGREEN = codeCanoniques.generateCodes(this.abrHuffmanG);
@@ -139,10 +122,11 @@ public class ConverterController {
}
public void saveAsPIF(String pathfile) {
// je Vérifie que l'image et les codes canoniques sont disponibles
// 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.");
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,12 +1,9 @@
package fr.iutfbleau.sae.vconverter;
package fr.iutfbleau.sae;
import java.awt.*;
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.
*
@@ -84,7 +81,6 @@ public class ConverterWindow extends JFrame {
scrollPane.getVerticalScrollBar().setUnitIncrement(16); // scroll plus adouci fluide
this.add(scrollPane, BorderLayout.CENTER);
this.setVisible(true);
}
@@ -137,6 +133,8 @@ public class ConverterWindow extends JFrame {
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) {
+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,7 +1,7 @@
package fr.iutfbleau.sae.vconverter;
package fr.iutfbleau.sae;
import javax.swing.*;
import java.awt.*;
import javax.swing.*;
public class FrequencyTablePanel extends JPanel {
@@ -1,8 +1,8 @@
package fr.iutfbleau.sae.vconverter;
package fr.iutfbleau.sae;
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
import java.awt.*;
/**
* Le panneau daperçu de limage.
*
+13 -29
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");
}
} catch (IOException e) {
JOptionPane.showMessageDialog(this,
"Erreur lors de l'ouverture du fichier",
"Erreur",
JOptionPane.ERROR_MESSAGE);
// chemins de l'image
String inpuPath = null;
if (args.length >= 1) {
inpuPath = args[0];
}
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.
@@ -61,13 +61,6 @@ public class HuffmanTree {
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.
* <p>
+213 -31
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 {
/**
* 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);
// j'Utilise d'un BufferedInputStream pour une meilleure performance
FileInputStream fis = new FileInputStream(filepath);
BufferedInputStream bis = new BufferedInputStream(fis);
BitInputStream lecteur = new BitInputStream(bis);
// 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) {
/**
* 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];
this.lenG = new int[256];
this.lenB = new int[256];
for (int i = 0; i < 256; i++){
lenR[i] = in.readBits(8);
}
for (int j = 0; j < 256; j++){
lenG[j] = in.readBits(8);
this.lenR[i] = in.readBits(8);
}
for (int k = 0; k < 256; k++){
lenB[k] = 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) {
// TODO: Implement canonical table reconstruction
return null;
// 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]));
}
}
public RGBImage decodePixels(BitInputStream in, DecodeNode red, DecodeNode green, DecodeNode blue) {
// TODO: Implement pixel decoding
return null;
// 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) {
// TODO: Implement trie building
return null;
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;
}
return f.length() >= 772; // taille minimal pour un fichier pif longueur largeur et tables de frequance
}
}
+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,4 +1,4 @@
package fr.iutfbleau.sae.mimage;
package fr.iutfbleau.sae.mpif;
public class Pixel{
private int r;
@@ -1,4 +1,4 @@
package fr.iutfbleau.sae.mimage;
package fr.iutfbleau.sae.mpif;
public class RGBImage {
@@ -27,4 +27,5 @@ public class RGBImage {
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,4 +1,4 @@
package fr.iutfbleau.sae.mpif;
package fr.iutfbleau.sae.util;
public class DecodeNode {
public DecodeNode left;
@@ -8,7 +8,7 @@ public class DecodeNode {
public DecodeNode() {
this.left = null;
this.right = null;
this.value = null;
this.value = -1; // valeur non initialisée
}
public DecodeNode(DecodeNode left, DecodeNode right, Integer value) {
@@ -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