Add files via upload
This commit is contained in:
parent
a3b8a1db13
commit
d1b23cf186
5 changed files with 829 additions and 0 deletions
185
src/GameOfLifeProcessor.java
Normal file
185
src/GameOfLifeProcessor.java
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
// GameOfLifeProcessor.java
|
||||||
|
package jfxlabproj.gameoflife;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import javafx.animation.KeyFrame;
|
||||||
|
import javafx.animation.Timeline;
|
||||||
|
import javafx.scene.image.Image;
|
||||||
|
import javafx.scene.image.ImageView;
|
||||||
|
import javafx.scene.image.PixelReader;
|
||||||
|
import javafx.scene.image.WritableImage;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.util.Duration;
|
||||||
|
|
||||||
|
public class GameOfLifeProcessor {
|
||||||
|
|
||||||
|
private static Timeline timeline;
|
||||||
|
|
||||||
|
public static void startGameOfLife(ImageView imageView) {
|
||||||
|
if (imageView.getImage() == null) return;
|
||||||
|
|
||||||
|
// Convert to black and white with chunks
|
||||||
|
Image source = imageView.getImage();
|
||||||
|
int width = 640;
|
||||||
|
int height = (int) (source.getHeight() * (640.0 / source.getWidth()));
|
||||||
|
int chunkSize = 8; // Reduced chunk size for better detail
|
||||||
|
WritableImage bwImage = new WritableImage(width, height);
|
||||||
|
PixelReader reader = source.getPixelReader();
|
||||||
|
|
||||||
|
// Calculate average brightness and variance of the entire image
|
||||||
|
double totalBrightness = 0;
|
||||||
|
double[] brightnesses = new double[width * height];
|
||||||
|
int pixelCount = 0;
|
||||||
|
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
Color color = reader.getColor(
|
||||||
|
(int) ((x * source.getWidth()) / 640.0),
|
||||||
|
(int) ((y * source.getWidth()) / 640.0)
|
||||||
|
);
|
||||||
|
double brightness = color.getBrightness();
|
||||||
|
brightnesses[pixelCount] = brightness;
|
||||||
|
totalBrightness += brightness;
|
||||||
|
pixelCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double averageBrightness = totalBrightness / pixelCount;
|
||||||
|
|
||||||
|
// Calculate variance
|
||||||
|
double variance = 0;
|
||||||
|
for (int i = 0; i < pixelCount; i++) {
|
||||||
|
variance += Math.pow(brightnesses[i] - averageBrightness, 2);
|
||||||
|
}
|
||||||
|
variance /= pixelCount;
|
||||||
|
|
||||||
|
// Adjust threshold based on variance
|
||||||
|
double varianceWeight = Math.min(1.0, Math.max(0.1, variance * 10));
|
||||||
|
double threshold = averageBrightness * varianceWeight;
|
||||||
|
|
||||||
|
for (int y = 0; y < height; y += chunkSize) {
|
||||||
|
for (int x = 0; x < width; x += chunkSize) {
|
||||||
|
double chunkBrightness = 0;
|
||||||
|
int validPixels = 0;
|
||||||
|
|
||||||
|
// Calculate average brightness for the chunk
|
||||||
|
for (int cy = 0; cy < chunkSize && (y + cy) < height; cy++) {
|
||||||
|
for (int cx = 0; cx < chunkSize && (x + cx) < width; cx++) {
|
||||||
|
Color color = reader.getColor(
|
||||||
|
(int) (((x + cx) * source.getWidth()) / 640.0),
|
||||||
|
(int) (((y + cy) * source.getWidth()) / 640.0)
|
||||||
|
);
|
||||||
|
chunkBrightness += color.getBrightness();
|
||||||
|
validPixels++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double avgChunkBrightness = chunkBrightness / validPixels;
|
||||||
|
Color chunkColor = (avgChunkBrightness < threshold)
|
||||||
|
? Color.BLACK
|
||||||
|
: Color.WHITE;
|
||||||
|
|
||||||
|
// Set the color for the entire chunk
|
||||||
|
for (int cy = 0; cy < chunkSize && (y + cy) < height; cy++) {
|
||||||
|
for (int cx = 0; cx < chunkSize && (x + cx) < width; cx++) {
|
||||||
|
bwImage
|
||||||
|
.getPixelWriter()
|
||||||
|
.setColor(x + cx, y + cy, chunkColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AtomicReference<WritableImage> bwImageRef = new AtomicReference<>(
|
||||||
|
bwImage
|
||||||
|
);
|
||||||
|
imageView.setImage(bwImageRef.get());
|
||||||
|
|
||||||
|
// Start Game of Life
|
||||||
|
timeline = new Timeline(
|
||||||
|
new KeyFrame(Duration.millis(200), event -> {
|
||||||
|
WritableImage nextGeneration = new WritableImage(width, height);
|
||||||
|
PixelReader pixelReader = bwImageRef.get().getPixelReader();
|
||||||
|
|
||||||
|
for (int y = 0; y < height; y += chunkSize) {
|
||||||
|
for (int x = 0; x < width; x += chunkSize) {
|
||||||
|
int aliveNeighbors = countAliveNeighbors(
|
||||||
|
pixelReader,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
chunkSize
|
||||||
|
);
|
||||||
|
Color currentColor = pixelReader.getColor(x, y);
|
||||||
|
Color nextColor;
|
||||||
|
|
||||||
|
if (currentColor.equals(Color.BLACK)) {
|
||||||
|
nextColor = (aliveNeighbors == 3 ||
|
||||||
|
aliveNeighbors == 2)
|
||||||
|
? Color.BLACK
|
||||||
|
: Color.WHITE;
|
||||||
|
} else {
|
||||||
|
nextColor = (aliveNeighbors == 3)
|
||||||
|
? Color.BLACK
|
||||||
|
: Color.WHITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the color for the entire chunk in the next generation
|
||||||
|
for (
|
||||||
|
int cy = 0;
|
||||||
|
cy < chunkSize && (y + cy) < height;
|
||||||
|
cy++
|
||||||
|
) {
|
||||||
|
for (
|
||||||
|
int cx = 0;
|
||||||
|
cx < chunkSize && (x + cx) < width;
|
||||||
|
cx++
|
||||||
|
) {
|
||||||
|
nextGeneration
|
||||||
|
.getPixelWriter()
|
||||||
|
.setColor(x + cx, y + cy, nextColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bwImageRef.set(nextGeneration);
|
||||||
|
imageView.setImage(bwImageRef.get());
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
timeline.setCycleCount(Timeline.INDEFINITE);
|
||||||
|
timeline.play();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void stopGameOfLife() {
|
||||||
|
if (timeline != null) {
|
||||||
|
timeline.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int countAliveNeighbors(
|
||||||
|
PixelReader reader,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
int chunkSize
|
||||||
|
) {
|
||||||
|
int count = 0;
|
||||||
|
for (int dy = -chunkSize; dy <= chunkSize; dy += chunkSize) {
|
||||||
|
for (int dx = -chunkSize; dx <= chunkSize; dx += chunkSize) {
|
||||||
|
if (dx == 0 && dy == 0) continue;
|
||||||
|
int nx = x + dx;
|
||||||
|
int ny = y + dy;
|
||||||
|
if (nx >= 0 && nx < width && ny >= 0 && ny < height) {
|
||||||
|
if (reader.getColor(nx, ny).equals(Color.BLACK)) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
113
src/ImageProcessor.java
Normal file
113
src/ImageProcessor.java
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
// ImageProcessor.java
|
||||||
|
package jfxlabproj;
|
||||||
|
|
||||||
|
import javafx.animation.FadeTransition;
|
||||||
|
import javafx.scene.effect.Bloom;
|
||||||
|
import javafx.scene.effect.ColorAdjust;
|
||||||
|
import javafx.scene.effect.DropShadow;
|
||||||
|
import javafx.scene.effect.GaussianBlur;
|
||||||
|
import javafx.scene.effect.InnerShadow;
|
||||||
|
import javafx.scene.effect.SepiaTone;
|
||||||
|
import javafx.scene.image.ImageView;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.util.Duration;
|
||||||
|
|
||||||
|
public class ImageProcessor {
|
||||||
|
|
||||||
|
public static void applySepia(ImageView imageView) {
|
||||||
|
if (imageView.getImage() != null) {
|
||||||
|
SepiaTone sepia = new SepiaTone(0.7);
|
||||||
|
Bloom bloom = new Bloom(0.2);
|
||||||
|
bloom.setInput(sepia);
|
||||||
|
|
||||||
|
DropShadow shadow = new DropShadow();
|
||||||
|
shadow.setRadius(10.0);
|
||||||
|
shadow.setSpread(0.3);
|
||||||
|
shadow.setColor(Color.rgb(0, 0, 0, 0.4));
|
||||||
|
shadow.setInput(bloom);
|
||||||
|
|
||||||
|
FadeTransition ft = new FadeTransition(
|
||||||
|
Duration.millis(300),
|
||||||
|
imageView
|
||||||
|
);
|
||||||
|
ft.setFromValue(0.7);
|
||||||
|
ft.setToValue(1.0);
|
||||||
|
|
||||||
|
imageView.setEffect(shadow);
|
||||||
|
ft.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void applyInvert(ImageView imageView) {
|
||||||
|
if (imageView.getImage() != null) {
|
||||||
|
ColorAdjust colorAdjust = new ColorAdjust();
|
||||||
|
colorAdjust.setBrightness(-1.0);
|
||||||
|
colorAdjust.setContrast(0);
|
||||||
|
colorAdjust.setHue(1.0);
|
||||||
|
colorAdjust.setSaturation(-1.0);
|
||||||
|
|
||||||
|
InnerShadow innerShadow = new InnerShadow();
|
||||||
|
innerShadow.setRadius(5.0);
|
||||||
|
innerShadow.setColor(Color.rgb(255, 255, 255, 0.3));
|
||||||
|
innerShadow.setInput(colorAdjust);
|
||||||
|
|
||||||
|
FadeTransition ft = new FadeTransition(
|
||||||
|
Duration.millis(300),
|
||||||
|
imageView
|
||||||
|
);
|
||||||
|
ft.setFromValue(0.7);
|
||||||
|
ft.setToValue(1.0);
|
||||||
|
|
||||||
|
imageView.setEffect(innerShadow);
|
||||||
|
ft.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void applyBlur(ImageView imageView) {
|
||||||
|
if (imageView.getImage() != null) {
|
||||||
|
GaussianBlur blur = new GaussianBlur(15);
|
||||||
|
Bloom bloom = new Bloom(0.3);
|
||||||
|
bloom.setInput(blur);
|
||||||
|
|
||||||
|
DropShadow shadow = new DropShadow();
|
||||||
|
shadow.setRadius(15.0);
|
||||||
|
shadow.setSpread(0.4);
|
||||||
|
shadow.setColor(Color.rgb(0, 0, 0, 0.3));
|
||||||
|
shadow.setInput(bloom);
|
||||||
|
|
||||||
|
FadeTransition ft = new FadeTransition(
|
||||||
|
Duration.millis(300),
|
||||||
|
imageView
|
||||||
|
);
|
||||||
|
ft.setFromValue(0.7);
|
||||||
|
ft.setToValue(1.0);
|
||||||
|
|
||||||
|
imageView.setEffect(shadow);
|
||||||
|
ft.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void applyGrayscale(ImageView imageView) {
|
||||||
|
if (imageView.getImage() != null) {
|
||||||
|
ColorAdjust grayscale = new ColorAdjust();
|
||||||
|
grayscale.setSaturation(-1);
|
||||||
|
grayscale.setContrast(0.2);
|
||||||
|
grayscale.setBrightness(0.1);
|
||||||
|
|
||||||
|
InnerShadow innerShadow = new InnerShadow();
|
||||||
|
innerShadow.setRadius(5.0);
|
||||||
|
innerShadow.setColor(Color.rgb(0, 0, 0, 0.3));
|
||||||
|
innerShadow.setInput(grayscale);
|
||||||
|
|
||||||
|
FadeTransition ft = new FadeTransition(
|
||||||
|
Duration.millis(300),
|
||||||
|
imageView
|
||||||
|
);
|
||||||
|
ft.setFromValue(0.7);
|
||||||
|
ft.setToValue(1.0);
|
||||||
|
|
||||||
|
imageView.setEffect(innerShadow);
|
||||||
|
ft.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
82
src/MusicPlayer.java
Normal file
82
src/MusicPlayer.java
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
package jfxlabproj.musicplayer;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import javafx.scene.image.Image;
|
||||||
|
import javafx.scene.image.PixelReader;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import javax.sound.sampled.*;
|
||||||
|
|
||||||
|
public class MusicPlayer {
|
||||||
|
|
||||||
|
private static final int BASE_NOTE = 262; // C4 note
|
||||||
|
private ScheduledExecutorService executor;
|
||||||
|
private volatile boolean isPlaying = false;
|
||||||
|
|
||||||
|
public void playImageAsMusic(Image image) {
|
||||||
|
if (image == null) return;
|
||||||
|
if (isPlaying) return; // Prevent starting multiple playbacks simultaneously
|
||||||
|
|
||||||
|
PixelReader reader = image.getPixelReader();
|
||||||
|
int width = (int) image.getWidth();
|
||||||
|
int height = (int) image.getHeight();
|
||||||
|
|
||||||
|
executor = Executors.newScheduledThreadPool(1);
|
||||||
|
isPlaying = true;
|
||||||
|
executor.scheduleAtFixedRate(
|
||||||
|
() -> {
|
||||||
|
Random random = new Random();
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
if (!isPlaying) return; // Stop processing if paused
|
||||||
|
|
||||||
|
Color color = reader.getColor(x, y);
|
||||||
|
double brightness = color.getBrightness();
|
||||||
|
int note = BASE_NOTE + (int) (brightness * 300); // Vary note based on brightness, reduced range for smoother sound
|
||||||
|
int duration = 150 + random.nextInt(150); // Randomize duration between 150ms and 300ms
|
||||||
|
playTone(note, duration, 0.2f); // Reduce volume
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
0,
|
||||||
|
300,
|
||||||
|
TimeUnit.MILLISECONDS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pauseMusic() {
|
||||||
|
if (executor != null) {
|
||||||
|
isPlaying = false;
|
||||||
|
executor.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void playTone(int hz, int duration, float volume) {
|
||||||
|
try {
|
||||||
|
byte[] buf = new byte[1];
|
||||||
|
AudioFormat audioFormat = new AudioFormat(44100, 8, 1, true, false);
|
||||||
|
SourceDataLine sdl = AudioSystem.getSourceDataLine(audioFormat);
|
||||||
|
sdl.open(audioFormat);
|
||||||
|
sdl.start();
|
||||||
|
|
||||||
|
FloatControl volumeControl = (FloatControl) sdl.getControl(
|
||||||
|
FloatControl.Type.MASTER_GAIN
|
||||||
|
);
|
||||||
|
volumeControl.setValue(20f * (float) Math.log10(volume)); // Set volume level
|
||||||
|
|
||||||
|
for (int i = 0; i < (duration * 44100) / 1000; i++) {
|
||||||
|
double angle = (i / (44100.0 / hz)) * 2.0 * Math.PI;
|
||||||
|
buf[0] = (byte) (Math.sin(angle) * 100.0); // Reduce amplitude for a softer sound
|
||||||
|
sdl.write(buf, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
sdl.drain();
|
||||||
|
sdl.stop();
|
||||||
|
sdl.close();
|
||||||
|
} catch (LineUnavailableException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
374
src/TheImaniPulator.java
Normal file
374
src/TheImaniPulator.java
Normal file
|
@ -0,0 +1,374 @@
|
||||||
|
package jfxlabproj;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import javafx.application.Application;
|
||||||
|
import javafx.embed.swing.SwingFXUtils;
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.geometry.Pos;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.scene.control.Alert;
|
||||||
|
import javafx.scene.control.Alert.AlertType;
|
||||||
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.image.Image;
|
||||||
|
import javafx.scene.image.ImageView;
|
||||||
|
import javafx.scene.layout.GridPane;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.scene.paint.Paint;
|
||||||
|
import javafx.stage.FileChooser;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import jfxlabproj.gameoflife.GameOfLifeProcessor;
|
||||||
|
import jfxlabproj.musicplayer.MusicPlayer;
|
||||||
|
|
||||||
|
public class TheImaniPulator extends Application {
|
||||||
|
|
||||||
|
private ImageView imageView;
|
||||||
|
private Image originalImage;
|
||||||
|
private MusicPlayer musicPlayer;
|
||||||
|
private Button activeButton = null;
|
||||||
|
private Label statusLabel;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start(Stage primaryStage) {
|
||||||
|
primaryStage.setTitle("Image Processor");
|
||||||
|
|
||||||
|
Scene welcomeScene = WelcomeScreen.createScene(primaryStage);
|
||||||
|
primaryStage.setScene(welcomeScene);
|
||||||
|
|
||||||
|
primaryStage.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Scene createMainScene(Stage primaryStage) {
|
||||||
|
HBox root = new HBox(30);
|
||||||
|
root.setAlignment(Pos.CENTER);
|
||||||
|
root.setStyle("-fx-background-color: #F5F5F7;");
|
||||||
|
root.setPadding(new Insets(30));
|
||||||
|
|
||||||
|
VBox leftSide = new VBox(20);
|
||||||
|
leftSide.setAlignment(Pos.CENTER);
|
||||||
|
leftSide.setStyle(
|
||||||
|
"-fx-background-color: white; -fx-background-radius: 20; -fx-padding: 20;" +
|
||||||
|
"-fx-effect: dropshadow(gaussian, rgba(0,0,0,0.1), 10, 0, 0, 5);"
|
||||||
|
);
|
||||||
|
|
||||||
|
imageView = new ImageView();
|
||||||
|
imageView.setFitWidth(400);
|
||||||
|
imageView.setFitHeight(500);
|
||||||
|
imageView.setPreserveRatio(true);
|
||||||
|
imageView.setStyle(
|
||||||
|
"-fx-effect: dropshadow(gaussian, rgba(0,0,0,0.1), 10, 0, 0, 5);"
|
||||||
|
);
|
||||||
|
|
||||||
|
statusLabel = new Label("Image Processor");
|
||||||
|
statusLabel.setStyle(
|
||||||
|
"-fx-font-family: 'SF Pro Display'; -fx-font-size: 18px; " +
|
||||||
|
"-fx-font-weight: bold; -fx-text-fill: #1D1D1F;"
|
||||||
|
);
|
||||||
|
|
||||||
|
Button loadButton = new Button("Choose Image");
|
||||||
|
styleButton(loadButton);
|
||||||
|
|
||||||
|
leftSide.getChildren().addAll(imageView, loadButton, statusLabel);
|
||||||
|
|
||||||
|
VBox rightSide = new VBox(15);
|
||||||
|
rightSide.setAlignment(Pos.TOP_CENTER);
|
||||||
|
rightSide.setPrefWidth(400);
|
||||||
|
rightSide.setStyle(
|
||||||
|
"-fx-background-color: white; -fx-background-radius: 20; -fx-padding: 30;" +
|
||||||
|
"-fx-effect: dropshadow(gaussian, rgba(0,0,0,0.1), 10, 0, 0, 5);"
|
||||||
|
);
|
||||||
|
|
||||||
|
Label titleLabel = new Label("Image Processor");
|
||||||
|
titleLabel.setStyle(
|
||||||
|
"-fx-font-family: 'SF Pro Display'; -fx-font-size: 32px; -fx-font-weight: bold;"
|
||||||
|
);
|
||||||
|
titleLabel.setTextFill(Paint.valueOf("#1D1D1F"));
|
||||||
|
|
||||||
|
Label filterLabel = new Label("Image Filters");
|
||||||
|
Label saveLabel = new Label("Save Options");
|
||||||
|
Label specialLabel = new Label("Special Effects");
|
||||||
|
Label musicLabel = new Label("Music Controls");
|
||||||
|
|
||||||
|
filterLabel.setStyle("-fx-font-weight: bold; -fx-font-size: 16px;");
|
||||||
|
saveLabel.setStyle("-fx-font-weight: bold; -fx-font-size: 16px;");
|
||||||
|
specialLabel.setStyle("-fx-font-weight: bold; -fx-font-size: 16px;");
|
||||||
|
musicLabel.setStyle("-fx-font-weight: bold; -fx-font-size: 16px;");
|
||||||
|
|
||||||
|
Button blurButton = new Button("Blur");
|
||||||
|
Button grayscaleButton = new Button("Grayscale");
|
||||||
|
Button sepiaButton = new Button("Sepia");
|
||||||
|
Button resetButton = new Button("Reset");
|
||||||
|
Button saveAsJpegButton = new Button("Save as JPEG");
|
||||||
|
Button saveAsPngButton = new Button("Save as PNG");
|
||||||
|
Button saveAsHeifButton = new Button("Save as HEIF");
|
||||||
|
Button gameOfLifeButton = new Button("Game of Life");
|
||||||
|
Button playMusicButton = new Button("Play as Music");
|
||||||
|
Button pauseMusicButton = new Button("Pause Music");
|
||||||
|
Button invertButton = new Button("Invert Colors");
|
||||||
|
|
||||||
|
int buttonWidth = 150;
|
||||||
|
for (Button btn : new Button[] {
|
||||||
|
blurButton,
|
||||||
|
grayscaleButton,
|
||||||
|
sepiaButton,
|
||||||
|
resetButton,
|
||||||
|
saveAsJpegButton,
|
||||||
|
saveAsPngButton,
|
||||||
|
saveAsHeifButton,
|
||||||
|
gameOfLifeButton,
|
||||||
|
playMusicButton,
|
||||||
|
pauseMusicButton,
|
||||||
|
invertButton,
|
||||||
|
}) {
|
||||||
|
styleButton(btn);
|
||||||
|
btn.setPrefWidth(buttonWidth);
|
||||||
|
btn.setWrapText(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
GridPane filterGrid = new GridPane();
|
||||||
|
filterGrid.setHgap(10);
|
||||||
|
filterGrid.setVgap(10);
|
||||||
|
filterGrid.add(blurButton, 0, 0);
|
||||||
|
filterGrid.add(grayscaleButton, 1, 0);
|
||||||
|
filterGrid.add(sepiaButton, 0, 1);
|
||||||
|
filterGrid.add(resetButton, 1, 1);
|
||||||
|
filterGrid.add(invertButton, 0, 2);
|
||||||
|
|
||||||
|
GridPane saveGrid = new GridPane();
|
||||||
|
saveGrid.setHgap(10);
|
||||||
|
saveGrid.setVgap(10);
|
||||||
|
saveGrid.add(saveAsJpegButton, 0, 0);
|
||||||
|
saveGrid.add(saveAsPngButton, 1, 0);
|
||||||
|
saveGrid.add(saveAsHeifButton, 0, 1);
|
||||||
|
|
||||||
|
GridPane specialGrid = new GridPane();
|
||||||
|
specialGrid.setHgap(10);
|
||||||
|
specialGrid.add(gameOfLifeButton, 0, 0);
|
||||||
|
|
||||||
|
GridPane musicGrid = new GridPane();
|
||||||
|
musicGrid.setHgap(10);
|
||||||
|
musicGrid.add(playMusicButton, 0, 0);
|
||||||
|
musicGrid.add(pauseMusicButton, 1, 0);
|
||||||
|
|
||||||
|
blurButton.setOnAction(e -> {
|
||||||
|
if (originalImage != null) {
|
||||||
|
setActiveButton(blurButton);
|
||||||
|
ImageProcessor.applyBlur(imageView);
|
||||||
|
updateStatus("Blur");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
grayscaleButton.setOnAction(e -> {
|
||||||
|
if (originalImage != null) {
|
||||||
|
setActiveButton(grayscaleButton);
|
||||||
|
ImageProcessor.applyGrayscale(imageView);
|
||||||
|
updateStatus("Grayscale");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
sepiaButton.setOnAction(e -> {
|
||||||
|
if (originalImage != null) {
|
||||||
|
setActiveButton(sepiaButton);
|
||||||
|
ImageProcessor.applySepia(imageView);
|
||||||
|
updateStatus("Sepia");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
invertButton.setOnAction(e -> {
|
||||||
|
if (originalImage != null) {
|
||||||
|
setActiveButton(invertButton);
|
||||||
|
ImageProcessor.applyInvert(imageView);
|
||||||
|
updateStatus("Invert Colors");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
resetButton.setOnAction(e -> {
|
||||||
|
if (originalImage != null) {
|
||||||
|
GameOfLifeProcessor.stopGameOfLife();
|
||||||
|
setActiveButton(null);
|
||||||
|
imageView.setImage(originalImage);
|
||||||
|
imageView.setEffect(null);
|
||||||
|
updateStatus("Image Processor");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
saveAsJpegButton.setOnAction(e -> {
|
||||||
|
saveImage(primaryStage, "jpeg");
|
||||||
|
updateStatus("Saving as JPEG");
|
||||||
|
});
|
||||||
|
|
||||||
|
saveAsPngButton.setOnAction(e -> {
|
||||||
|
saveImage(primaryStage, "png");
|
||||||
|
updateStatus("Saving as PNG");
|
||||||
|
});
|
||||||
|
|
||||||
|
saveAsHeifButton.setOnAction(e -> {
|
||||||
|
saveImage(primaryStage, "heif");
|
||||||
|
updateStatus("Saving as HEIF");
|
||||||
|
});
|
||||||
|
|
||||||
|
gameOfLifeButton.setOnAction(e -> {
|
||||||
|
if (originalImage != null) {
|
||||||
|
setActiveButton(gameOfLifeButton);
|
||||||
|
GameOfLifeProcessor.startGameOfLife(imageView);
|
||||||
|
updateStatus("Game of Life");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
playMusicButton.setOnAction(e -> {
|
||||||
|
if (originalImage != null) {
|
||||||
|
setActiveButton(playMusicButton);
|
||||||
|
musicPlayer = new MusicPlayer();
|
||||||
|
musicPlayer.playImageAsMusic(originalImage);
|
||||||
|
updateStatus("Playing Music");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
pauseMusicButton.setOnAction(e -> {
|
||||||
|
if (musicPlayer != null) {
|
||||||
|
setActiveButton(null);
|
||||||
|
musicPlayer.pauseMusic();
|
||||||
|
updateStatus("Music Paused");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
loadButton.setOnAction(e -> {
|
||||||
|
FileChooser fileChooser = new FileChooser();
|
||||||
|
fileChooser
|
||||||
|
.getExtensionFilters()
|
||||||
|
.add(
|
||||||
|
new FileChooser.ExtensionFilter(
|
||||||
|
"Image Files",
|
||||||
|
"*.png",
|
||||||
|
"*.jpg",
|
||||||
|
"*.jpeg",
|
||||||
|
"*.gif"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
File file = fileChooser.showOpenDialog(primaryStage);
|
||||||
|
if (file != null) {
|
||||||
|
Image image = new Image(file.toURI().toString());
|
||||||
|
imageView.setImage(image);
|
||||||
|
originalImage = image;
|
||||||
|
setActiveButton(null);
|
||||||
|
updateStatus("Image Processor");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
rightSide
|
||||||
|
.getChildren()
|
||||||
|
.addAll(
|
||||||
|
titleLabel,
|
||||||
|
filterLabel,
|
||||||
|
filterGrid,
|
||||||
|
saveLabel,
|
||||||
|
saveGrid,
|
||||||
|
specialLabel,
|
||||||
|
specialGrid,
|
||||||
|
musicLabel,
|
||||||
|
musicGrid
|
||||||
|
);
|
||||||
|
|
||||||
|
root.getChildren().addAll(leftSide, rightSide);
|
||||||
|
|
||||||
|
Scene scene = new Scene(root, 1000, 700);
|
||||||
|
scene.setFill(Color.web("#F5F5F7"));
|
||||||
|
|
||||||
|
return scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateStatus(String status) {
|
||||||
|
statusLabel.setText(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setActiveButton(Button button) {
|
||||||
|
if (activeButton != null) {
|
||||||
|
styleButton(activeButton);
|
||||||
|
}
|
||||||
|
activeButton = button;
|
||||||
|
if (activeButton != null) {
|
||||||
|
activeButton.setStyle(
|
||||||
|
"-fx-background-color: #FFC799;" +
|
||||||
|
"-fx-text-fill: black;" +
|
||||||
|
"-fx-font-family: 'SF Pro Text';" +
|
||||||
|
"-fx-font-size: 16px;" +
|
||||||
|
"-fx-padding: 12px 20px;" +
|
||||||
|
"-fx-background-radius: 10px;" +
|
||||||
|
"-fx-cursor: hand;" +
|
||||||
|
"-fx-effect: dropshadow(gaussian, rgba(0,0,0,0.2), 10, 0, 0, 5);"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveImage(Stage stage, String format) {
|
||||||
|
if (imageView.getImage() != null) {
|
||||||
|
FileChooser fileChooser = new FileChooser();
|
||||||
|
fileChooser.setTitle("Save Image");
|
||||||
|
fileChooser.setInitialFileName("processed_image." + format);
|
||||||
|
fileChooser
|
||||||
|
.getExtensionFilters()
|
||||||
|
.add(
|
||||||
|
new FileChooser.ExtensionFilter(
|
||||||
|
format.toUpperCase() + " files",
|
||||||
|
"*." + format
|
||||||
|
)
|
||||||
|
);
|
||||||
|
File file = fileChooser.showSaveDialog(stage);
|
||||||
|
if (file != null) {
|
||||||
|
try {
|
||||||
|
BufferedImage bufferedImage = SwingFXUtils.fromFXImage(
|
||||||
|
imageView.getImage(),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
ImageIO.write(bufferedImage, format, file);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
Alert alert = new Alert(AlertType.ERROR);
|
||||||
|
alert.setTitle("Error");
|
||||||
|
alert.setHeaderText("Could not save image");
|
||||||
|
alert.setContentText("Error: " + ex.getMessage());
|
||||||
|
alert.showAndWait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void styleButton(Button button) {
|
||||||
|
String defaultStyle =
|
||||||
|
"-fx-background-color: #F5F5F7;" +
|
||||||
|
"-fx-text-fill: #1D1D1F;" +
|
||||||
|
"-fx-font-family: 'SF Pro Text';" +
|
||||||
|
"-fx-font-size: 16px;" +
|
||||||
|
"-fx-padding: 12px 20px;" +
|
||||||
|
"-fx-background-radius: 10px;" +
|
||||||
|
"-fx-cursor: hand;" +
|
||||||
|
"-fx-border-color: #D2D2D7;" +
|
||||||
|
"-fx-border-radius: 10px;" +
|
||||||
|
"-fx-border-width: 1px;";
|
||||||
|
|
||||||
|
String hoverStyle =
|
||||||
|
"-fx-background-color: #E8E8ED;" +
|
||||||
|
"-fx-text-fill: #1D1D1F;" +
|
||||||
|
"-fx-font-family: 'SF Pro Text';" +
|
||||||
|
"-fx-font-size: 16px;" +
|
||||||
|
"-fx-padding: 12px 20px;" +
|
||||||
|
"-fx-background-radius: 10px;" +
|
||||||
|
"-fx-cursor: hand;" +
|
||||||
|
"-fx-border-color: #007AFF;" +
|
||||||
|
"-fx-border-radius: 10px;" +
|
||||||
|
"-fx-border-width: 2px;" +
|
||||||
|
"-fx-effect: dropshadow(gaussian, rgba(0,0,0,0.1), 5, 0, 0, 2);";
|
||||||
|
|
||||||
|
button.setStyle(defaultStyle);
|
||||||
|
button.setOnMouseEntered(e -> button.setStyle(hoverStyle));
|
||||||
|
button.setOnMouseExited(e -> button.setStyle(defaultStyle));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
launch(args);
|
||||||
|
}
|
||||||
|
}
|
75
src/WelcomeScreen.java
Normal file
75
src/WelcomeScreen.java
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
package jfxlabproj;
|
||||||
|
|
||||||
|
import javafx.animation.FadeTransition;
|
||||||
|
import javafx.geometry.Pos;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import javafx.util.Duration;
|
||||||
|
|
||||||
|
public class WelcomeScreen {
|
||||||
|
|
||||||
|
public static Scene createScene(Stage primaryStage) {
|
||||||
|
VBox root = new VBox(30);
|
||||||
|
root.setAlignment(Pos.CENTER);
|
||||||
|
root.setStyle("-fx-background-color: #1E1E1E;" + "-fx-padding: 40px;");
|
||||||
|
|
||||||
|
Label welcomeLabel = new Label("Image Processor");
|
||||||
|
welcomeLabel.setStyle(
|
||||||
|
"-fx-font-family: 'SF Pro Display';" +
|
||||||
|
"-fx-font-size: 48px;" +
|
||||||
|
"-fx-font-weight: bold;" +
|
||||||
|
"-fx-text-fill: #FFFFFF;"
|
||||||
|
);
|
||||||
|
|
||||||
|
Label subtitleLabel = new Label("Made by Aadit, Akhil and Saurabh.");
|
||||||
|
subtitleLabel.setStyle(
|
||||||
|
"-fx-font-family: 'SF Pro Text';" +
|
||||||
|
"-fx-font-size: 18px;" +
|
||||||
|
"-fx-text-fill: #BBBBBB;"
|
||||||
|
);
|
||||||
|
|
||||||
|
Button nextButton = new Button("Get Started");
|
||||||
|
nextButton.setStyle(
|
||||||
|
"-fx-background-color: #0F0F0F;" +
|
||||||
|
"-fx-text-fill: white;" +
|
||||||
|
"-fx-font-family: 'SF Pro Text';" +
|
||||||
|
"-fx-font-size: 16px;" +
|
||||||
|
"-fx-padding: 12px 24px;" +
|
||||||
|
"-fx-background-radius: 8px;" +
|
||||||
|
"-fx-cursor: hand;"
|
||||||
|
);
|
||||||
|
|
||||||
|
nextButton.setOnMouseEntered(e ->
|
||||||
|
nextButton.setStyle(
|
||||||
|
nextButton.getStyle() + "-fx-background-color: #0071E3;"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
nextButton.setOnMouseExited(e ->
|
||||||
|
nextButton.setStyle(
|
||||||
|
nextButton.getStyle() + "-fx-background-color: #0F0F0F;"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
nextButton.setOnAction(e -> {
|
||||||
|
FadeTransition ft = new FadeTransition(Duration.millis(300), root);
|
||||||
|
ft.setFromValue(1.0);
|
||||||
|
ft.setToValue(0.0);
|
||||||
|
ft.setOnFinished(event -> {
|
||||||
|
TheImaniPulator mainApp = new TheImaniPulator();
|
||||||
|
primaryStage.setScene(mainApp.createMainScene(primaryStage));
|
||||||
|
});
|
||||||
|
ft.play();
|
||||||
|
});
|
||||||
|
|
||||||
|
root.getChildren().addAll(welcomeLabel, subtitleLabel, nextButton);
|
||||||
|
|
||||||
|
Scene scene = new Scene(root, 800, 600);
|
||||||
|
scene.setFill(Color.web("#1E1E1E"));
|
||||||
|
|
||||||
|
return scene;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue