Extract save button

This commit is contained in:
2026-09-29 14:26:23 +02:00
parent b8544b8f46
commit 8360fc0a6a
11 changed files with 113 additions and 122 deletions

View File

@@ -7,8 +7,16 @@ import java.util.Objects;
public class SaveButton extends JButton {
public SaveButton(){
this(() -> {});
}
public SaveButton(Runnable onClick) {
super(new ImageIcon());
URL icon = Objects.requireNonNull(getClass().getResource("/dd_27_p3.jpg"));
setIcon(new ImageIcon(Objects.requireNonNull(icon)));
setIcon(new ImageIcon(icon));
addActionListener(e -> onClick.run());
}
}

View File

@@ -1,44 +1,94 @@
package ui.implementation.components.image;
import domain.image.GrayScaleMatrix;
import domain.image.Image;
import infrastructure.ui.ImageMapper;
import ui.implementation.components.controls.SaveButton;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.WritableRaster;
import java.util.function.Consumer;
/**
* @author Laurent Crema
*/
public class ImagePanel extends JPanel {
private BufferedImage image;
private double scale;
private int drawW;
private int drawH;
private int offsetX;
private int offsetY;
public ImagePanel() { }
public ImagePanel() {
this(image -> {});
}
public ImagePanel(BufferedImage image) {
this();
loadImage(image);
}
public void loadImage(BufferedImage image){
public ImagePanel(BufferedImage image, Consumer<BufferedImage> onSave) {
this(onSave);
loadImage(image);
}
public ImagePanel(Consumer<BufferedImage> onSave) {
setLayout(new OverlayLayout(this));
SaveButton saveButton = new SaveButton(
() -> {
if (image != null) {
onSave.accept(getImage());
}
}
);
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
buttonPanel.setOpaque(false);
buttonPanel.add(saveButton);
add(buttonPanel);
}
public void loadImage(BufferedImage image) {
this.image = image;
setPreferredSize(new Dimension(image.getWidth(null), image.getHeight(null)));
setPreferredSize(new Dimension(image.getWidth(), image.getHeight()));
revalidate();
repaint();
}
public void loadImage(GrayScaleMatrix matrix){
this.image = ImageMapper.toBufferedImage(matrix.toImage());
setPreferredSize(new Dimension(this.image.getWidth(null), this.image.getHeight(null)));
repaint();
public void loadImage(GrayScaleMatrix matrix) {
loadImage(ImageMapper.toBufferedImage(matrix.toImage()));
}
/**
* @return A copy of the currently retained image.
*/
public BufferedImage getImage() {
if (image == null) {
return null;
}
ColorModel colorModel = image.getColorModel();
boolean isAlphaPremultiplied = image.isAlphaPremultiplied();
WritableRaster raster = image.copyData(null);
return new BufferedImage(colorModel, raster, isAlphaPremultiplied,null);
}
public Point toImageCoordinates(int x, int y) {
if (image == null) return null;
if (image == null) {
return null;
}
if (x < offsetX || x >= offsetX + drawW ||
y < offsetY || y >= offsetY + drawH) {
@@ -52,30 +102,27 @@ public class ImagePanel extends JPanel {
}
private void computeViewport() {
if (image == null) return;
if (image == null) {
return;
}
int imgW = image.getWidth();
int imgH = image.getHeight();
int imgW = image.getWidth();
int imgH = image.getHeight();
scale = Math.min(
(double) getWidth() / imgW,
(double) getHeight() / imgH
);
scale = Math.min((double) getWidth() / imgW, (double) getHeight() / imgH);
drawW = (int) (imgW * scale);
drawH = (int) (imgH * scale);
drawW = (int) (imgW * scale);
drawH = (int) (imgH * scale);
offsetX = (getWidth() - drawW) / 2;
offsetY = (getHeight() - drawH) / 2;
offsetX = (getWidth() - drawW) / 2;
offsetY = (getHeight() - drawH) / 2;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (image == null) return;
computeViewport();
g.drawImage(image, offsetX, offsetY, drawW, drawH, null);
g.drawImage(image, offsetX, offsetY, drawW, drawH,null);
}
}
}

View File

@@ -4,7 +4,6 @@ import domain.image.GrayScaleMatrix;
import jakarta.inject.Inject;
import presenters.doubleMatrix.DoubleMatrixPresenter;
import ui.abstractions.AbstractView;
import ui.implementation.components.controls.SaveButton;
import ui.implementation.components.image.ImagePanel;
import ui.implementation.components.intent.FileChooser;
import ui.abstractions.IDoubleMatrix;
@@ -32,8 +31,6 @@ public class DoubleMatrix extends AbstractView implements IDoubleMatrix
private ImagePanel realPreviewContainer;
private ImagePanel imaginaryPreviewContainer;
private SaveButton saveButton;
private JSlider whiteSlider;
private JTextField whiteTextField;
private JLabel maxLabel;
@@ -57,7 +54,6 @@ public class DoubleMatrix extends AbstractView implements IDoubleMatrix
this.phasePreviewContainer = new ImagePanel();
this.realPreviewContainer = new ImagePanel();
this.imaginaryPreviewContainer = new ImagePanel();
this.saveButton = new SaveButton();
blackSlider = buildSlider();
whiteSlider = buildSlider();
@@ -71,7 +67,7 @@ public class DoubleMatrix extends AbstractView implements IDoubleMatrix
JLabel maxValueText = new JLabel("Valeur MAX :");
modeTab = buildModeTab();
buildLayout(modeTab, maxValueText, minValueText, minLabel, maxLabel, saveButton);
buildLayout(modeTab, maxValueText, minValueText, minLabel, maxLabel);
setTitle("Fourier");
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
@@ -87,8 +83,6 @@ public class DoubleMatrix extends AbstractView implements IDoubleMatrix
this.blackSlider.setValue(0);
this.whiteSlider.setValue(1000);
this.saveButton.addActionListener(this::saveImage);
this.blackSlider.addChangeListener(this::onValueUpdate);
this.whiteSlider.addChangeListener(this::onValueUpdate);
@@ -141,8 +135,7 @@ public class DoubleMatrix extends AbstractView implements IDoubleMatrix
private void buildLayout(JTabbedPane modeTab,
JLabel labelMax, JLabel labelMin,
JLabel valeurMin, JLabel valeurMax,
JButton saveButton) {
JLabel valeurMin, JLabel valeurMax) {
JPanel rightPanel = new JPanel();
GroupLayout rightLayout = new GroupLayout(rightPanel);
@@ -194,7 +187,6 @@ public class DoubleMatrix extends AbstractView implements IDoubleMatrix
.addComponent(valeurMax)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED,
GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(saveButton)
.addContainerGap()
)
@@ -205,8 +197,7 @@ public class DoubleMatrix extends AbstractView implements IDoubleMatrix
.addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(rightPanel, GroupLayout.PREFERRED_SIZE,
GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addContainerGap()
)
.addContainerGap())
);
layout.setVerticalGroup(
@@ -217,15 +208,13 @@ public class DoubleMatrix extends AbstractView implements IDoubleMatrix
.addComponent(labelMin)
.addComponent(valeurMin)
.addComponent(labelMax)
.addComponent(valeurMax)
.addComponent(saveButton)
)
.addComponent(valeurMax))
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
// MAIN CONTENT
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(modeTab)
.addComponent(modeTab, 400, 400, Short.MAX_VALUE)
.addComponent(rightPanel)
)
);

View File

@@ -29,10 +29,7 @@ public class IdealFilteringView extends AbstractView implements IGlobalFiltering
}
private void buildLayout(JTabbedPane modeTab,
JLabel valueTextField,
JSlider intensitySlider,
JButton saveButton) {
private void buildLayout(JTabbedPane modeTab, JLabel valueTextField, JSlider intensitySlider) {
JPanel rightPanel = new JPanel();
GroupLayout rightLayout = new GroupLayout(rightPanel);
@@ -77,7 +74,6 @@ public class IdealFilteringView extends AbstractView implements IGlobalFiltering
//.addComponent(valeurMax)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED,
GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(saveButton)
.addContainerGap()
)
@@ -96,15 +92,12 @@ public class IdealFilteringView extends AbstractView implements IGlobalFiltering
layout.createSequentialGroup()
// TOP BAR
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(saveButton)
)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE))
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
// MAIN CONTENT
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(modeTab)
.addComponent(modeTab, 400, 400, Short.MAX_VALUE)
.addComponent(rightPanel)
)
);
@@ -154,11 +147,9 @@ public class IdealFilteringView extends AbstractView implements IGlobalFiltering
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);
buildLayout(modeTab, intensityLabel, intensitySlider);
setTitle("Filtre idéal");
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
pack();

