Update architecture

This commit is contained in:
2026-09-22 13:30:03 +02:00
parent 8b1e6ae358
commit b177ea5a38
27 changed files with 792 additions and 374 deletions

View File

@@ -5,14 +5,14 @@ import app.state.DoubleMatrixState;
import com.google.common.eventbus.EventBus; import com.google.common.eventbus.EventBus;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Scopes; import com.google.inject.Scopes;
import presenters.DoubleMatrixPresenter; import presenters.doubleMatrix.DoubleMatrixPresenter;
import presenters.FilteringPresenter; import presenters.filtering.FilteringPresenter;
import presenters.MainPresenter; import presenters.MainPresenter;
import presenters.NavPresenter; import presenters.NavPresenter;
import services.ImageService; import services.ImageService;
import ui.implementation.components.nav.NavBar; import ui.implementation.components.nav.NavBar;
import ui.implementation.views.DoubleMatrix; import ui.implementation.views.DoubleMatrix;
import ui.implementation.views.FilteringView; import ui.implementation.views.IdealFilteringView;
import ui.implementation.views.MainView; import ui.implementation.views.MainView;
import ui.abstractions.IDoubleMatrix; import ui.abstractions.IDoubleMatrix;
import ui.abstractions.IFilteringView; import ui.abstractions.IFilteringView;
@@ -40,7 +40,7 @@ public class AppModule extends AbstractModule {
bind(INavBar.class).to(NavBar.class); bind(INavBar.class).to(NavBar.class);
bind(IMainView.class).to(MainView.class); bind(IMainView.class).to(MainView.class);
bind(IDoubleMatrix.class).to(DoubleMatrix.class); bind(IDoubleMatrix.class).to(DoubleMatrix.class);
bind(IFilteringView.class).to(FilteringView.class); bind(IFilteringView.class).to(IdealFilteringView.class);
//--- Presentation layer --- //--- Presentation layer ---
bind(MainPresenter.class); bind(MainPresenter.class);

View File

@@ -3,11 +3,9 @@ package app;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import ui.implementation.views.DoubleMatrix; import ui.implementation.views.DoubleMatrix;
import ui.implementation.views.FilteringView; import ui.implementation.views.IdealFilteringView;
import ui.implementation.views.ViewInitializer; import ui.implementation.views.ViewInitializer;
import javax.swing.text.View;
/** /**
* Concrete implement of the INavigator interface. * Concrete implement of the INavigator interface.
* Implements abstract endpoints to displays views in a Swing way * Implements abstract endpoints to displays views in a Swing way
@@ -16,12 +14,12 @@ import javax.swing.text.View;
public class SwingNavigator implements INavigator { public class SwingNavigator implements INavigator {
private final Provider<DoubleMatrix> doubleMatrixProvider; private final Provider<DoubleMatrix> doubleMatrixProvider;
private final Provider<FilteringView> filteringProvider; private final Provider<IdealFilteringView> filteringProvider;
@Inject @Inject
public SwingNavigator( public SwingNavigator(
Provider<DoubleMatrix> doubleMatrixProvider, Provider<DoubleMatrix> doubleMatrixProvider,
Provider<FilteringView> filteringProvider Provider<IdealFilteringView> filteringProvider
) { ) {
this.doubleMatrixProvider = doubleMatrixProvider; this.doubleMatrixProvider = doubleMatrixProvider;
this.filteringProvider = filteringProvider; this.filteringProvider = filteringProvider;
@@ -36,7 +34,7 @@ public class SwingNavigator implements INavigator {
@Override @Override
public void showFiltering() { public void showFiltering() {
FilteringView filteringView = filteringProvider.get(); IdealFilteringView filteringView = filteringProvider.get();
ViewInitializer.Initialize(filteringView); ViewInitializer.Initialize(filteringView);
filteringView.setVisible(true); filteringView.setVisible(true);
} }

View File

@@ -6,35 +6,47 @@ import com.google.inject.Singleton;
import domain.common.Mode; import domain.common.Mode;
import domain.events.ImageChangedEvent; import domain.events.ImageChangedEvent;
import domain.events.ModeChangedEvent; import domain.events.ModeChangedEvent;
import domain.events.listeners.Listener;
import domain.image.Image; import domain.image.Image;
import java.util.ArrayList;
import java.util.List;
/** /**
* Represents the global state of the app * Represents the global state of the app
*/ */
@Singleton @Singleton
public class AppState extends State { public class AppState extends State {
private Mode mode; private Mode mode;
private Image rgbImage; private Image rgbImage;
private final List<AppStateListener> listeners = new ArrayList<>();
@Inject @Inject
public AppState(EventBus eventBus) { public AppState() {}
super(eventBus);
public void subscribe(AppStateListener listener) {
listeners.add(listener);
}
public void unsubscribe(AppStateListener listener) {
listeners.remove(listener);
} }
public void setMode(Mode mode) { public void setMode(Mode mode) {
this.mode = mode; this.mode = mode;
this.eventBus.post(new ModeChangedEvent(mode)); listeners.forEach(listener -> listener.onModeChanged(mode));
} }
public void setImage(Image image) { public void setImage(Image image) {
this.rgbImage = image; this.rgbImage = image;
this.eventBus.post(new ImageChangedEvent(image)); listeners.forEach(listener -> listener.onImageChanged(image));
} }
public Image getImage(){ public Image getImage() {
return this.rgbImage; return rgbImage;
} }
public Mode getMode() { return this.mode; } public Mode getMode() {
return mode;
}
} }

View File

@@ -0,0 +1,9 @@
package app.state;
import domain.common.Mode;
import domain.image.Image;
public interface AppStateListener {
void onModeChanged(Mode mode);
void onImageChanged(Image image);
}

View File

@@ -1,22 +1,32 @@
package app.state; package app.state;
import com.google.common.eventbus.EventBus;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Singleton;
import domain.events.fourier.*;
import domain.image.GrayScaleMatrix; import domain.image.GrayScaleMatrix;
import domain.image.processing.complex.ComplexMatrix; import domain.image.processing.complex.ComplexMatrix;
import presenters.doubleMatrix.DoubleMatrixListener;
import java.util.ArrayList;
import java.util.List;
public class DoubleMatrixState extends State { public class DoubleMatrixState extends State {
private ComplexMatrix fourier; private ComplexMatrix fourier;
private GrayScaleMatrix module; private GrayScaleMatrix module;
private GrayScaleMatrix phase; private GrayScaleMatrix phase;
private GrayScaleMatrix real; private GrayScaleMatrix real;
private GrayScaleMatrix imaginary; private GrayScaleMatrix imaginary;
private final List<DoubleMatrixListener> listeners = new ArrayList<>();
@Inject @Inject
public DoubleMatrixState() { super(new EventBus()); } public DoubleMatrixState() {}
public void subscribe(DoubleMatrixListener listener) {
listeners.add(listener);
}
public void unsubscribe(DoubleMatrixListener listener) {
listeners.remove(listener);
}
public ComplexMatrix getFourier() { public ComplexMatrix getFourier() {
return fourier; return fourier;
@@ -24,26 +34,42 @@ public class DoubleMatrixState extends State {
public void setFourier(ComplexMatrix fourier) { public void setFourier(ComplexMatrix fourier) {
this.fourier = fourier; this.fourier = fourier;
this.eventBus.post(new ComplexMatrixChanged(fourier)); listeners.forEach(listener -> listener.onFourierChanged(fourier));
} }
public void setModule(GrayScaleMatrix matrix) { public void setModule(GrayScaleMatrix matrix) {
this.module = matrix; this.module = matrix;
this.eventBus.post(new ModuleChangedEvent(matrix)); listeners.forEach(listener -> listener.onModuleChanged(matrix));
} }
public void setPhase(GrayScaleMatrix matrix) { public void setPhase(GrayScaleMatrix matrix) {
this.phase = matrix; this.phase = matrix;
this.eventBus.post(new PhaseChangedEvent(matrix)); listeners.forEach(listener -> listener.onPhaseChanged(matrix));
} }
public void setReal(GrayScaleMatrix matrix) { public void setReal(GrayScaleMatrix matrix) {
this.real = matrix; this.real = matrix;
this.eventBus.post(new RealChangedEvent(matrix)); listeners.forEach(listener -> listener.onRealChanged(matrix));
} }
public void setImaginary(GrayScaleMatrix matrix) { public void setImaginary(GrayScaleMatrix matrix) {
this.imaginary = matrix; this.imaginary = matrix;
this.eventBus.post(new ImaginaryChangedEvent(matrix)); listeners.forEach(listener -> listener.onImaginaryChanged(matrix));
}
public GrayScaleMatrix getModule() {
return module;
}
public GrayScaleMatrix getPhase() {
return phase;
}
public GrayScaleMatrix getReal() {
return real;
}
public GrayScaleMatrix getImaginary() {
return imaginary;
} }
} }

View File

@@ -1,27 +1,64 @@
package app.state; package app.state;
import com.google.common.eventbus.EventBus;
import com.google.inject.Inject; import com.google.inject.Inject;
import domain.events.filtering.HighPassChangedEvent;
import domain.events.filtering.LowPassChangedEvent;
import domain.events.fourier.ModuleChangedEvent;
import domain.image.GrayScaleMatrix;
import domain.image.Image; import domain.image.Image;
import presenters.filtering.FilteringListener;
import java.util.ArrayList;
import java.util.List;
public class FilteringState extends State { public class FilteringState extends State {
private Image lowPass; private Image lowPass;
private Image highPass; private Image highPass;
private Image butterworthLowPass;
private Image butterworthHighPass;
private final List<FilteringListener> listeners = new ArrayList<>();
@Inject @Inject
public FilteringState() { super(new EventBus()); } public FilteringState() {}
public void subscribe(FilteringListener listener) {
listeners.add(listener);
}
public void unsubscribe(FilteringListener listener) {
listeners.remove(listener);
}
public void setLowPass(Image image) { public void setLowPass(Image image) {
this.eventBus.post(new LowPassChangedEvent(image)); lowPass = image;
listeners.forEach(listener -> listener.onLowPassChanged(image));
} }
public void setHighPass(Image image) { public void setHighPass(Image image) {
this.eventBus.post(new HighPassChangedEvent(image)); highPass = image;
listeners.forEach(listener -> listener.onHighPassChanged(image));
} }
} public void setButterworthLowPass(Image image) {
butterworthLowPass = image;
listeners.forEach(listener -> listener.onButterworthLowPassChanged(image));
}
public void setButterworthHighPass(Image image) {
butterworthHighPass = image;
listeners.forEach(listener -> listener.onButterworthHighPassChanged(image));
}
public Image getLowPass() {
return lowPass;
}
public Image getHighPass() {
return highPass;
}
public Image getButterworthLowPass() {
return butterworthLowPass;
}
public Image getButterworthHighPass() {
return butterworthHighPass;
}
}

View File

@@ -2,6 +2,10 @@ package app.state;
import com.google.common.eventbus.EventBus; import com.google.common.eventbus.EventBus;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
/** /**
* Represents any states that could ever exist. * Represents any states that could ever exist.
* In order to notify the caller about any change made to internal properties of a children state, the caller * In order to notify the caller about any change made to internal properties of a children state, the caller
@@ -9,18 +13,4 @@ import com.google.common.eventbus.EventBus;
* @author Laurent Crema * @author Laurent Crema
*/ */
public abstract class State { public abstract class State {
}
protected EventBus eventBus;
public State(EventBus eventBus) {
this.eventBus = eventBus;
}
/**
* Register the caller so it can be notifed from changes within the state
* @param obj the caller itself
*/
public void register(Object obj) {
eventBus.register(obj);
}
}

View File

@@ -1,5 +0,0 @@
package domain.events.filtering;
import domain.image.Image;
public record HighPassChangedEvent(Image image) { }

View File

@@ -1,5 +0,0 @@
package domain.events.filtering;
import domain.image.Image;
public record LowPassChangedEvent(Image image) { }

View File

@@ -0,0 +1,5 @@
package domain.events.listeners;
public interface Listener {
}

View File

@@ -13,136 +13,96 @@ import java.util.List;
public class GlobalLinearFiltering { public class GlobalLinearFiltering {
public static GrayScaleMatrix lowPassFiltering(GrayScaleMatrix matrix, double cutoff) { public static GrayScaleMatrix lowPassFiltering(GrayScaleMatrix matrix, double cutoff) {
int width = matrix.getWidth(); int width = matrix.getWidth();
int height = matrix.getHeight(); int height = matrix.getHeight();
double minCutoff = 0; validateCutoff(cutoff, width, height);
double maxCutoff = Math.sqrt(Math.pow(width / 2.0, 2) + Math.pow(height / 2.0, 2));
if(cutoff < minCutoff || cutoff > maxCutoff){ Mat mat = toMat(matrix);
throw new IllegalArgumentException( Mat spectrum = fourierTransform(mat);
String.format("Cutoff value is out of bond (%f - %f)", minCutoff, maxCutoff)
);
}
Mat mat = new Mat(height, width, CvType.CV_64F); shiftSpectrum(spectrum);
applyIdealLowPassFilter(spectrum, cutoff);
shiftSpectrum(spectrum);
double[][] data = matrix.getRawData(); Mat filtered = inverseFourierTransform(spectrum);
for (int y = 0; y < height; y++) { return toGrayScaleMatrix(filtered);
mat.put(y, 0, data[y]); }
}
// Fourier transform public static GrayScaleMatrix highPassFiltering(GrayScaleMatrix matrix, double cutoff) {
Mat spectrum = new Mat(); int width = matrix.getWidth();
Core.dft(mat, spectrum, Core.DFT_COMPLEX_OUTPUT); int height = matrix.getHeight();
validateCutoff(cutoff, width, height);
Mat mat = toMat(matrix);
Mat spectrum = fourierTransform(mat);
shiftSpectrum(spectrum);
applyIdealHighPassFilter(spectrum, cutoff);
shiftSpectrum(spectrum);
Mat filtered = inverseFourierTransform(spectrum);
return toGrayScaleMatrix(filtered);
}
public static GrayScaleMatrix butterworthLowPassFiltering(GrayScaleMatrix matrix, double cutoff, int order) {
validateCutoff(cutoff, matrix.getWidth(), matrix.getHeight());
Mat spectrum = fourierTransform(toMat(matrix));
shiftSpectrum(spectrum);
applyButterworthLowPassFilter(spectrum, cutoff, order);
shiftSpectrum(spectrum);
return toGrayScaleMatrix(inverseFourierTransform(spectrum));
}
public static GrayScaleMatrix butterworthHighPassFiltering(GrayScaleMatrix matrix, double cutoff, int order) {
validateCutoff(cutoff, matrix.getWidth(), matrix.getHeight());
Mat spectrum = fourierTransform(toMat(matrix));
shiftSpectrum(spectrum);
applyButterworthHighPassFilter(spectrum, cutoff, order);
shiftSpectrum(spectrum);
return toGrayScaleMatrix(inverseFourierTransform(spectrum));
}
private static void applyIdealLowPassFilter(Mat spectrum, double cutoff) {
int width = spectrum.cols();
int height = spectrum.rows();
// Shift zero frequency to the center
int cx = width / 2; int cx = width / 2;
int cy = height / 2; int cy = height / 2;
Mat q0 = spectrum.submat(0, cy, 0, cx);
Mat q1 = spectrum.submat(0, cy, cx, width);
Mat q2 = spectrum.submat(cy, height, 0, cx);
Mat q3 = spectrum.submat(cy, height, cx, width);
Mat tmp = new Mat();
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
for (int y = 0; y < height; y++) { for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) { for (int x = 0; x < width; x++) {
double distance = Math.sqrt(Math.pow(x - cx, 2) + Math.pow(y - cy, 2));
double distance = Math.sqrt(
Math.pow(x - cx, 2) + Math.pow(y - cy, 2)
);
if (distance > cutoff) { if (distance > cutoff) {
spectrum.put(y, x, 0, 0); spectrum.put(y, x, 0, 0);
} }
} }
} }
// Shift back
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
// Inverse Fourier transform
Mat filtered = new Mat();
Core.idft(
spectrum,
filtered,
Core.DFT_REAL_OUTPUT | Core.DFT_SCALE
);
// Convert result back to your Image
double[][] pixels = new double[height][width];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
pixels[y][x] = Math.clamp(filtered.get(y, x)[0], 0.0, 255.0);
}
}
return new GrayScaleMatrix(pixels);
} }
public static GrayScaleMatrix highPassFiltering(GrayScaleMatrix matrix, double cutoff){ private static void applyIdealHighPassFilter(Mat spectrum, double cutoff) {
int width = matrix.getWidth(); int width = spectrum.cols();
int height = matrix.getHeight(); int height = spectrum.rows();
double minCutoff = 0;
double maxCutoff = Math.sqrt(Math.pow(width / 2.0, 2) + Math.pow(height / 2.0, 2));
if(cutoff < minCutoff || cutoff > maxCutoff){
throw new IllegalArgumentException(
String.format("Cutoff value is out of bond (%f - %f)", minCutoff, maxCutoff)
);
}
Mat mat = new Mat(height, width, CvType.CV_64F);
double[][] data = matrix.getRawData();
for (int y = 0; y < height; y++) {
mat.put(y, 0, data[y]);
}
// Fourier transform
Mat spectrum = new Mat();
Core.dft(mat, spectrum, Core.DFT_COMPLEX_OUTPUT);
// Shift zero frequency to the center
int cx = width / 2; int cx = width / 2;
int cy = height / 2; int cy = height / 2;
Mat q0 = spectrum.submat(0, cy, 0, cx);
Mat q1 = spectrum.submat(0, cy, cx, width);
Mat q2 = spectrum.submat(cy, height, 0, cx);
Mat q3 = spectrum.submat(cy, height, cx, width);
Mat tmp = new Mat();
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
for (int y = 0; y < height; y++) { for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) { for (int x = 0; x < width; x++) {
double distance = Math.sqrt(Math.pow(x - cx, 2) + Math.pow(y - cy, 2)); double distance = Math.sqrt(Math.pow(x - cx, 2) + Math.pow(y - cy, 2));
if (distance <= cutoff) { if (distance <= cutoff) {
@@ -150,8 +110,94 @@ public class GlobalLinearFiltering {
} }
} }
} }
}
private static void applyButterworthLowPassFilter(Mat spectrum, double cutoff, int order) {
int width = spectrum.cols();
int height = spectrum.rows();
int cx = width / 2;
int cy = height / 2;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
double distance = Math.sqrt(Math.pow(x - cx, 2) + Math.pow(y - cy, 2) );
double coefficient = 1.0 / (1.0 + Math.pow(distance / cutoff, 2 * order));
double[] value = spectrum.get(y, x);
spectrum.put(y, x, value[0] * coefficient, value[1] * coefficient);
}
}
}
private static void applyButterworthHighPassFilter(Mat spectrum, double cutoff, int order) {
int width = spectrum.cols();
int height = spectrum.rows();
int cx = width / 2;
int cy = height / 2;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
double distance = Math.sqrt(Math.pow(x - cx, 2) + Math.pow(y - cy, 2));
double coefficient;
if (distance == 0) {
coefficient = 0;
} else {
coefficient = 1.0 / (1.0 + Math.pow(cutoff / distance, 2 * order));
}
double[] value = spectrum.get(y, x);
spectrum.put(y, x, value[0] * coefficient, value[1] * coefficient);
}
}
}
private static void validateCutoff(double cutoff, int width, int height) {
double minCutoff = 0;
double maxCutoff = Math.sqrt(
Math.pow(width / 2.0, 2) +
Math.pow(height / 2.0, 2)
);
if (cutoff < minCutoff || cutoff > maxCutoff) {
throw new IllegalArgumentException(
String.format(
"Cutoff value is out of bounds (%f - %f)",
minCutoff,
maxCutoff
)
);
}
}
private static Mat fourierTransform(Mat mat) {
Mat spectrum = new Mat();
Core.dft(mat, spectrum, Core.DFT_COMPLEX_OUTPUT);
return spectrum;
}
private static void shiftSpectrum(Mat spectrum) {
int width = spectrum.cols();
int height = spectrum.rows();
int cx = width / 2;
int cy = height / 2;
Mat q0 = spectrum.submat(0, cy, 0, cx);
Mat q1 = spectrum.submat(0, cy, cx, width);
Mat q2 = spectrum.submat(cy, height, 0, cx);
Mat q3 = spectrum.submat(cy, height, cx, width);
Mat tmp = new Mat();
// Shift back
q0.copyTo(tmp); q0.copyTo(tmp);
q3.copyTo(q0); q3.copyTo(q0);
tmp.copyTo(q3); tmp.copyTo(q3);
@@ -159,8 +205,9 @@ public class GlobalLinearFiltering {
q1.copyTo(tmp); q1.copyTo(tmp);
q2.copyTo(q1); q2.copyTo(q1);
tmp.copyTo(q2); tmp.copyTo(q2);
}
// Inverse Fourier transform private static Mat inverseFourierTransform(Mat spectrum) {
Mat filtered = new Mat(); Mat filtered = new Mat();
Core.idft( Core.idft(
@@ -169,23 +216,41 @@ public class GlobalLinearFiltering {
Core.DFT_REAL_OUTPUT | Core.DFT_SCALE Core.DFT_REAL_OUTPUT | Core.DFT_SCALE
); );
// Convert result back to your Image return filtered;
}
private static GrayScaleMatrix toGrayScaleMatrix(Mat filtered) {
int width = filtered.cols();
int height = filtered.rows();
double[][] pixels = new double[height][width]; double[][] pixels = new double[height][width];
for (int y = 0; y < height; y++) { for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) { for (int x = 0; x < width; x++) {
pixels[y][x] = Math.clamp(filtered.get(y, x)[0], 0.0, 255.0); pixels[y][x] = Math.clamp(
filtered.get(y, x)[0],
0.0,
255.0
);
} }
} }
return new GrayScaleMatrix(pixels); return new GrayScaleMatrix(pixels);
} }
public static void butterworthLowPassFiltering(){ private static Mat toMat(GrayScaleMatrix matrix) {
int width = matrix.getWidth();
int height = matrix.getHeight();
Mat mat = new Mat(height, width, CvType.CV_64F);
double[][] data = matrix.getRawData();
for (int y = 0; y < height; y++) {
mat.put(y, 0, data[y]);
}
return mat;
} }
public static void butterworthHighPassFiltering(){
}
} }

View File

@@ -1,55 +0,0 @@
package presenters;
import app.state.FilteringState;
import com.google.common.eventbus.Subscribe;
import com.google.inject.Inject;
import domain.events.filtering.HighPassChangedEvent;
import domain.events.filtering.LowPassChangedEvent;
import domain.image.GrayScaleMatrix;
import domain.image.Image;
import services.FilteringService;
import services.ImageService;
import ui.abstractions.IFilteringView;
public class FilteringPresenter {
private final FilteringState state;
private final ImageService imageService;
private final FilteringService filteringService;
private IFilteringView view;
@Inject
public FilteringPresenter(FilteringState state, ImageService imageService, FilteringService filteringService) {
this.state = state;
this.state.register(this);
this.imageService = imageService;
this.filteringService = filteringService;
}
public void setView(IFilteringView view){
this.view = view;
}
public void computeLowPassFiltering(int percentage){
GrayScaleMatrix matrix = imageService.getGrayScale();
Image image = filteringService.lowPassFiltering(matrix, (double) percentage /100);
this.state.setLowPass(image);
}
public void computeHighPassFiltering(int percentage){
GrayScaleMatrix matrix = imageService.getGrayScale();
Image image = filteringService.highPassFiltering(matrix, (double) percentage /100);
this.state.setHighPass(image);
}
@Subscribe
public void onLowPassUpdate(LowPassChangedEvent event){
view.updateLowPassFiltering(event.image());
}
@Subscribe
public void onHighPassUpdate(HighPassChangedEvent event){
view.updateHighPassFiltering(event.image());
}
}

