0% found this document useful (0 votes)
22 views

IED Code

The document outlines the implementation of a Java Swing GUI application for secure image encryption and decryption. It includes features such as password protection, drag-and-drop functionality for image selection, and the ability to save encrypted or decrypted images. Additionally, it supports theme toggling between dark and light modes and provides progress indicators during encryption and decryption processes.

Uploaded by

Pranav Shingne
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
22 views

IED Code

The document outlines the implementation of a Java Swing GUI application for secure image encryption and decryption. It includes features such as password protection, drag-and-drop functionality for image selection, and the ability to save encrypted or decrypted images. Additionally, it supports theme toggling between dark and light modes and provides progress indicators during encryption and decryption processes.

Uploaded by

Pranav Shingne
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 31

package IED;

import com.formdev.flatlaf.FlatDarkLaf;
import com.formdev.flatlaf.FlatIntelliJLaf;
import com.formdev.flatlaf.FlatLaf;
import javax.swing.Box; // For Box.createRigidArea
import java.io.IOException; // Ensure IOException is imported

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.BasicStroke;
import java.awt.Desktop;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.nio.file.Files;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.prefs.Preferences;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextPane;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.Timer;
import javax.swing.TransferHandler;
import javax.swing.UIManager;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import javax.crypto.spec.GCMParameterSpec; // Ensure
GCMParameterSpec is imported
import java.awt.datatransfer.DataFlavor; // Ensure DataFlavor is
imported
import java.awt.Cursor; // Ensure Cursor is imported
import java.awt.datatransfer.Transferable; // Ensure Transferable
is imported

