Files
SAE32_2025/src/fr/iutfbleau/sae/ConverterController.java
T
Diallo-VM-fbleau c24ad9fb2e mis a jour
2026-01-08 13:05:29 +01:00

276 lines
10 KiB
Java

package fr.iutfbleau.sae;
import fr.iutfbleau.sae.mhuffman.*;
import fr.iutfbleau.sae.mpif.PIFWriter;
import fr.iutfbleau.sae.mpif.Pixel;
import fr.iutfbleau.sae.mpif.RGBImage;
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;
/**
* Controleur pour la conversion d'images au format PIF.
* Gere le chargement des images, le calcul des frequences,
* la generation des codes de Huffman et la sauvegarde au format PIF.
*/
public class ConverterController {
/** Image convertie en RGBImage */
private RGBImage image;
/** Table de frequences pour chaque composante */
private FrequencyTable frequencyTable;
/** Codes de Huffman pour la composante rouge */
private Map<Integer, String> abrHuffmanR;
/** Codes de Huffman pour la composante verte */
private Map<Integer, String> abrHuffmanG;
/** Codes de Huffman pour la composante bleue */
private Map<Integer, String> abrHuffmanB;
/** Codes canoniques pour la composante rouge */
private Map<Integer, String> canonRED;
/** Codes canoniques pour la composante verte */
private Map<Integer, String> canonGREEN;
/** Codes canoniques pour la composante bleue */
private Map<Integer, String> canonBLUE;
/** La fenetre du convertisseur */
private ConverterWindow fen;
/** Chemin du fichier de sortie */
String outputPath;
/** Chemin du fichier d'entree */
String inputPath;
/**
* Construit un nouveau controleur de conversion.
*
* @param fen la fenetre de l'interface graphique
* @param in le chemin du fichier d'entree (peut etre null)
* @param out le chemin du fichier de sortie (peut etre null)
*/
public ConverterController(ConverterWindow fen, String in, String out) {
this.fen = fen;
this.outputPath = out;
this.inputPath = in;
}
/**
* Charge une image depuis un fichier et la convertit en RGBImage.
* Extrait les composantes RGB de chaque pixel et met a jour l'interface.
*
* @param file le fichier image a charger
*/
public void loadImage(File file) {
try {
// Lire l'image avec BufferedImage
BufferedImage buffimage = ImageIO.read(file);
if (buffimage == null) {
throw new IllegalArgumentException("Le fichier specifie n'est pas une image valide.");
}
int w = buffimage.getWidth();
int h = buffimage.getHeight();
// Creer une RGBImage de la meme 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);
// Extraire les composantes R, G, B
int r = (rgb >> 16) & 0xFF;
int g = (rgb >> 8) & 0xFF;
int b = rgb & 0xFF;
// Creer un pixel et l'ajouter a la RGBImage
this.image.setPixel(x, y, new Pixel(r, g, b));
}
}
// Mettre a jour le GUI
this.fen.setImagePreview(buffimage);
} catch (IOException e) {
GestionErreur.afficherErreur("Impossible de charger l'image: \n \t Verifier que le Fichier transmit correspond a une image");
System.exit(2);
}
}
/**
* Calcule les frequences d'apparition de chaque valeur RGB dans l'image.
* Met a jour l'interface avec les tables de frequences calculees.
*/
public void computeFrequencies() {
this.frequencyTable = new FrequencyTable();
if (this.image == null) {
return;
}
this.frequencyTable.computeFromImage(this.image);
// Mettre a jour le GUI avec les frequences
int[] freqR = this.frequencyTable.getRed();
int[] freqG = this.frequencyTable.getGreen();
int[] freqB = this.frequencyTable.getBlue();
this.fen.setFrequencyTable(freqR, freqG, freqB);
}
/**
* Genere les arbres de Huffman pour chaque composante RGB.
* Cree les codes binaires optimaux bases sur les frequences calculees.
* Met a jour l'interface avec les codes de Huffman generes.
*/
public void computeHuffman() {
// Generation des arbres de Huffman pour chaque composante
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 a jour le GUI avec les codes de Huffman
this.fen.setHuffmanTable(this.abrHuffmanR, this.abrHuffmanG, this.abrHuffmanB);
}
/**
* Genere les codes canoniques a partir des codes de Huffman.
* Les codes canoniques sont une forme normalisee des codes de Huffman
* qui facilite le stockage et le decodage.
* Met a jour l'interface avec les codes canoniques generes.
*/
public void computeCanonical() {
CanonicalCode codeCanoniques = new CanonicalCode();
this.canonRED = codeCanoniques.generateCodes(this.abrHuffmanR);
this.canonGREEN = codeCanoniques.generateCodes(this.abrHuffmanG);
this.canonBLUE = codeCanoniques.generateCodes(this.abrHuffmanB);
// Mettre a jour le GUI avec les codes canoniques
this.fen.setCanonicalTable(this.canonRED, this.canonGREEN, this.canonBLUE);
}
/**
* Sauvegarde l'image au format PIF.
* Verifie que l'image et les codes canoniques sont disponibles avant
* d'effectuer la sauvegarde.
*
* @param pathfile le chemin du fichier de sortie
*/
public void saveAsPIF(String pathfile) {
// Verifier 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;
}
try {
PIFWriter ecriveur = new PIFWriter();
ecriveur.writeTOFile(pathfile, this.image, this.canonRED, this.canonGREEN, this.canonBLUE);
} catch (Exception e) {
GestionErreur.afficherErreur("Erreur lors de l'ecriture du fichier .pif : ");
}
}
/**
* Gere la sauvegarde via le bouton de l'interface.
* Si un chemin de sortie est defini, sauvegarde directement.
* Sinon, ouvre un selecteur de fichier pour que l'utilisateur choisisse
* l'emplacement de sauvegarde.
* La sauvegarde est effectuee dans un thread separe pour ne pas bloquer
* l'interface graphique.
*/
public void saveViaBtn() {
if (outputPath != null) {
saveAsPIF(outputPath);
GestionErreur.afficherInfo("Fichier sauvegarde avec succes. Chemin : " + outputPath);
return;
}
// Sinon JFileChooser
JFileChooser chooser = new JFileChooser();
chooser.setDialogTitle("Enregistrer le fichier .pif");
if (chooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) {
File fichierSelectionne = chooser.getSelectedFile();
ThreadSauvegardePIF thread = new ThreadSauvegardePIF(this, fichierSelectionne);
thread.start();
}
}
/**
* Lance le processus complet de conversion d'une image au format PIF.
* Etapes :
* 1. Chargement de l'image (depuis un fichier ou via selecteur)
* 2. Calcul des frequences
* 3. Generation des codes de Huffman
* 4. Generation des codes canoniques
* 5. Sauvegarde (automatique ou via bouton selon les parametres)
*/
public void conversionProcess() {
// Chargement
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;
}
// j'essaye de charge limage
try {
this.loadImage(file);
} catch (IllegalArgumentException e) {
GestionErreur.afficherErreur("Le fichier specifie n'est pas une image valide : " + inputPath);
}
} else {
// Sinon JFileChooser pour choisir l'image
JFileChooser chooser = new JFileChooser();
chooser.setDialogTitle("Choisissez une image");
if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
this.loadImage(chooser.getSelectedFile());
} else {
GestionErreur.afficherErreur("Aucune image choisie. Arret du programme.");
System.exit(1);
return;
}
}
// Placer la logique de conversion dans l'ordre
computeFrequencies();
computeHuffman();
computeCanonical();
// Sauvegarder : si un second argument est donne, sauvegarde automatique
if (this.outputPath != null) {
this.saveAsPIF(this.outputPath);
GestionErreur.afficherInfo("Fichier sauvegarde automatiquement : " + this.outputPath);
} else {
// Pas de deuxieme argument : ajouter un bouton pour choisir avec un JFileChooser
fen.addSaveButton(this);
}
}
/**
* Retourne l'image actuellement chargee.
*
* @return l'image RGB chargee, ou null si aucune image n'est chargee
*/
public RGBImage getImage() {
return this.image;
}
}