View File

@@ -1,67 +1,63 @@
package presenters; package presenters;
import com.google.common.eventbus.EventBus; import app.state.AppState;
import com.google.common.eventbus.Subscribe; import app.state.AppStateListener;
import com.google.inject.Inject; import com.google.inject.Inject;
import domain.common.Mode; import domain.common.Mode;
import domain.events.ImageChangedEvent;
import domain.events.ModeChangedEvent;
import domain.image.Image; import domain.image.Image;
import services.ImageService; import services.ImageService;
import services.ModeService; import services.ModeService;
import ui.abstractions.IMainView; import ui.abstractions.IMainView;
/** public class MainPresenter implements AppStateListener {
* @author Laurent Crema
*/
public class MainPresenter {
private IMainView view; private IMainView view;
private final AppState appState;
private final ModeService modeService; private final ModeService modeService;
private final ImageService imageService; private final ImageService imageService;
@Inject @Inject
public MainPresenter(ModeService modeService, ImageService imageService, EventBus eventBus) { public MainPresenter(AppState appState, ModeService modeService, ImageService imageService) {
this.appState = appState;
this.modeService = modeService; this.modeService = modeService;
this.imageService = imageService; this.imageService = imageService;
eventBus.register(this); this.appState.subscribe(this);
} }
public void setView(IMainView view) { public void setView(IMainView view) {
this.view = view; this.view = view;
} }
@Subscribe @Override
public void onImageChanged(ImageChangedEvent e){ public void onImageChanged(Image image) {
view.displayImage(e.image()); view.displayImage(image);
} }
@Subscribe @Override
public void onModeChanged(ModeChangedEvent e){ public void onModeChanged(Mode mode) {
view.changeMode(e.mode()); view.changeMode(mode);
} }
public void drawPixel(int x, int y, int red, int green, int blue){ public void drawPixel(int x, int y, int red, int green, int blue) {
if(modeService.getMode() != Mode.DRAW_PIXEL) return; if (modeService.getMode() != Mode.DRAW_PIXEL) return;
Image image = imageService.getImage();
Image image = appState.getImage();
image.setPixelColor(x, y, red, green, blue); image.setPixelColor(x, y, red, green, blue);
imageService.setImage(image); appState.setImage(image);
} }
public void drawShape(int x1, int x2, int y1, int y2, int red, int green, int blue){ public void drawShape(int x1, int x2, int y1, int y2, int red, int green, int blue) {
Image image = imageService.getImage(); Image image = appState.getImage();
switch (modeService.getMode()) { switch (modeService.getMode()) {
case DRAW_RECTANGLE: case DRAW_RECTANGLE -> image.setRectangleColor(x1, x2, y1, y2, red, green, blue);
image.setRectangleColor(x1, x2, y1, y2, red, green, blue); case DRAW_LINE -> image.setLineColor(x1, x2, y1, y2, red, green, blue);
break; case DRAW_CIRCLE -> {}
case DRAW_LINE:
image.setLineColor(x1, x2, y1, y2, red, green, blue);
break;
case DRAW_CIRCLE:
break;
} }
imageService.setImage(image);
appState.setImage(image);
} }
public void dispose() {
} appState.unsubscribe(this);
}
}