public class ImageEncryptionGUI extends JFrame {

// UI components for encryption and decryption panels


private JPanel imagePanelEnc, imagePanelDec;
private JPasswordField passwordFieldEnc, passwordFieldDec;
private JButton selectEncImageButton, encryptButton,
saveEncButton;
private JButton selectDecImageButton, decryptButton,
saveDecButton;
private JButton resetButton, exitButton, themeToggleButton;
private JProgressBar encryptionProgress, decryptionProgress;
private JLabel statusBar;

// Data structures for managing selected files and previews


private ArrayList<File> selectedImages = new ArrayList<>();
private ArrayList<File> selectedEncryptedFiles = new
ArrayList<>();
private Map<File, JPanel> previewPanelMapEnc = new
HashMap<>();
private Map<File, JPanel> previewPanelMapDec = new
HashMap<>();
private Map<File, JPanel> rightPreviewPanelMapEnc = new
HashMap<>();
private Map<File, byte[]> encryptedDataMap = new HashMap<>();
private Map<File, byte[]> decryptedDataMap = new HashMap<>();

// AES encryption key length and preferences


private int aesKeyLength;
private Preferences prefs =
Preferences.userRoot().node("ImageEncryptionGUI");
private boolean isDarkMode;

// Labels for displaying encryption and decryption times


private JLabel encryptionTimeLabel, decryptionTimeLabel;

public ImageEncryptionGUI() {
setTitle("Secure Image Encryption Tool");
setSize(1200, 800);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setLayout(new BorderLayout(5, 5));
setResizable(true);

// Determine AES key length based on system capabilities


try {
int maxKeyLength =
Cipher.getMaxAllowedKeyLength("AES");
aesKeyLength = (maxKeyLength >= 256) ? 256 :
(maxKeyLength >= 192) ? 192 : 128;
} catch (Exception ex) {
aesKeyLength = 128;
}

// Load theme preference


isDarkMode = prefs.getBoolean("darkMode", false);

// Initialize top toolbar


JPanel topToolbar = new JPanel(new
FlowLayout(FlowLayout.LEFT, 10, 5));
themeToggleButton = new JButton();
resetButton = new JButton("🔄 Reset");
exitButton = new JButton("❌ Exit");
JButton aboutButton = new JButton("ℹ About");
updateThemeButton();
topToolbar.add(themeToggleButton);
topToolbar.add(resetButton);
topToolbar.add(exitButton);
topToolbar.add(aboutButton);
add(topToolbar, BorderLayout.NORTH);

// Add action listener for About button


aboutButton.addActionListener(e -> showAboutDialog());

// Initialize encryption and decryption panels


JPanel encryptionPanel = createEncryptionPanel();
JPanel decryptionPanel = createDecryptionPanel();

// Add panels to split pane


JSplitPane mainSplitPane = new
JSplitPane(JSplitPane.VERTICAL_SPLIT, encryptionPanel,
decryptionPanel);
mainSplitPane.setResizeWeight(0.5);
add(mainSplitPane, BorderLayout.CENTER);

// Initialize status bar


statusBar = new JLabel("Status: Ready");
encryptionTimeLabel = new JLabel("Encryption Time: N/A");
decryptionTimeLabel = new JLabel("Decryption Time: N/A");
JPanel statusPanel = new JPanel(new
FlowLayout(FlowLayout.LEFT));
statusPanel.add(statusBar);
statusPanel.add(encryptionTimeLabel);
statusPanel.add(decryptionTimeLabel);
add(statusPanel, BorderLayout.SOUTH);

// Add action listeners for buttons


addActionListeners();

// Enable drag-and-drop for encryption and decryption


panels
enableDragAndDrop(imagePanelEnc, selectedImages, false);
enableDragAndDrop(imagePanelDec, selectedEncryptedFiles,
true);

// Apply the selected theme


updateTheme();
}

// Create the encryption panel with its components


private JPanel createEncryptionPanel() {
JPanel panel = new JPanel(new BorderLayout());

panel.setBorder(BorderFactory.createTitledBorder("Encryption
Panel"));
panel.setMinimumSize(new Dimension(100, 200));

selectEncImageButton = new JButton("📂 Select Images");


encryptButton = new JButton("🔒 Encrypt");
saveEncButton = new JButton("💾 Save Encrypted");

passwordFieldEnc = new JPasswordField(15);


JCheckBox showPasswordEnc = new JCheckBox("👁 Show");
showPasswordEnc.addActionListener(e ->
togglePasswordVisibility(passwordFieldEnc, showPasswordEnc));

JPanel topPanel = new JPanel(new


FlowLayout(FlowLayout.LEFT));
topPanel.add(new JLabel("Password:"));
topPanel.add(passwordFieldEnc);
topPanel.add(showPasswordEnc);
topPanel.add(selectEncImageButton);
topPanel.add(encryptButton);
topPanel.add(saveEncButton);

imagePanelEnc = new JPanel(new FlowLayout(FlowLayout.LEFT,


10, 10));
JScrollPane scrollPane = new JScrollPane(imagePanelEnc);

scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCR
OLLBAR_ALWAYS);

scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLB
AR_AS_NEEDED);

encryptionProgress = new JProgressBar();


encryptionProgress.setStringPainted(true);
encryptionProgress.setForeground(Color.BLUE);

panel.add(topPanel, BorderLayout.NORTH);
panel.add(scrollPane, BorderLayout.CENTER);
panel.add(encryptionProgress, BorderLayout.SOUTH);

return panel;
}

// Create the decryption panel with its components


private JPanel createDecryptionPanel() {
JPanel panel = new JPanel(new BorderLayout());

panel.setBorder(BorderFactory.createTitledBorder("Decryption
Panel"));
panel.setMinimumSize(new Dimension(100, 200));

selectDecImageButton = new JButton("📂 Select Encrypted");


decryptButton = new JButton("🔓 Decrypt");
saveDecButton = new JButton("💾 Save Decrypted");

passwordFieldDec = new JPasswordField(15);


JCheckBox showPasswordDec = new JCheckBox("👁 Show");
showPasswordDec.addActionListener(e ->
togglePasswordVisibility(passwordFieldDec, showPasswordDec));

JPanel topPanel = new JPanel(new


FlowLayout(FlowLayout.LEFT));
topPanel.add(new JLabel("Password:"));
topPanel.add(passwordFieldDec);
topPanel.add(showPasswordDec);
topPanel.add(selectDecImageButton);
topPanel.add(decryptButton);
topPanel.add(saveDecButton);

imagePanelDec = new JPanel(new FlowLayout(FlowLayout.LEFT,


10, 10));
JScrollPane scrollPane = new JScrollPane(imagePanelDec);

scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCR
OLLBAR_ALWAYS);

scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLB
AR_AS_NEEDED);
decryptionProgress = new JProgressBar();
decryptionProgress.setStringPainted(true);
decryptionProgress.setForeground(Color.BLUE);

panel.add(topPanel, BorderLayout.NORTH);
panel.add(scrollPane, BorderLayout.CENTER);
panel.add(decryptionProgress, BorderLayout.SOUTH);

return panel;
}

// Add action listeners for buttons


private void addActionListeners() {
selectEncImageButton.addActionListener(e ->
selectImages(selectedImages, imagePanelEnc, false));
encryptButton.addActionListener(e -> {
if (selectedImages.isEmpty()) {
JOptionPane.showMessageDialog(this, "Please select
an image to encrypt.", "Error", JOptionPane.ERROR_MESSAGE);
return;
}
encryptImages();
});
selectDecImageButton.addActionListener(e ->
selectImages(selectedEncryptedFiles, imagePanelDec, true));
decryptButton.addActionListener(e -> {
if (selectedEncryptedFiles.isEmpty()) {
JOptionPane.showMessageDialog(this, "Please select
an image to decrypt.", "Error", JOptionPane.ERROR_MESSAGE);
return;
}
decryptImages();
});
saveEncButton.addActionListener(e -> {
if (selectedImages.isEmpty()) {
JOptionPane.showMessageDialog(this, "Please select
an image to save.", "Error", JOptionPane.ERROR_MESSAGE);
return;
}
saveEncryptedImages();
});
saveDecButton.addActionListener(e -> {
if (selectedEncryptedFiles.isEmpty()) {
JOptionPane.showMessageDialog(this, "Please select
an image to save.", "Error", JOptionPane.ERROR_MESSAGE);
return;
}
saveDecryptedImages();
});
themeToggleButton.addActionListener(e -> toggleTheme());
resetButton.addActionListener(e -> resetAll());
exitButton.addActionListener(e -> System.exit(0));
}
// Enable drag-and-drop functionality for a panel
private void enableDragAndDrop(JPanel panel, ArrayList<File>
fileList, boolean isDecryption) {
panel.setTransferHandler(new TransferHandler() {
@Override
public boolean canImport(TransferSupport support) {
return
support.isDataFlavorSupported(DataFlavor.javaFileListFlavor);
}

@Override
@SuppressWarnings("unchecked")
public boolean importData(TransferSupport support) {
if (!canImport(support)) return false;
try {
List<File> files = (List<File>)
support.getTransferable().getTransferData(DataFlavor.javaFileListF
lavor);
for (File file : files) {
if (isDecryption ?
isValidEncryptedFile(file) : isValidImageFile(file)) {
fileList.add(file);
addImageThumbnail(file, panel,
fileList, isDecryption);
}
}
return true;
} catch (Exception ex) {
ex.printStackTrace();
return false;
}
}
});
}

// Helper method: addPrefixIfNeeded returns a string with the


prefix added if not already present.
private String addPrefixIfNeeded(String prefix, String name) {
if (prefix.equalsIgnoreCase("Encrypted_")) {
if (name.toLowerCase().startsWith("encrypted_")) {
return "Encrypted_" +
name.substring("encrypted_".length());
}
}
if (prefix.equalsIgnoreCase("Decrypted_")) {
if (name.toLowerCase().startsWith("decrypted_")) { //
Corrected starts with to startsWith
return "Decrypted_" +
name.substring("decrypted_".length());
}
}
return prefix + name;
}
// Helper method to update the theme toggle button text.
private void updateThemeButton() {
themeToggleButton.setText(isDarkMode ? "🌙 Dark Mode" : "☀
Light Mode");
}

// Helper method to toggle password field visibility.


private void togglePasswordVisibility(JPasswordField
passwordField, JCheckBox checkBox) {
if (checkBox.isSelected()) {
passwordField.setEchoChar((char) 0);
} else {
passwordField.setEchoChar('•');
}
}

// Helper method to toggle between dark and light themes.


private void toggleTheme() {
isDarkMode = !isDarkMode;
prefs.putBoolean("darkMode", isDarkMode);
try {
if (isDarkMode) {
UIManager.setLookAndFeel(new FlatDarkLaf());
} else {
UIManager.setLookAndFeel(new FlatIntelliJLaf());
}
FlatLaf.updateUI();
SwingUtilities.updateComponentTreeUI(this);
this.invalidate();
this.validate();
this.repaint();
} catch (Exception ex) {
ex.printStackTrace();
}
updateThemeButton();
}

// Helper method to update the current theme.


private void updateTheme() {
try {
if (isDarkMode) {
UIManager.setLookAndFeel(new FlatDarkLaf());
} else {
UIManager.setLookAndFeel(new FlatIntelliJLaf());
}
FlatLaf.updateUI();
SwingUtilities.updateComponentTreeUI(this);
} catch (Exception ex) {
ex.printStackTrace();
}
}

// Helper method to animate a progress bar.


private void animateProgress(JProgressBar progressBar, int
targetValue) {
Timer timer = new Timer(15, new ActionListener() {
public void actionPerformed(ActionEvent e) {
int current = progressBar.getValue();
if (current < targetValue) {
progressBar.setValue(current + 5);
} else {
((Timer) e.getSource()).stop();
}
}
});
timer.start();
}

// Returns a JLabel displaying file name and size.


// Using HTML with a maximum width so that the text wraps
automatically if it is too long.
// Updated createFileInfoLabel method to wrap image name using
<html> tags
// Updated createFileInfoLabel to reduce thumbnail height from
the bottom
private JLabel createFileInfoLabel(File file, long sizeBytes)
{
String name = file.getName();
String sizeStr;
if (sizeBytes < 1024) {
sizeStr = sizeBytes + " bytes";
} else if (sizeBytes < 1024 * 1024) {
double sizeKB = sizeBytes / 1024.0;
sizeStr = String.format("%.1f KB", sizeKB);
} else {
double sizeMB = sizeBytes / (1024.0 * 1024.0);
sizeStr = String.format("%.1f MB", sizeMB);
}

// Dynamically calculate the line break length based on


thumbnail width
int thumbnailWidth = 200; // Width of the thumbnail in
pixels
int charPerLine = thumbnailWidth / 7; // Approximate
character width (7 pixels per character)
String formattedName = name.replaceAll("(.{" + charPerLine
+ "})", "$1<br/>");

// Keep consistent padding


String html = "<html><div style='text-align: center;
padding: 2px; width:" + thumbnailWidth + "px; word-wrap: break-
word; overflow-wrap: break-word;'>"
+ formattedName + "<br/>(" + sizeStr +
")</div></html>";
return new JLabel(html, SwingConstants.CENTER);
}
// Updated createColumnPanel method to ensure consistent
thumbnail width
private JPanel createColumnPanel(String headerText, Icon
imageIcon, Component extra) {
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
JLabel header = new JLabel(headerText,
SwingConstants.CENTER);
header.setFont(new Font("Arial", Font.BOLD, 16));
header.setAlignmentX(Component.CENTER_ALIGNMENT);
panel.add(header);
panel.add(Box.createRigidArea(new Dimension(0, 10))); //
Added gap below the header
if (imageIcon != null) {
JLabel imageLabel = new JLabel(imageIcon);
imageLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
panel.add(imageLabel);
}
if (extra != null) {
panel.add(Box.createRigidArea(new Dimension(0,
10))); // Added gap above the extra content
JPanel extraPanel = new JPanel(new
FlowLayout(FlowLayout.CENTER, 0, 0));
extraPanel.add(extra);
extraPanel.setAlignmentX(Component.CENTER_ALIGNMENT);
panel.add(extraPanel);
}
// Reduce bottom padding from 10 to 7
panel.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(Color.BLUE, 2), //
Outer border
BorderFactory.createEmptyBorder(10, 10, 7, 10) //
Inner padding
));
// Set preferred size to 220x220
panel.setPreferredSize(new Dimension(220, 220));
return panel;
}

// Method to show a popup with the image in its original size


// Updated showImagePreview method to display actual details
correctly
// Fix showImagePreview to display the correct size in the
image preview
private void showImagePreview(BufferedImage image, String
imageName, int imageIndex, List<BufferedImage> imageList,
List<String> imageNames) {
JDialog previewDialog = new JDialog(this, "Image Preview",
true);
previewDialog.setLayout(new BorderLayout());

// Create a custom panel to handle image rendering,


zooming, and dragging
class ImagePreviewPanel extends JPanel {
private BufferedImage image;
private double scale = 1.0; // Default scale
private boolean fitToWindow = true; // Fit to window
by default
private int offsetX = 0, offsetY = 0; // Drag offsets
private int dragStartX, dragStartY; // Drag start
positions

public ImagePreviewPanel(BufferedImage image) {


this.image = image;
fitToWindow(); // Automatically fit to window on
initialization

// Add mouse wheel listener for zooming


addMouseWheelListener(e -> {
if (e.getWheelRotation() < 0) {
zoom(1.1);
} else {
zoom(0.9);
}
});

// Add mouse listeners for dragging


addMouseListener(new java.awt.event.MouseAdapter()
{
@Override
public void
mousePressed(java.awt.event.MouseEvent e) {
dragStartX = e.getX();
dragStartY = e.getY();

setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); // Set
hand cursor
}

@Override
public void
mouseReleased(java.awt.event.MouseEvent e) {
setCursor(Cursor.getDefaultCursor()); //
Reset cursor
}
});

addMouseMotionListener(new
java.awt.event.MouseMotionAdapter() {
@Override
public void
mouseDragged(java.awt.event.MouseEvent e) {
offsetX += e.getX() - dragStartX;
offsetY += e.getY() - dragStartY;
dragStartX = e.getX();
dragStartY = e.getY();
repaint();
}
});
}

public void zoom(double factor) {


fitToWindow = false; // Disable fit-to-window mode
scale *= factor;
repaint();
}

public void fitToWindow() {


fitToWindow = true; // Enable fit-to-window mode
offsetX = 0;
offsetY = 0;
repaint();
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (image != null) {
Graphics2D g2d = (Graphics2D) g;

g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);

g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);

g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);

int drawWidth, drawHeight;


if (fitToWindow) {
// Scale image to fit the panel size
int availableWidth = getWidth();
int availableHeight = getHeight();
double scaleWidth = (double)
availableWidth / image.getWidth();
double scaleHeight = (double)
availableHeight / image.getHeight();
scale = Math.min(scaleWidth, scaleHeight);
}

drawWidth = (int) (image.getWidth() * scale);


drawHeight = (int) (image.getHeight() *
scale);
int x = (getWidth() - drawWidth) / 2 +
offsetX;
int y = (getHeight() - drawHeight) / 2 +
offsetY;

g2d.drawImage(image, x, y, drawWidth,
drawHeight, null);
}
}
}

ImagePreviewPanel imagePanel = new


ImagePreviewPanel(image);
JScrollPane scrollPane = new JScrollPane(imagePanel);
previewDialog.add(scrollPane, BorderLayout.CENTER);

// Add image name and resolution (size label removed)


JPanel infoPanel = new JPanel(new GridLayout(3, 1)); //
Adjusted grid layout to 3 rows
JLabel nameLabel = new JLabel("Name: " + imageName,
SwingConstants.CENTER);
JLabel resolutionLabel = new JLabel("Resolution: " +
image.getWidth() + "x" + image.getHeight(),
SwingConstants.CENTER);

infoPanel.add(nameLabel);
infoPanel.add(resolutionLabel);
previewDialog.add(infoPanel, BorderLayout.NORTH);

// Add navigation and zoom controls


JPanel controlPanel = new JPanel(new BorderLayout());
JButton previousButton = new JButton("Previous");
JButton nextButton = new JButton("Next");
JPanel zoomPanel = new JPanel();
JButton zoomInButton = new JButton("Zoom In");
JButton zoomOutButton = new JButton("Zoom Out");
JButton fitToWindowButton = new JButton("Fit to Window");

zoomInButton.addActionListener(e -> imagePanel.zoom(1.1));


zoomOutButton.addActionListener(e ->
imagePanel.zoom(0.9));
fitToWindowButton.addActionListener(e ->
imagePanel.fitToWindow());

zoomPanel.add(zoomInButton);
zoomPanel.add(zoomOutButton);
zoomPanel.add(fitToWindowButton);

previousButton.addActionListener(e -> {
if (imageIndex > 0) {
previewDialog.dispose();
showImagePreview(imageList.get(imageIndex - 1),
imageNames.get(imageIndex - 1), imageIndex - 1, imageList,
imageNames);
}
});

nextButton.addActionListener(e -> {
if (imageIndex < imageList.size() - 1) {
previewDialog.dispose();
showImagePreview(imageList.get(imageIndex + 1),
imageNames.get(imageIndex + 1), imageIndex + 1, imageList,
imageNames);
}
});

controlPanel.add(previousButton, BorderLayout.WEST);
controlPanel.add(zoomPanel, BorderLayout.CENTER);
controlPanel.add(nextButton, BorderLayout.EAST);
previewDialog.add(controlPanel, BorderLayout.SOUTH);

// Set initial size and location


previewDialog.setSize(800, 600);
previewDialog.setLocationRelativeTo(this);
previewDialog.setVisible(true);
}

