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