View File

@@ -30,7 +30,7 @@ public class NonIdealFilteringView extends AbstractView implements IGlobalFilter
this.presenter = presenter;
}
private void buildLayout(JTabbedPane modeTab, JButton saveButton) {
private void buildLayout(JTabbedPane modeTab) {
JPanel rightPanel = new JPanel();
GroupLayout rightLayout = new GroupLayout(rightPanel);
@@ -79,7 +79,6 @@ public class NonIdealFilteringView extends AbstractView implements IGlobalFilter
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED,
GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(saveButton)
.addContainerGap()
)
@@ -98,15 +97,13 @@ public class NonIdealFilteringView extends AbstractView implements IGlobalFilter
layout.createSequentialGroup()
// TOP BAR
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
.addComponent(saveButton)
)
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE))
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
// MAIN CONTENT
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
.addComponent(modeTab)
.addComponent(modeTab, 400, 400, Short.MAX_VALUE)
.addComponent(rightPanel)
)
);
@@ -175,11 +172,7 @@ public class NonIdealFilteringView extends AbstractView implements IGlobalFilter
this.modeTab.addPreviewTab(LOW_PASS_TAB_TITLE);
this.modeTab.addPreviewTab(HIGH_PASS_TAB_TITLE);
JButton saveButton = new SaveButton();
saveButton.addActionListener(e -> {});
buildLayout(modeTab, saveButton);
buildLayout(modeTab);
setTitle("Filtre non-idéal");
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
pack();

View File