// Updated JThrobber to ensure continuous rotation


private static class JThrobber extends JComponent {
private int angle = 0;
private Timer timer;

public JThrobber() {
setPreferredSize(new Dimension(40, 40));
start(); // Ensure the timer starts when the throbber
is created
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);

int size = Math.min(getWidth(), getHeight()) - 10;


int x = (getWidth() - size) / 2;
int y = (getHeight() - size) / 2;

g2.setStroke(new BasicStroke(3));
g2.setColor(Color.BLUE);
g2.drawArc(x, y, size, size, angle, 120);
g2.drawArc(x, y, size, size, angle + 180, 120);
g2.dispose();
}

public void start() {


if (timer == null || !timer.isRunning()) {
timer = new Timer(50, e -> {
angle = (angle + 12) % 360;
repaint();
});
timer.start();
}
}

public void stop() {


if (timer != null && timer.isRunning()) {
timer.stop();
}
}
}

// Updated selectImages method to ensure JThrobber animates


correctly
private void selectImages(ArrayList<File> fileList, JPanel
imagePanel, boolean isDecryption) {
JFileChooser chooser = new JFileChooser();
chooser.setMultiSelectionEnabled(true);
if (fileList == selectedEncryptedFiles) {
chooser.setFileFilter(new
FileNameExtensionFilter("Encrypted Files (.enc)", "enc"));
} else {
chooser.setFileFilter(new
FileNameExtensionFilter("Image Files", "jpg", "png", "bmp",
"jpeg"));
}

if (chooser.showOpenDialog(this) ==
JFileChooser.APPROVE_OPTION) {
JThrobber throbber = new JThrobber();
JDialog loadingDialog = createLoadingDialog("Loading
images...", throbber);

SwingWorker<Void, File> worker = new SwingWorker<Void,


File>() {
@Override
protected Void doInBackground() {
File[] files = chooser.getSelectedFiles();
for (File file : files) {
fileList.add(file);
publish(file); // Publish each file to
update the UI incrementally
}
return null;
}

@Override
protected void process(List<File> chunks) {
for (File file : chunks) {
addImageThumbnail(file, imagePanel,
fileList, isDecryption);
}
}

@Override
protected void done() {
SwingUtilities.invokeLater(() -> {
loadingDialog.dispose();
throbber.stop();
});
}
};

// Start the worker and ensure the throbber animates


continuously
throbber.start();
worker.execute();
}
}

// Adds a thumbnail container panel for the selected image.


// For encryption panel (isDecryption == false), the left
panel shows original image info,
private void addImageThumbnail(File file, JPanel imagePanel,
ArrayList<File> fileList, boolean isDecryption) {
String leftHeader;
BufferedImage origImg = null;

if (isDecryption) {
leftHeader = "Encrypted Image";
try {
byte[] fileBytes =
Files.readAllBytes(file.toPath());
origImg = encryptedBytesToImage(fileBytes, 100,
100); // Set thumbnail size to 100x100
} catch (Exception ex) {
origImg = null;
}
} else {
leftHeader = "Original Image";
try {
origImg = ImageIO.read(file); // Load full-quality
image
} catch (Exception ex) {
origImg = null;
}
}

// Use high-quality scaling for thumbnail creation


ImageIcon thumbnailIcon = null;
if (origImg != null) {
Image scaledImage = origImg.getScaledInstance(100,
100, Image.SCALE_SMOOTH); // Resize to 100x100
thumbnailIcon = new ImageIcon(scaledImage);
}

JPanel leftPanel = createColumnPanel(leftHeader,


thumbnailIcon, createFileInfoLabel(file, file.length()));

// Set tooltip to show details on hover


String tooltipText = String.format("<html>Name:
%s<br>Size: %.1f KB<br>Resolution: %dx%d</html>",
file.getName(), file.length() / 1024.0, origImg !=
null ? origImg.getWidth() : 0, origImg != null ?
origImg.getHeight() : 0);
leftPanel.setToolTipText(tooltipText);

JPanel rightPanel = new JPanel(new BorderLayout());


JLabel placeholder = new JLabel(isDecryption ? "Decrypted
Preview not generated" : "Encrypted Preview not generated",
SwingConstants.CENTER);
placeholder.setFont(new Font("Arial", Font.ITALIC, 14));
rightPanel.add(placeholder, BorderLayout.CENTER);

rightPanel.setBorder(BorderFactory.createLineBorder(Color.BLUE,
1));
rightPanel.setPreferredSize(new Dimension(100, 100)); //
Match thumbnail size

if (!isDecryption) {
rightPreviewPanelMapEnc.put(file, rightPanel);
}

JPanel sideBySide = new JPanel(new GridLayout(1, 2, 5,


5));
sideBySide.add(leftPanel);
sideBySide.add(rightPanel);
sideBySide.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(Color.BLUE, 2),
BorderFactory.createEmptyBorder(5, 5, 5, 5)
));