View File

@@ -1,9 +1,11 @@
package presenters; package presenters;
import app.INavigator; import app.INavigator;
import app.state.AppState;
import com.google.inject.Inject; import com.google.inject.Inject;
import domain.common.Mode; import domain.common.Mode;
import domain.image.GrayScaleMatrix; import domain.image.GrayScaleMatrix;
import domain.image.Image;
import services.ImageService; import services.ImageService;
import services.ModeService; import services.ModeService;
import ui.abstractions.INavBar; import ui.abstractions.INavBar;
@@ -11,19 +13,17 @@ import ui.abstractions.INavBar;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
/**
* @author Laurent Crema
*/
public class NavPresenter { public class NavPresenter {
private INavBar navBar; private INavBar navBar;
private INavigator navigator; private final INavigator navigator;
private final AppState appState;
private final ImageService imageService; private final ImageService imageService;
private final ModeService modeService; private final ModeService modeService;
@Inject @Inject
public NavPresenter(INavigator navigator, ImageService imageService, ModeService modeService) { public NavPresenter(INavigator navigator, AppState appState, ImageService imageService, ModeService modeService) {
this.navigator = navigator; this.navigator = navigator;
this.appState = appState;
this.imageService = imageService; this.imageService = imageService;
this.modeService = modeService; this.modeService = modeService;
} }
@@ -33,27 +33,28 @@ public class NavPresenter {
} }
public void createImage(int red, int green, int blue, int height, int width) { public void createImage(int red, int green, int blue, int height, int width) {
imageService.createImage(red, green, blue, height, width); Image image = imageService.createImage(red, green, blue, height, width);
appState.setImage(image);
} }
public void loadImage(File f) throws IOException { public void loadImage(File file) throws IOException {
imageService.loadImage(f); Image image = imageService.loadImage(file);
appState.setImage(image);
} }
public void goToFourier(){ public void goToFourier() {
navigator.showFourier(); navigator.showFourier();
} }
public void goToFiltering(){ public void goToFiltering() {
navigator.showFiltering(); navigator.showFiltering();
} }
public GrayScaleMatrix getImageGrayMatrix() { public GrayScaleMatrix getImageGrayMatrix() {
//return ((CImageNG)appState.getImage()).getMatrice(); return appState.getImage().toGrayScale();
return imageService.getImage().toGrayScale();
} }
public void setMode(Mode mode) { public void setMode(Mode mode) {
modeService.setMode(mode); modeService.setMode(mode);
} }
} }