@@ -50,7 +50,6 @@ public class LocalFilteringView extends AbstractView implements ILocalFilteringV
JButton applyMeanButton = new JButton("Appliquer moyenneur");
applyMeanButton.addActionListener(e -> applyMean());
JButton saveButton = new SaveButton();
buildLayout(
modeTab,
@@ -59,9 +58,7 @@ public class LocalFilteringView extends AbstractView implements ILocalFilteringV
convolutionMaskPanel,
applyConvolutionButton,
meanSizeField,
applyMeanButton,
saveButton
);
applyMeanButton);
setTitle("Filtrage linéaire local");
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
@@ -150,9 +147,7 @@ public class LocalFilteringView extends AbstractView implements ILocalFilteringV
JPanel convolutionMaskPanel,
JButton applyConvolutionButton,
JTextField meanSizeField,
JButton applyMeanButton,
JButton saveButton
) {
JButton applyMeanButton) {
JPanel convolutionPanel = new JPanel();
GroupLayout convolutionLayout = new GroupLayout(convolutionPanel);
convolutionPanel.setLayout(convolutionLayout);
@@ -206,13 +201,11 @@ public class LocalFilteringView extends AbstractView implements ILocalFilteringV
rightLayout.setHorizontalGroup(
rightLayout.createParallelGroup(GroupLayout.Alignment.CENTER)
.addComponent(operationTabs)
.addComponent(saveButton)
);
rightLayout.setVerticalGroup(
rightLayout.createSequentialGroup()
.addComponent(operationTabs)
.addComponent(saveButton)
);
JPanel mainPanel = new JPanel();

View File

@@ -5,7 +5,6 @@ import jakarta.inject.Inject;
import presenters.morphology.BasicMorphologyPresenter;
import ui.abstractions.AbstractView;
import ui.abstractions.IBasicMorphologyView;
import ui.implementation.components.controls.SaveButton;
import ui.implementation.components.image.TabbedImagePanel;
import javax.swing.*;
@@ -44,7 +43,6 @@ public class BasicMorphologyView extends AbstractView implements IBasicMorpholog
JButton applyButton = new JButton("Appliquer");
applyButton.addActionListener(e -> applyMorphology());
JButton saveButton = new SaveButton();
JPanel controlPanel = createControlPanel(
maskSizeSpinner,
@@ -61,13 +59,11 @@ public class BasicMorphologyView extends AbstractView implements IBasicMorpholog
rightLayout.setHorizontalGroup(
rightLayout.createParallelGroup(GroupLayout.Alignment.CENTER)
.addComponent(controlPanel)
.addComponent(saveButton)
);
rightLayout.setVerticalGroup(
rightLayout.createSequentialGroup()
.addComponent(controlPanel)
.addComponent(saveButton)
);
JPanel mainPanel = new JPanel();
@@ -79,13 +75,13 @@ public class BasicMorphologyView extends AbstractView implements IBasicMorpholog
mainLayout.setHorizontalGroup(
mainLayout.createSequentialGroup()
.addComponent(modeTab)
.addComponent(modeTab, 400, 400, Short.MAX_VALUE)
.addComponent(rightPanel)
);
mainLayout.setVerticalGroup(
mainLayout.createParallelGroup(GroupLayout.Alignment.CENTER)
.addComponent(modeTab)
.addComponent(modeTab, 400, 400, Short.MAX_VALUE)
.addComponent(rightPanel)
);

View File

@@ -7,7 +7,6 @@ import jakarta.inject.Inject;
import presenters.morphology.ComplexMorphologyPresenter;
import ui.abstractions.AbstractView;
import ui.abstractions.IComplexMorphologyView;
import ui.implementation.components.controls.SaveButton;
import ui.implementation.components.image.TabbedImagePanel;
import ui.implementation.components.intent.FileChooser;
@@ -55,7 +54,6 @@ public class ComplexMorphologyView extends AbstractView implements IComplexMorph
JButton applyButton = new JButton("Appliquer");
applyButton.addActionListener(e -> applyMorphology());
JButton saveButton = new SaveButton();
JPanel controlPanel = createControlPanel(applyButton);
@@ -68,15 +66,11 @@ public class ComplexMorphologyView extends AbstractView implements IComplexMorph
rightLayout.setHorizontalGroup(
rightLayout.createParallelGroup(GroupLayout.Alignment.CENTER)
.addComponent(controlPanel)
.addComponent(saveButton)
);
.addComponent(controlPanel));
rightLayout.setVerticalGroup(
rightLayout.createSequentialGroup()
.addComponent(controlPanel)
.addComponent(saveButton)
);
.addComponent(controlPanel));
JPanel mainPanel = new JPanel();
@@ -87,13 +81,13 @@ public class ComplexMorphologyView extends AbstractView implements IComplexMorph
mainLayout.setHorizontalGroup(
mainLayout.createSequentialGroup()
.addComponent(modeTab)
.addComponent(modeTab, 400, 400, Short.MAX_VALUE)
.addComponent(rightPanel)
);
mainLayout.setVerticalGroup(
mainLayout.createParallelGroup(GroupLayout.Alignment.CENTER)
.addComponent(modeTab)
.addComponent(modeTab, 400, 400, Short.MAX_VALUE)
.addComponent(rightPanel)
);

View File

@@ -5,7 +5,6 @@ import jakarta.inject.Inject;
import presenters.outline.LinearOutlinePresenter;
import ui.abstractions.AbstractView;
import ui.abstractions.ILinearOutlineView;
import ui.implementation.components.controls.SaveButton;
import ui.implementation.components.image.TabbedImagePanel;
import javax.swing.*;
@@ -41,8 +40,6 @@ public class LinearOutlineView extends AbstractView implements ILinearOutlineVie
JButton applyButton = new JButton("Appliquer");
applyButton.addActionListener(e -> applyOutline());
JButton saveButton = new SaveButton();
JPanel controlPanel = createControlPanel(applyButton);
JPanel rightPanel = new JPanel();
@@ -54,15 +51,11 @@ public class LinearOutlineView extends AbstractView implements ILinearOutlineVie
rightLayout.setHorizontalGroup(
rightLayout.createParallelGroup(GroupLayout.Alignment.CENTER)
.addComponent(controlPanel)
.addComponent(saveButton)
);
.addComponent(controlPanel));
rightLayout.setVerticalGroup(
rightLayout.createSequentialGroup()
.addComponent(controlPanel)
.addComponent(saveButton)
);
.addComponent(controlPanel));
JPanel mainPanel = new JPanel();
@@ -73,13 +66,13 @@ public class LinearOutlineView extends AbstractView implements ILinearOutlineVie
mainLayout.setHorizontalGroup(
mainLayout.createSequentialGroup()
.addComponent(modeTab)
.addComponent(modeTab, 400, 400, Short.MAX_VALUE)
.addComponent(rightPanel)
);
mainLayout.setVerticalGroup(
mainLayout.createParallelGroup(GroupLayout.Alignment.CENTER)
.addComponent(modeTab)
.addComponent(modeTab, 400, 400, Short.MAX_VALUE)
.addComponent(rightPanel)
);