JPanel container = new JPanel(new BorderLayout());


container.add(sideBySide, BorderLayout.CENTER);
JPanel topPanel = new JPanel(new
FlowLayout(FlowLayout.RIGHT, 0, 0));
topPanel.setOpaque(false);
JButton removeButton = new JButton("❌");
removeButton.addActionListener(e -> {
imagePanel.remove(container);
imagePanel.revalidate();
imagePanel.repaint();
fileList.remove(file);
if (isDecryption) {
previewPanelMapDec.remove(file);
} else {
previewPanelMapEnc.remove(file);
rightPreviewPanelMapEnc.remove(file);
}
});
topPanel.add(removeButton);
container.add(topPanel, BorderLayout.NORTH);

if (isDecryption) {
previewPanelMapDec.put(file, container);
} else {
previewPanelMapEnc.put(file, container);
}

// Add double-click listener to show the actual image in


the preview
leftPanel.addMouseListener(new
java.awt.event.MouseAdapter() {
@Override
public void mouseClicked(java.awt.event.MouseEvent e)
{
if (e.getClickCount() == 2) { // Double-click
detected
if (file.exists() && file.isFile()) {
try {
BufferedImage fullImage =
ImageIO.read(file); // Load full-quality image
showImagePreview(fullImage,
file.getName(), selectedImages.indexOf(file),
selectedImages.stream().map(f -> {
try {
return ImageIO.read(f);
} catch (IOException ex) {
return null;
}
}).toList(),
selectedImages.stream().map(File::getName).toList()); // Show
full-quality preview
} catch (IOException ex) {

JOptionPane.showMessageDialog(ImageEncryptionGUI.this,
"Error loading image: " +
ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
}
} else {

JOptionPane.showMessageDialog(ImageEncryptionGUI.this,
"File not found or unsupported
format.", "Error", JOptionPane.ERROR_MESSAGE);
}
}
}
});

imagePanel.add(container);
imagePanel.revalidate();
imagePanel.repaint();
}

// --- AES Encryption/Decryption using PBKDF2 ---


private SecretKeySpec getSecretKeyPBKDF2(String password,
byte[] salt) throws Exception {
int iterationCount = 65536;
int keyLength = aesKeyLength;
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(),
salt, iterationCount, keyLength);
SecretKeyFactory factory =
SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
byte[] keyBytes =
factory.generateSecret(spec).getEncoded();
return new SecretKeySpec(keyBytes, "AES");
}