View File

@@ -0,0 +1,12 @@
package presenters.doubleMatrix;
import domain.image.GrayScaleMatrix;
import domain.image.processing.complex.ComplexMatrix;
public interface DoubleMatrixListener {
void onFourierChanged(ComplexMatrix fourier);
void onModuleChanged(GrayScaleMatrix matrix);
void onPhaseChanged(GrayScaleMatrix matrix);
void onRealChanged(GrayScaleMatrix matrix);
void onImaginaryChanged(GrayScaleMatrix matrix);
}

View File

@@ -1,5 +1,6 @@
package presenters; package presenters.doubleMatrix;
import app.state.AppState;
import app.state.DoubleMatrixState; import app.state.DoubleMatrixState;
import com.google.common.eventbus.Subscribe; import com.google.common.eventbus.Subscribe;
import com.google.inject.Inject; import com.google.inject.Inject;
@@ -18,25 +19,26 @@ import java.io.IOException;
/** /**
* @author Laurent Crema * @author Laurent Crema
*/ */
public class DoubleMatrixPresenter { public class DoubleMatrixPresenter implements DoubleMatrixListener {
private IDoubleMatrix view; private IDoubleMatrix view;
private final AppState appState;
private final DoubleMatrixState state; private final DoubleMatrixState state;
private final ImageService imageService; private final ImageService imageService;
@Inject @Inject
public DoubleMatrixPresenter(ImageService imageService, DoubleMatrixState state) { public DoubleMatrixPresenter(AppState appState, ImageService imageService, DoubleMatrixState state) {
this.appState = appState;
this.imageService = imageService; this.imageService = imageService;
this.state = state; this.state = state;
this.state.register(this); this.state.subscribe(this);
} }
public void setView(IDoubleMatrix view){ public void setView(IDoubleMatrix view) {
this.view = view; this.view = view;
} }
public void saveImage(Image image) throws IOException { public void saveImage(Image image) throws IOException {
this.imageService.saveImage(image); imageService.saveImage(image);
} }
public void loadModule(){ public void loadModule(){
@@ -87,28 +89,32 @@ public class DoubleMatrixPresenter {
state.setImaginary(matrix); state.setImaginary(matrix);
} }
@Subscribe @Override
public void onModuleUpdate(ModuleChangedEvent event) { public void onModuleChanged(GrayScaleMatrix matrix) {
GrayScaleMatrix module = new GrayScaleMatrix(getFourier().getModule()); GrayScaleMatrix module = new GrayScaleMatrix(getFourier().getModule());
view.updateModule(module, event.matrix()); view.updateModule(module, matrix);
} }
@Subscribe @Override
public void onPhaseUpdate(PhaseChangedEvent event) { public void onPhaseChanged(GrayScaleMatrix matrix) {
GrayScaleMatrix phase = new GrayScaleMatrix(getFourier().getPhase()); GrayScaleMatrix phase = new GrayScaleMatrix(getFourier().getPhase());
view.updatePhase(phase, event.matrix()); view.updatePhase(phase, matrix);
} }
@Subscribe @Override
public void onRealUpdate(RealChangedEvent event) { public void onRealChanged(GrayScaleMatrix matrix) {
GrayScaleMatrix real = new GrayScaleMatrix(getFourier().getPartieReelle()); GrayScaleMatrix real = new GrayScaleMatrix(getFourier().getPartieReelle());
view.updateReal(real, event.matrix()); view.updateReal(real, matrix);
} }
@Subscribe @Override
public void onImaginaryUpdate(ImaginaryChangedEvent event) { public void onFourierChanged(ComplexMatrix fourier) {
}
@Override
public void onImaginaryChanged(GrayScaleMatrix matrix) {
GrayScaleMatrix imaginary = new GrayScaleMatrix(getFourier().getPartieImaginaire()); GrayScaleMatrix imaginary = new GrayScaleMatrix(getFourier().getPartieImaginaire());
view.updateImaginary(imaginary, event.matrix()); view.updateImaginary(imaginary, matrix);
} }
private GrayScaleMatrix clip(GrayScaleMatrix matrix, double black, double white){ private GrayScaleMatrix clip(GrayScaleMatrix matrix, double black, double white){
@@ -119,7 +125,7 @@ public class DoubleMatrixPresenter {
private ComplexMatrix getFourier() { private ComplexMatrix getFourier() {
if (state.getFourier() == null) { if (state.getFourier() == null) {
state.setFourier(imageService.computeFourier()); state.setFourier(imageService.computeFourier(appState.getImage()));
} }
return state.getFourier(); return state.getFourier();
} }

View File

@@ -0,0 +1,11 @@
package presenters.filtering;
import domain.events.listeners.Listener;
import domain.image.Image;
public interface FilteringListener extends Listener {
void onLowPassChanged(Image image);
void onHighPassChanged(Image image);
void onButterworthLowPassChanged(Image image);
void onButterworthHighPassChanged(Image image);
}

View File

@@ -0,0 +1,79 @@
package presenters.filtering;
import app.state.AppState;
import app.state.FilteringState;
import com.google.inject.Inject;
import domain.image.GrayScaleMatrix;
import domain.image.Image;
import services.FilteringService;
import services.ImageService;
import ui.abstractions.IFilteringView;
public class FilteringPresenter implements FilteringListener {
private final AppState appState;
private final FilteringState state;
private final ImageService imageService;
private final FilteringService filteringService;
private IFilteringView view;
@Inject
public FilteringPresenter(AppState appState, FilteringState state, ImageService imageService, FilteringService filteringService) {
this.appState = appState;
this.state = state;
this.imageService = imageService;
this.filteringService = filteringService;
this.state.subscribe(this);
}
public void setView(IFilteringView view) {
this.view = view;
}
public void computeLowPassFiltering(float percentage) {
GrayScaleMatrix matrix = imageService.getGrayScale(appState.getImage());
Image image = filteringService.lowPassFiltering(matrix, percentage / 100);
state.setLowPass(image);
}
public void computeHighPassFiltering(float percentage) {
GrayScaleMatrix matrix = imageService.getGrayScale(appState.getImage());
Image image = filteringService.highPassFiltering(matrix, percentage / 100);
state.setHighPass(image);
}
public void computeButterworthLowPassFiltering(float percentage) {
GrayScaleMatrix matrix = imageService.getGrayScale(appState.getImage());
Image image = filteringService.butterworthLowPassFiltering(matrix, percentage / 100);
state.setButterworthLowPass(image);
}
public void computeButterworthHighPassFiltering(float percentage) {
GrayScaleMatrix matrix = imageService.getGrayScale(appState.getImage());
Image image = filteringService.butterworthHighPassFiltering(matrix, percentage / 100);
state.setButterworthHighPass(image);
}
@Override
public void onLowPassChanged(Image image) {
view.updateLowPassFiltering(image);
}
@Override
public void onHighPassChanged(Image image) {
view.updateHighPassFiltering(image);
}
@Override
public void onButterworthLowPassChanged(Image image) {
view.updateButterworthLowPassFiltering(image);
}
@Override
public void onButterworthHighPassChanged(Image image) {
view.updateButterworthHighPassFiltering(image);
}
public void dispose() {
state.unsubscribe(this);
}
}

View File

@@ -22,4 +22,11 @@ public class FilteringService {
return Math.sqrt(Math.pow(width / 2.0, 2) + Math.pow(height / 2.0, 2)); return Math.sqrt(Math.pow(width / 2.0, 2) + Math.pow(height / 2.0, 2));
} }
public Image butterworthLowPassFiltering(GrayScaleMatrix matrix, float v) {
return null;
}
public Image butterworthHighPassFiltering(GrayScaleMatrix matrix, float v) {
return null;
}
} }

View File

@@ -1,9 +1,7 @@
package services; package services;
import app.state.AppState;
import com.google.inject.Inject;
import domain.image.Image;
import domain.image.GrayScaleMatrix; import domain.image.GrayScaleMatrix;
import domain.image.Image;
import domain.image.processing.complex.ComplexMatrix; import domain.image.processing.complex.ComplexMatrix;
import domain.image.processing.fourier.Fourier; import domain.image.processing.fourier.Fourier;
import infrastructure.image.io.ImageLoader; import infrastructure.image.io.ImageLoader;
@@ -17,42 +15,25 @@ import java.io.IOException;
*/ */
public class ImageService { public class ImageService {
private final AppState appState; public Image createImage(int red, int green, int blue, int height, int width) {
return new Image(red, green, blue, height, width);
@Inject
public ImageService(AppState appState) {
this.appState = appState;
} }
public void createImage(int red, int green, int blue, int height, int width) { public Image loadImage(File file) throws IOException {
Image image = new Image(red, green, blue, height, width); return ImageLoader.loadImage(file);
appState.setImage(image);
}
public void loadImage(File f) throws IOException {
Image image = ImageLoader.loadImage(f);
appState.setImage(image);
} }
public void saveImage(Image image) throws IOException { public void saveImage(Image image) throws IOException {
ImageSaver.saveImage(image); ImageSaver.saveImage(image);
} }
public ComplexMatrix computeFourier(){ public ComplexMatrix computeFourier(Image image) {
GrayScaleMatrix matrix = appState.getImage().toGrayScale(); GrayScaleMatrix matrix = image.toGrayScale();
ComplexMatrix fourier = Fourier.Fourier2D(matrix.getRawData()); ComplexMatrix fourier = Fourier.Fourier2D(matrix.getRawData());
return Fourier.decroise(fourier); return Fourier.decroise(fourier);
} }
public Image getImage(){ public GrayScaleMatrix getGrayScale(Image image) {
return appState.getImage(); return image.toGrayScale();
} }
}
public void setImage(Image img){
appState.setImage(img);
}
public GrayScaleMatrix getGrayScale(){
return appState.getImage().toGrayScale();
}
}

View File

@@ -5,4 +5,11 @@ import javax.swing.*;
public abstract class AbstractView extends JFrame { public abstract class AbstractView extends JFrame {
public abstract void initComponents(); public abstract void initComponents();
public abstract void initValues(); public abstract void initValues();
public abstract void disposeCore();
@Override
public void dispose() {
disposeCore();
super.dispose();
}
} }

View File

@@ -0,0 +1,17 @@
package ui.implementation.components.controls;
import javax.swing.*;
import java.awt.event.ActionListener;
public class IntensitySlider extends JSlider {
public IntensitySlider() {
super();
setMinimum(0);
setMaximum(1000);
}
public float getPercentage(){
return (float) getValue() /10;
}
}

View File

@@ -1,4 +1,4 @@
package ui.implementation.components.button; package ui.implementation.components.controls;
import javax.swing.*; import javax.swing.*;
import java.net.URL; import java.net.URL;

View File

@@ -0,0 +1,29 @@
package ui.implementation.components.image;
import domain.image.Image;
import infrastructure.ui.ImageMapper;
import javax.swing.*;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
public class TabbedImagePanel extends JTabbedPane {
private final Map<String, ImagePanel> tabs;
public TabbedImagePanel() {
this.tabs = new HashMap<>();
}
public void addPreviewTab(String title) {
ImagePanel panel = new ImagePanel();
tabs.put(title, panel);
addTab(title, panel);
}
public void loadImage(String title, Image image) {
BufferedImage bufferedImage = ImageMapper.toBufferedImage(image);
tabs.get(title).loadImage(bufferedImage);
}
}

View File

@@ -2,9 +2,9 @@ package ui.implementation.views;
import domain.image.GrayScaleMatrix; import domain.image.GrayScaleMatrix;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import presenters.DoubleMatrixPresenter; import presenters.doubleMatrix.DoubleMatrixPresenter;
import ui.abstractions.AbstractView; import ui.abstractions.AbstractView;
import ui.implementation.components.button.SaveButton; import ui.implementation.components.controls.SaveButton;
import ui.implementation.components.image.ImagePanel; import ui.implementation.components.image.ImagePanel;
import ui.implementation.components.intent.FileChooser; import ui.implementation.components.intent.FileChooser;
import ui.abstractions.IDoubleMatrix; import ui.abstractions.IDoubleMatrix;
@@ -96,6 +96,11 @@ public class DoubleMatrix extends AbstractView implements IDoubleMatrix
this.whiteTextField.addActionListener(this::jTextFieldBlancActionPerformed); this.whiteTextField.addActionListener(this::jTextFieldBlancActionPerformed);
} }
@Override
public void disposeCore() {
this.presenter.setView(null);
}
private JSlider buildSlider() { private JSlider buildSlider() {
return new JSlider(JSlider.VERTICAL); return new JSlider(JSlider.VERTICAL);
} }

View File

@@ -2,39 +2,42 @@ package ui.implementation.views;
import com.google.inject.Inject; import com.google.inject.Inject;
import domain.image.Image; import domain.image.Image;
import infrastructure.ui.ImageMapper; import presenters.filtering.FilteringPresenter;
import presenters.FilteringPresenter;
import ui.abstractions.AbstractView; import ui.abstractions.AbstractView;
import ui.implementation.components.button.SaveButton; import ui.implementation.components.controls.IntensitySlider;
import ui.implementation.components.image.ImagePanel; import ui.implementation.components.controls.SaveButton;
import ui.abstractions.IFilteringView; import ui.abstractions.IFilteringView;
import ui.implementation.components.image.TabbedImagePanel;
import javax.swing.*; import javax.swing.*;
import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeEvent;
public class FilteringView extends AbstractView implements IFilteringView { public class IdealFilteringView extends AbstractView implements IFilteringView {
private ImagePanel lowPassContainer; private final static String LOW_PASS_TAB_TITLE = "Passe-haut";
private ImagePanel highPassContainer; private final static String HIGH_PASS_TAB_TITLE = "Passe-bas";
private JTabbedPane modeTab;
private JSlider intensitySlider; private TabbedImagePanel modeTab;
private IntensitySlider intensitySlider;
private JLabel intensityLabel; private JLabel intensityLabel;
private final FilteringPresenter presenter; private final FilteringPresenter presenter;
private boolean isUpdating; private boolean isUpdating;
@Inject @Inject
public FilteringView(FilteringPresenter presenter) { public IdealFilteringView(FilteringPresenter presenter) {
this.presenter = presenter; this.presenter = presenter;
} }
@Override @Override
public void initComponents(){ public void initComponents(){
this.lowPassContainer = new ImagePanel();
this.highPassContainer = new ImagePanel();
this.modeTab = buildModeTab();
this.intensitySlider = new JSlider(0,100,0);
this.intensitySlider.setOrientation(JSlider.VERTICAL);
this.intensityLabel = new JLabel(); this.intensityLabel = new JLabel();
this.intensitySlider = new IntensitySlider();
this.intensitySlider.setOrientation(JSlider.VERTICAL);
this.modeTab = new TabbedImagePanel();
this.modeTab.addPreviewTab(LOW_PASS_TAB_TITLE);
this.modeTab.addPreviewTab(HIGH_PASS_TAB_TITLE);
JButton saveButton = new SaveButton(); JButton saveButton = new SaveButton();
saveButton.addActionListener(e -> {}); saveButton.addActionListener(e -> {});
@@ -45,33 +48,7 @@ public class FilteringView extends AbstractView implements IFilteringView {
pack(); pack();
} }
@Override
public void initValues(){
this.presenter.setView(this);
this.intensitySlider.setMinimum(0);
this.intensitySlider.setMaximum(100);
this.intensitySlider.setValue(50);
this.intensitySlider.addChangeListener(this::onCutoffUpdate);
this.intensityLabel.setText(String.valueOf(intensitySlider.getValue()));
this.modeTab.addChangeListener(e -> {
switch (modeTab.getSelectedIndex()) {
case 0 -> presenter.computeLowPassFiltering(intensitySlider.getValue());
case 1 -> presenter.computeHighPassFiltering(intensitySlider.getValue());
}
});
this.presenter.computeLowPassFiltering(intensitySlider.getValue());
}
private JTabbedPane buildModeTab(){
JTabbedPane modeTabs = new JTabbedPane();
modeTabs.addTab("Passe-bas", lowPassContainer);
modeTabs.addTab("Passe-haut", highPassContainer);
return modeTabs;
}
private void buildLayout(JTabbedPane modeTab, private void buildLayout(JTabbedPane modeTab,
JLabel valueTextField, JLabel valueTextField,
@@ -158,10 +135,10 @@ public class FilteringView extends AbstractView implements IFilteringView {
if (isUpdating) return; if (isUpdating) return;
isUpdating = true; isUpdating = true;
try { try {
this.intensityLabel.setText(String.valueOf(intensitySlider.getValue())); this.intensityLabel.setText(String.valueOf(intensitySlider.getPercentage()));
switch (modeTab.getSelectedIndex()) { switch (modeTab.getSelectedIndex()) {
case 0 -> presenter.computeLowPassFiltering(intensitySlider.getValue()); case 0 -> presenter.computeLowPassFiltering(intensitySlider.getPercentage());
case 1 -> presenter.computeHighPassFiltering(intensitySlider.getValue()); case 1 -> presenter.computeHighPassFiltering(intensitySlider.getPercentage());
} }
} finally { } finally {
isUpdating = false; isUpdating = false;
@@ -170,12 +147,12 @@ public class FilteringView extends AbstractView implements IFilteringView {
@Override @Override
public void updateLowPassFiltering(Image image) { public void updateLowPassFiltering(Image image) {
lowPassContainer.loadImage(ImageMapper.toBufferedImage(image)); modeTab.loadImage(LOW_PASS_TAB_TITLE, image);
} }
@Override @Override
public void updateHighPassFiltering(Image image) { public void updateHighPassFiltering(Image image) {
highPassContainer.loadImage(ImageMapper.toBufferedImage(image)); modeTab.loadImage(HIGH_PASS_TAB_TITLE, image);
} }
@Override @Override
@@ -187,4 +164,27 @@ public class FilteringView extends AbstractView implements IFilteringView {
public void updateButterworthLowPassFiltering(Image image) { public void updateButterworthLowPassFiltering(Image image) {
} }
@Override
public void initValues(){
this.presenter.setView(this);
this.intensitySlider.addChangeListener(this::onCutoffUpdate);
this.intensityLabel.setText(String.valueOf(intensitySlider.getValue()));
this.modeTab.addChangeListener(e -> {
switch (modeTab.getSelectedIndex()) {
case 0 -> presenter.computeLowPassFiltering(intensitySlider.getPercentage());
case 1 -> presenter.computeHighPassFiltering(intensitySlider.getPercentage());
}
});
this.presenter.computeLowPassFiltering(intensitySlider.getPercentage());
}
@Override
public void disposeCore() {
this.presenter.setView(null);
this.presenter.dispose();
}
} }

View File

@@ -0,0 +1,190 @@
package ui.implementation.views;
import com.google.inject.Inject;
import domain.image.Image;
import presenters.filtering.FilteringPresenter;
import ui.abstractions.AbstractView;
import ui.abstractions.IFilteringView;
import ui.implementation.components.controls.IntensitySlider;
import ui.implementation.components.controls.SaveButton;
import ui.implementation.components.image.TabbedImagePanel;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
public class NonIdealFilteringView extends AbstractView implements IFilteringView {
private final static String LOW_PASS_TAB_TITLE = "Passe-haut";
private final static String HIGH_PASS_TAB_TITLE = "Passe-bas";
private TabbedImagePanel modeTab;
private IntensitySlider intensitySlider;
private JLabel intensityLabel;
private final FilteringPresenter presenter;
private boolean isUpdating;
@Inject
public NonIdealFilteringView(FilteringPresenter presenter) {
this.presenter = presenter;
}
private void buildLayout(JTabbedPane modeTab,
JLabel valueTextField,
JSlider intensitySlider,
JButton saveButton) {
JPanel rightPanel = new JPanel();
GroupLayout rightLayout = new GroupLayout(rightPanel);
rightPanel.setLayout(rightLayout);
rightLayout.setHorizontalGroup(
rightLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(valueTextField, GroupLayout.PREFERRED_SIZE, 90, GroupLayout.PREFERRED_SIZE)
.addGroup(rightLayout.createSequentialGroup()
.addComponent(intensitySlider)
.addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
)
);
rightLayout.setVerticalGroup(
rightLayout.createSequentialGroup()
.addComponent(valueTextField, GroupLayout.PREFERRED_SIZE,
GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addGroup(rightLayout.createParallelGroup(GroupLayout.Alignment.CENTER)
.addComponent(intensitySlider)
)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
);
// -------------------------
// MAIN LAYOUT
// -------------------------
GroupLayout layout = new GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(GroupLayout.Alignment.LEADING)
// TOP BAR
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
//.addComponent(valeurMin)
.addGap(50)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
//.addComponent(valeurMax)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED,
GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(saveButton)
.addContainerGap()
)
// MAIN ROW
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(modeTab, 400, 400, Short.MAX_VALUE)
.addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(rightPanel, GroupLayout.PREFERRED_SIZE,
GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addContainerGap()
)
);
layout.setVerticalGroup(
layout.createSequentialGroup()
// TOP BAR
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(saveButton)
)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
// MAIN CONTENT
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(modeTab)
.addComponent(rightPanel)
)
);
}
private void onCutoffUpdate(ChangeEvent e) {
if (isUpdating) return;
isUpdating = true;
try {
this.intensityLabel.setText(String.valueOf(intensitySlider.getPercentage()));
switch (modeTab.getSelectedIndex()) {
case 0 -> presenter.computeLowPassFiltering(intensitySlider.getPercentage());
case 1 -> presenter.computeHighPassFiltering(intensitySlider.getPercentage());
}
} finally {
isUpdating = false;
}
}
@Override
public void updateLowPassFiltering(Image image) {
}
@Override
public void updateHighPassFiltering(Image image) {
}
@Override
public void updateButterworthHighPassFiltering(Image image) {
modeTab.loadImage(LOW_PASS_TAB_TITLE, image);
}
@Override
public void updateButterworthLowPassFiltering(Image image) {
modeTab.loadImage(HIGH_PASS_TAB_TITLE, image);
}
@Override
public void initComponents(){
this.intensityLabel = new JLabel();
this.intensitySlider = new IntensitySlider();
this.intensitySlider.setOrientation(JSlider.VERTICAL);
this.modeTab = new TabbedImagePanel();
this.modeTab.addPreviewTab(LOW_PASS_TAB_TITLE);
this.modeTab.addPreviewTab(HIGH_PASS_TAB_TITLE);
JButton saveButton = new SaveButton();
saveButton.addActionListener(e -> {});
buildLayout(modeTab, intensityLabel, intensitySlider, saveButton);
setTitle("Filtering");
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
pack();
}
@Override
public void initValues(){
this.presenter.setView(this);
this.intensitySlider.addChangeListener(this::onCutoffUpdate);
this.intensityLabel.setText(String.valueOf(intensitySlider.getValue()));
this.modeTab.addChangeListener(e -> {
switch (modeTab.getSelectedIndex()) {
case 0 -> presenter.computeLowPassFiltering(intensitySlider.getPercentage());
case 1 -> presenter.computeHighPassFiltering(intensitySlider.getPercentage());
}
});
this.presenter.computeLowPassFiltering(intensitySlider.getPercentage());
}
@Override
public void disposeCore() {
this.presenter.setView(null);
this.presenter.dispose();
}
}