View File

@@ -5,7 +5,6 @@ import jakarta.inject.Inject;
import presenters.outline.NonLinearOutlinePresenter;
import ui.abstractions.AbstractView;
import ui.abstractions.INonLinearOutlineView;
import ui.implementation.components.controls.SaveButton;
import ui.implementation.components.image.TabbedImagePanel;
import javax.swing.*;
@@ -38,8 +37,6 @@ public class NonLinearOutlineView extends AbstractView implements INonLinearOutl
JButton applyButton = new JButton("Appliquer");
applyButton.addActionListener(e -> applyOutline());
JButton saveButton = new SaveButton();
JPanel controlPanel = createControlPanel(applyButton);
JPanel rightPanel = new JPanel();
@@ -51,15 +48,11 @@ public class NonLinearOutlineView extends AbstractView implements INonLinearOutl
rightLayout.setHorizontalGroup(
rightLayout.createParallelGroup(GroupLayout.Alignment.CENTER)
.addComponent(controlPanel)
.addComponent(saveButton)
);
.addComponent(controlPanel));
rightLayout.setVerticalGroup(
rightLayout.createSequentialGroup()
.addComponent(controlPanel)
.addComponent(saveButton)
);
.addComponent(controlPanel));
JPanel mainPanel = new JPanel();
@@ -70,13 +63,13 @@ public class NonLinearOutlineView extends AbstractView implements INonLinearOutl
mainLayout.setHorizontalGroup(
mainLayout.createSequentialGroup()
.addComponent(modeTab)
.addComponent(modeTab, 400, 400, Short.MAX_VALUE)
.addComponent(rightPanel)
);
mainLayout.setVerticalGroup(
mainLayout.createParallelGroup(GroupLayout.Alignment.CENTER)
.addComponent(modeTab)
.addComponent(modeTab, 400, 400, Short.MAX_VALUE)
.addComponent(rightPanel)
);

View File

@@ -5,7 +5,6 @@ import jakarta.inject.Inject;
import presenters.threshold.ThresholdingPresenter;
import ui.abstractions.AbstractView;
import ui.abstractions.IThresholdingView;
import ui.implementation.components.controls.SaveButton;
import ui.implementation.components.image.TabbedImagePanel;
import javax.swing.*;
@@ -84,7 +83,6 @@ public class ThresholdingView extends AbstractView implements IThresholdingView
);
});
JButton saveButton = new SaveButton();
JPanel controlPanel = createControlPanel();
@@ -97,15 +95,11 @@ public class ThresholdingView extends AbstractView implements IThresholdingView
rightLayout.setHorizontalGroup(
rightLayout.createParallelGroup(GroupLayout.Alignment.CENTER)
.addComponent(controlPanel)
.addComponent(saveButton)
);
.addComponent(controlPanel));
rightLayout.setVerticalGroup(
rightLayout.createSequentialGroup()
.addComponent(controlPanel)
.addComponent(saveButton)
);
.addComponent(controlPanel));
JPanel mainPanel = new JPanel();
@@ -116,13 +110,13 @@ public class ThresholdingView extends AbstractView implements IThresholdingView
mainLayout.setHorizontalGroup(
mainLayout.createSequentialGroup()
.addComponent(modeTab)
.addComponent(modeTab, 400, 400, Short.MAX_VALUE)
.addComponent(rightPanel)
);
mainLayout.setVerticalGroup(
mainLayout.createParallelGroup(GroupLayout.Alignment.CENTER)
.addComponent(modeTab)
.addComponent(modeTab, 400, 400, Short.MAX_VALUE)
.addComponent(rightPanel)
);