// Fix encryptFile method for AES/GCM/NoPadding


private byte[] encryptFile(byte[] fileData, String password)
throws Exception {
byte[] salt = new byte[16];
SecureRandom sr = new SecureRandom();
sr.nextBytes(salt);
SecretKeySpec secretKey = getSecretKeyPBKDF2(password,
salt);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
byte[] iv = new byte[12];
sr.nextBytes(iv);
GCMParameterSpec gcmSpec = new GCMParameterSpec(128,
iv); // Use 128-bit authentication tag
cipher.init(Cipher.ENCRYPT_MODE, secretKey, gcmSpec);
byte[] encrypted = cipher.doFinal(fileData);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bos.write(salt);
bos.write(iv);
bos.write(encrypted);
return bos.toByteArray();
}

// Fix decryptFile method for AES/GCM/NoPadding


private byte[] decryptFile(byte[] encryptedData, String
password) throws Exception {
if (encryptedData.length < 28) { // Validate minimum
length (16 bytes salt + 12 bytes IV)
throw new Exception("Invalid encrypted data length");
}
byte[] salt = Arrays.copyOfRange(encryptedData, 0, 16);
byte[] iv = Arrays.copyOfRange(encryptedData, 16, 28);
byte[] actualData = Arrays.copyOfRange(encryptedData, 28,
encryptedData.length);
SecretKeySpec secretKey = getSecretKeyPBKDF2(password,
salt);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec gcmSpec = new GCMParameterSpec(128,
iv); // Use 128-bit authentication tag
cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmSpec);
return cipher.doFinal(actualData);
}
// --- End of AES methods ---
// Updates only the right panel (encrypted preview) in the
encryption container,
// leaving the left panel (original image info) intact.
private void updateEncryptionThumbnails() {
int thumbSize = 100;
for (File file : selectedImages) {
byte[] encryptedBytes = encryptedDataMap.get(file);
if (encryptedBytes != null) {
BufferedImage previewImg =
encryptedBytesToImage(encryptedBytes, thumbSize, thumbSize);
String encName = addPrefixIfNeeded("Encrypted_",
file.getName());
File dummyEncFile = new File(encName);
JLabel infoLabel =
createFileInfoLabel(dummyEncFile, encryptedBytes.length);
JPanel newPreview = createColumnPanel("Encrypted
Image", new ImageIcon(previewImg), infoLabel);
// Update only the right panel.
JPanel rightPanel =
rightPreviewPanelMapEnc.get(file);
if (rightPanel != null) {
rightPanel.removeAll();
rightPanel.setLayout(new BorderLayout());
rightPanel.add(newPreview,
BorderLayout.CENTER);
rightPanel.revalidate();
rightPanel.repaint();
}
}
}
}

// Converts a byte array to a grayscale image.


private BufferedImage encryptedBytesToImage(byte[] data, int
width, int height) {
BufferedImage img = new BufferedImage(width, height,
BufferedImage.TYPE_BYTE_GRAY);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int idx = (y * width + x) % data.length;
int gray = data[idx] & 0xFF;
int rgb = (gray << 16) | (gray << 8) | gray;
img.setRGB(x, y, rgb);
}
}
return img;
}

// Measure and display encryption time


private void encryptImages() {
if (selectedImages.isEmpty()) return;

String password = new


String(passwordFieldEnc.getPassword());
if (password.isEmpty()) {
JOptionPane.showMessageDialog(this, "Please Enter
Password", "Error", JOptionPane.ERROR_MESSAGE);
return;
}

long startTime = System.nanoTime(); // Start time


JThrobber throbber = new JThrobber();
JDialog loadingDialog =
createLoadingDialog("Encrypting...", throbber);
encryptionProgress.setValue(0);

SwingWorker<Void, Integer> worker = new SwingWorker<Void,


Integer>() {
private int totalFiles = selectedImages.size();
private int processedFiles = 0;

@Override
protected Void doInBackground() {
for (File file : selectedImages) {
try {
byte[] fileData =
Files.readAllBytes(file.toPath());
byte[] encryptedData =
encryptFile(fileData, password);
encryptedDataMap.put(file, encryptedData);
processedFiles++;
publish((int) ((processedFiles / (double)
totalFiles) * 100));
} catch (Exception ex) {
SwingUtilities.invokeLater(() ->

JOptionPane.showMessageDialog(ImageEncryptionGUI.this,
"Error encrypting " +
file.getName() + ": " + ex.getMessage(),
"Encryption Error",
JOptionPane.ERROR_MESSAGE)
);
}
}
return null;
}

@Override
protected void process(List<Integer> chunks) {

encryptionProgress.setValue(chunks.get(chunks.size() - 1));
}

@Override
protected void done() {
long endTime = System.nanoTime(); // End time
long duration = (endTime - startTime) / 1_000_000;
// Convert to milliseconds
encryptionTimeLabel.setText("Encryption Time: " +
duration + " ms");
loadingDialog.dispose();
throbber.stop();
updateEncryptionThumbnails();
statusBar.setText("Status: Encryption complete");
}
};
worker.execute();
}

// Measure and display decryption time


private void decryptImages() {
if (selectedEncryptedFiles.isEmpty()) return;

String password = new


String(passwordFieldDec.getPassword());
if (password.isEmpty()) {
JOptionPane.showMessageDialog(this, "Please Enter
Password", "Error", JOptionPane.ERROR_MESSAGE);
return;
}

long startTime = System.nanoTime(); // Start time


JThrobber throbber = new JThrobber();
JDialog loadingDialog =
createLoadingDialog("Decrypting...", throbber);
decryptionProgress.setValue(0);

SwingWorker<Void, DecryptedResult> worker = new


SwingWorker<Void, DecryptedResult>() {
@Override
protected Void doInBackground() {
int count = selectedEncryptedFiles.size();
int index = 0;

for (File file : selectedEncryptedFiles) {


try {
byte[] encryptedData =
Files.readAllBytes(file.toPath());
byte[] decryptedData =
decryptFile(encryptedData, password);

// Validate if decrypted data is a valid


image
BufferedImage decryptedImg =
ImageIO.read(new ByteArrayInputStream(decryptedData));
if (decryptedImg == null) {
throw new Exception("Decrypted data is
not a valid image");
}

Image scaled =
decryptedImg.getScaledInstance(100, 100, Image.SCALE_SMOOTH);
BufferedImage scaledBuffered = new
BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);

scaledBuffered.getGraphics().drawImage(scaled, 0, 0, null);

publish(new DecryptedResult(file,
decryptedData, scaledBuffered));
setProgress((int) ((++index / (double)
count) * 100));
} catch (Exception ex) {
SwingUtilities.invokeLater(() ->

JOptionPane.showMessageDialog(ImageEncryptionGUI.this,
"Error decrypting " +
file.getName() + ": " + ex.getMessage(),
"Decryption Error",
JOptionPane.ERROR_MESSAGE)
);
}
}
return null;
}

@Override
protected void process(List<DecryptedResult> chunks) {
for (DecryptedResult result : chunks) {
JPanel container =
previewPanelMapDec.get(result.file);
if (container != null) {
// Create a new right-side thumbnail for
the decrypted image
String decName =
addPrefixIfNeeded("Decrypted_", result.file.getName());
File dummyDecFile = new File(decName);
JPanel newRightPanel =
createColumnPanel("Decrypted Image",
new
ImageIcon(result.decryptedImage),
createFileInfoLabel(dummyDecFile,
result.decryptedData.length));

// Update the right-side thumbnail in the


container
JPanel sideBySide = (JPanel)
container.getComponent(0);
sideBySide.remove(1); // Remove the
placeholder or old right panel
sideBySide.add(newRightPanel, 1); // Add
the new right panel
sideBySide.revalidate();
sideBySide.repaint();
}
decryptedDataMap.put(result.file,
result.decryptedData);
}
decryptionProgress.setValue(getProgress());
}

@Override
protected void done() {
long endTime = System.nanoTime(); // End time
long duration = (endTime - startTime) / 1_000_000;
// Convert to milliseconds
decryptionTimeLabel.setText("Decryption Time: " +
duration + " ms");
loadingDialog.dispose();
throbber.stop();
statusBar.setText("Status: Decryption complete");
}
};

worker.addPropertyChangeListener(evt -> {
if ("progress".equals(evt.getPropertyName())) {
decryptionProgress.setValue(worker.getProgress());
}
});
worker.execute();
}

// Updated saveEncryptedImages method with loading indicator


private void saveEncryptedImages() {
if (selectedImages.isEmpty()) {
JOptionPane.showMessageDialog(this, "Please select an
image to save.", "Error", JOptionPane.ERROR_MESSAGE);
return;
}

// Check if any image has been encrypted


boolean hasEncryptedImages =
selectedImages.stream().anyMatch(encryptedDataMap::containsKey);
if (!hasEncryptedImages) {
JOptionPane.showMessageDialog(this, "Please encrypt
the images before saving.", "Error", JOptionPane.ERROR_MESSAGE);
return;
}

JThrobber throbber = new JThrobber();


JDialog loadingDialog = createLoadingDialog("Saving
encrypted images...", throbber);

SwingWorker<Void, Void> worker = new SwingWorker<Void,


Void>() {
@Override
protected Void doInBackground() {
JFileChooser chooser = new JFileChooser();

chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
if
(chooser.showSaveDialog(ImageEncryptionGUI.this) ==
JFileChooser.APPROVE_OPTION) {
File dir = chooser.getSelectedFile();
for (File file : selectedImages) {
byte[] encryptedData =
encryptedDataMap.get(file);
if (encryptedData != null) {
String encName =
addPrefixIfNeeded("Encrypted_", file.getName());
File outFile = new File(dir, encName +
".enc");
try (FileOutputStream fos = new
FileOutputStream(outFile)) {
fos.write(encryptedData);
} catch (Exception ex) {
SwingUtilities.invokeLater(() ->

JOptionPane.showMessageDialog(ImageEncryptionGUI.this,
"Error saving encrypted
file for " + file.getName())
);
}
}
}
}
return null;
}

@Override
protected void done() {
loadingDialog.dispose();
throbber.stop();
SwingUtilities.invokeLater(() ->

JOptionPane.showMessageDialog(ImageEncryptionGUI.this, "Encrypted
images saved successfully.")
);
}
};
worker.execute();
}

// Updated saveDecryptedImages method with loading indicator


private void saveDecryptedImages() {
if (selectedEncryptedFiles.isEmpty()) {
JOptionPane.showMessageDialog(this, "Please select an
image to save.", "Error", JOptionPane.ERROR_MESSAGE);
return;
}

// Check if any image has been decrypted


boolean hasDecryptedImages =
selectedEncryptedFiles.stream().anyMatch(decryptedDataMap::contain
sKey);
if (!hasDecryptedImages) {
JOptionPane.showMessageDialog(this, "Please decrypt
the images before saving.", "Error", JOptionPane.ERROR_MESSAGE);
return;
}

JThrobber throbber = new JThrobber();


JDialog loadingDialog = createLoadingDialog("Saving
decrypted images...", throbber);

SwingWorker<Void, Void> worker = new SwingWorker<Void,


Void>() {
@Override
protected Void doInBackground() {
JFileChooser chooser = new JFileChooser();

chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
if
(chooser.showSaveDialog(ImageEncryptionGUI.this) ==
JFileChooser.APPROVE_OPTION) {
File dir = chooser.getSelectedFile();
for (File file : selectedEncryptedFiles) {
byte[] decryptedData =
decryptedDataMap.get(file);
if (decryptedData != null) {
BufferedImage decryptedImg = null;
try {
decryptedImg = ImageIO.read(new
ByteArrayInputStream(decryptedData));
} catch (Exception ex) {}
String originalName = file.getName();
if
(originalName.toLowerCase().startsWith("encrypted_")) {
originalName =
originalName.substring("encrypted_".length());
}
if
(originalName.toLowerCase().endsWith(".enc")) {
originalName =
originalName.substring(0, originalName.length() - 4);
}
String saveName =
addPrefixIfNeeded("Decrypted_", originalName);
if (decryptedImg != null) {
File outFile = new File(dir,
saveName);
try {
ImageIO.write(decryptedImg,
"png", outFile);
} catch (Exception ex) {
SwingUtilities.invokeLater(()
->

JOptionPane.showMessageDialog(ImageEncryptionGUI.this,
"Error saving
decrypted file for " + file.getName())
);
}
} else {
File outFile = new File(dir,
saveName + ".bin");
try (FileOutputStream fos = new
FileOutputStream(outFile)) {
fos.write(decryptedData);
} catch (Exception ex) {
SwingUtilities.invokeLater(()
->

JOptionPane.showMessageDialog(ImageEncryptionGUI.this,
"Error saving
decrypted file for " + file.getName())
);
}
}
}
}
}
return null;
}

@Override
protected void done() {
loadingDialog.dispose();
throbber.stop();
SwingUtilities.invokeLater(() ->

JOptionPane.showMessageDialog(ImageEncryptionGUI.this, "Decrypted
images saved successfully.")
);
}
};
worker.execute();
}

// Resets the application state.


private void resetAll() {
selectedImages.clear();
selectedEncryptedFiles.clear();
encryptedDataMap.clear();
decryptedDataMap.clear();
previewPanelMapEnc.clear();
previewPanelMapDec.clear();
rightPreviewPanelMapEnc.clear();
imagePanelEnc.removeAll();
imagePanelDec.removeAll();
imagePanelEnc.revalidate();
imagePanelEnc.repaint();
imagePanelDec.revalidate();
imagePanelDec.repaint();
statusBar.setText("Status: Reset complete.");
}

// Helper inner class for decryption results.


private static class DecryptedResult {
File file;
byte[] decryptedData;
BufferedImage decryptedImage;
DecryptedResult(File file, byte[] decryptedData,
BufferedImage decryptedImage) {
this.file = file;
this.decryptedData = decryptedData;
this.decryptedImage = decryptedImage;
}
}

// Helper method to create a loading dialog with a JThrobber


private JDialog createLoadingDialog(String title, JThrobber
throbber) {
JDialog dialog = new JDialog(this, title, false);
JPanel panel = new JPanel(new BorderLayout());
panel.add(throbber, BorderLayout.CENTER);
panel.add(new JLabel(title, SwingConstants.CENTER),
BorderLayout.SOUTH);
dialog.add(panel);
dialog.setSize(200, 100);
dialog.setLocationRelativeTo(this);
dialog.setVisible(true);
return dialog;
}

// Added createTextPane method to create a JTextPane with


centered text
public JTextPane createTextPane(String text) {
JTextPane textPane = new JTextPane();
textPane.setText(text);
StyledDocument doc = textPane.getStyledDocument();
SimpleAttributeSet center = new SimpleAttributeSet();
StyleConstants.setAlignment(center,
StyleConstants.ALIGN_CENTER);
doc.setParagraphAttributes(0, doc.getLength(), center,
false);
return textPane;
}

// Updated ImagePanel class (removed duplicate definition and


fixed constructor)
class ImagePanel extends JPanel {
private BufferedImage image;
private double scale = 1.0; // Default zoom scale
private boolean fitToWindow = false; // Fit-to-window mode
flag
// Set default preview image dimensions to 552x667
private final int DEFAULT_WIDTH = 552;
private final int DEFAULT_HEIGHT = 667;

public ImagePanel(BufferedImage image) {


this.image = image;
setPreferredSize(new Dimension(DEFAULT_WIDTH,
DEFAULT_HEIGHT));
addMouseWheelListener(e -> {
if (e.getWheelRotation() < 0) {
zoom(1.2);
} else {
zoom(1 / 1.2);
}
});
}

// Zoom method disables fit-to-window mode.


public void zoom(double factor) {
fitToWindow = false;
scale *= factor;
repaint();
}

// Enable fit-to-window mode.


public void fitToWindowMode() {
fitToWindow = true;
repaint();
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (image != null) {
int drawWidth, drawHeight;
if (fitToWindow) {
// Scale image to panel size.
drawWidth = getWidth();
drawHeight = getHeight();
} else {
drawWidth = (int) (DEFAULT_WIDTH * scale);
drawHeight = (int) (DEFAULT_HEIGHT * scale);
}
int x = (getWidth() - drawWidth) / 2;
int y = (getHeight() - drawHeight) / 2; // Fixed
typo: replaced drawHeight() with drawHeight
Graphics2D g2 = (Graphics2D) g;
// Use high-quality rendering hints for best image
quality
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);

g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.drawImage(image, x, y, drawWidth, drawHeight,
this);
}
}
}

// Method to open an image file in the default image viewer.


private void openImageInDefaultViewer(File imageFile) {
if (Desktop.isDesktopSupported()) {
Desktop desktop = Desktop.getDesktop();
try {
desktop.open(imageFile);
} catch (IOException e) {
JOptionPane.showMessageDialog(this, "Error opening
image: " + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
}
} else {
JOptionPane.showMessageDialog(this, "Desktop is not
supported on this system.", "Error", JOptionPane.ERROR_MESSAGE);
}
}

// Method to show the About dialog


private void showAboutDialog() {
JDialog aboutDialog = new JDialog(this, "About", true);
aboutDialog.setLayout(new BorderLayout());
aboutDialog.setSize(400, 300);
aboutDialog.setLocationRelativeTo(this);

JTextPane aboutText = new JTextPane();


aboutText.setContentType("text/html");
aboutText.setText("""
<html>
<h2>Secure Image Encryption Tool</h2>
<p>This tool allows users to securely encrypt and
decrypt images using AES encryption.</p>
<h3>User Manual:</h3>
<ul>
<li><b>Select Images:</b> Choose images to encrypt
or decrypt.</li>
<li><b>Encrypt:</b> Encrypt selected images with a
password.</li>
<li><b>Decrypt:</b> Decrypt encrypted images with
the correct password.</li>
<li><b>Save:</b> Save encrypted or decrypted
images to your system.</li>
<li><b>Preview:</b> Double-click thumbnails to
preview images.</li>
</ul>
<p>Developed by: Pranav Shingne</p>
</html>
""");
aboutText.setEditable(false);
aboutText.setBorder(BorderFactory.createEmptyBorder(10,
10, 10, 10));

JScrollPane scrollPane = new JScrollPane(aboutText);


aboutDialog.add(scrollPane, BorderLayout.CENTER);

JButton closeButton = new JButton("Close");


closeButton.addActionListener(e -> aboutDialog.dispose());
JPanel buttonPanel = new JPanel();
buttonPanel.add(closeButton);
aboutDialog.add(buttonPanel, BorderLayout.SOUTH);

aboutDialog.setVisible(true);
}

// Helper method to check if a file is a valid image


private boolean isValidImageFile(File file) {
String[] validExtensions = {"jpg", "jpeg", "png", "bmp"};
String fileName = file.getName().toLowerCase();
for (String ext : validExtensions) {
if (fileName.endsWith("." + ext)) {
return true;
}
}
return false;
}

// Helper method to check if a file is a valid encrypted file


private boolean isValidEncryptedFile(File file) {
return file.getName().toLowerCase().endsWith(".enc");
}

public static void main(String[] args) {


SwingUtilities.invokeLater(new Runnable(){
public void run(){
ImageEncryptionGUI gui = new ImageEncryptionGUI();
gui.setVisible(true);
}
});
}
}

You might also like