Skip to content

Commit fe13a03

Browse files
committed
FastImage v0.1.0: Final Polish & Bing Showcase Demos (Resize Benchmark, Pipeline, Batch)
1 parent 5f87cc9 commit fe13a03

11 files changed

Lines changed: 627 additions & 94 deletions

File tree

docs/API_DESIGN.md

Lines changed: 0 additions & 27 deletions
This file was deleted.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
<groupId>fastimage</groupId>
5+
<artifactId>batch-processing-bing</artifactId>
6+
<version>0.1.0</version>
7+
<name>FastImage Batch Processing (Bing)</name>
8+
9+
<properties>
10+
<maven.compiler.source>17</maven.compiler.source>
11+
<maven.compiler.target>17</maven.compiler.target>
12+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
13+
</properties>
14+
15+
<dependencies>
16+
<dependency>
17+
<groupId>com.github.andrestubbe</groupId>
18+
<artifactId>fastimage</artifactId>
19+
<version>0.1.0</version>
20+
</dependency>
21+
</dependencies>
22+
</project>
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package fastimage;
2+
3+
import javax.swing.*;
4+
import javax.swing.border.EmptyBorder;
5+
import java.awt.*;
6+
import java.awt.image.BufferedImage;
7+
import java.util.concurrent.ExecutorService;
8+
import java.util.concurrent.Executors;
9+
import java.util.concurrent.TimeUnit;
10+
import java.util.concurrent.atomic.AtomicInteger;
11+
12+
/**
13+
* BatchProcessing_Bing - Parallel High-Throughput Demo.
14+
* Goal: Process 100 images as fast as possible.
15+
*/
16+
public class BatchProcessing_Bing extends JFrame {
17+
18+
private final BufferedImage sample;
19+
private final JProgressBar progressBar;
20+
private final JLabel statsLabel;
21+
private final AtomicInteger completedCount = new AtomicInteger(0);
22+
23+
public BatchProcessing_Bing() {
24+
setTitle("FastImage Batch Processor (Bing)");
25+
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
26+
setResizable(false);
27+
getContentPane().setBackground(new Color(30, 30, 35));
28+
setLayout(new BorderLayout());
29+
30+
sample = new BufferedImage(1024, 1024, BufferedImage.TYPE_INT_ARGB);
31+
Graphics2D g = sample.createGraphics();
32+
g.setPaint(new GradientPaint(0, 0, Color.CYAN, 1024, 1024, Color.MAGENTA));
33+
g.fillRect(0, 0, 1024, 1024);
34+
g.dispose();
35+
36+
// Header
37+
JLabel header = new JLabel("PARALLEL BATCH PROCESSING (100 IMAGES)", SwingConstants.CENTER);
38+
header.setForeground(Color.WHITE);
39+
header.setFont(new Font("Segoe UI", Font.BOLD, 20));
40+
header.setBorder(new EmptyBorder(30, 0, 30, 0));
41+
add(header, BorderLayout.NORTH);
42+
43+
// Center Panel
44+
JPanel center = new JPanel(new GridLayout(2, 1, 10, 10));
45+
center.setOpaque(false);
46+
center.setBorder(new EmptyBorder(0, 40, 0, 40));
47+
48+
progressBar = new JProgressBar(0, 100);
49+
progressBar.setPreferredSize(new Dimension(0, 40));
50+
progressBar.setStringPainted(true);
51+
progressBar.setForeground(new Color(0, 255, 150));
52+
progressBar.setBackground(new Color(50, 50, 60));
53+
center.add(progressBar);
54+
55+
statsLabel = new JLabel("READY TO PROCESS", SwingConstants.CENTER);
56+
statsLabel.setForeground(Color.LIGHT_GRAY);
57+
statsLabel.setFont(new Font("Consolas", Font.BOLD, 18));
58+
center.add(statsLabel);
59+
60+
add(center, BorderLayout.CENTER);
61+
62+
// Run Button
63+
JButton btnRun = new JButton("🚀 START BATCH PROCESS");
64+
btnRun.setFont(new Font("Segoe UI", Font.BOLD, 18));
65+
btnRun.setBackground(new Color(0, 120, 215));
66+
btnRun.setForeground(Color.WHITE);
67+
btnRun.addActionListener(e -> {
68+
btnRun.setEnabled(false);
69+
runBatch();
70+
});
71+
add(btnRun, BorderLayout.SOUTH);
72+
73+
pack();
74+
setSize(800, 400);
75+
setLocationRelativeTo(null);
76+
}
77+
78+
private void runBatch() {
79+
completedCount.set(0);
80+
progressBar.setValue(0);
81+
statsLabel.setText("PROCESSING...");
82+
83+
new Thread(() -> {
84+
long startTime = System.currentTimeMillis();
85+
int threadCount = Runtime.getRuntime().availableProcessors();
86+
ExecutorService executor = Executors.newFixedThreadPool(threadCount);
87+
88+
for (int i = 0; i < 100; i++) {
89+
executor.submit(() -> {
90+
try {
91+
FastImage img = FastImage.fromBufferedImage(sample);
92+
img.resize(512, 512);
93+
img.blurStack(5.0f);
94+
img.dispose();
95+
96+
int done = completedCount.incrementAndGet();
97+
SwingUtilities.invokeLater(() -> progressBar.setValue(done));
98+
} catch (Exception ex) {
99+
ex.printStackTrace();
100+
}
101+
});
102+
}
103+
104+
executor.shutdown();
105+
try {
106+
executor.awaitTermination(30, TimeUnit.SECONDS);
107+
} catch (InterruptedException e) {
108+
e.printStackTrace();
109+
}
110+
111+
long duration = System.currentTimeMillis() - startTime;
112+
double imgPerSec = 100.0 / (duration / 1000.0);
113+
114+
SwingUtilities.invokeLater(() -> {
115+
statsLabel.setText(String.format("FINISHED: %d ms (%.1f images/sec)", duration, imgPerSec));
116+
statsLabel.setForeground(Color.GREEN);
117+
});
118+
}).start();
119+
}
120+
121+
public static void main(String[] args) {
122+
SwingUtilities.invokeLater(() -> new BatchProcessing_Bing().setVisible(true));
123+
}
124+
}

examples/PipelineDemo_Bing/pom.xml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
<groupId>fastimage</groupId>
5+
<artifactId>pipeline-demo-bing</artifactId>
6+
<version>0.1.0</version>
7+
<name>FastImage Pipeline Demo (Bing)</name>
8+
9+
<properties>
10+
<maven.compiler.source>17</maven.compiler.source>
11+
<maven.compiler.target>17</maven.compiler.target>
12+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
13+
</properties>
14+
15+
<dependencies>
16+
<dependency>
17+
<groupId>com.github.andrestubbe</groupId>
18+
<artifactId>fastimage</artifactId>
19+
<version>0.1.0</version>
20+
</dependency>
21+
</dependencies>
22+
</project>
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
package fastimage;
2+
3+
import javax.swing.*;
4+
import javax.swing.border.EmptyBorder;
5+
import java.awt.*;
6+
import java.awt.image.BufferedImage;
7+
8+
/**
9+
* PipelineDemo_Bing - Visualizing the processing chain.
10+
* Steps: Original -> Gaussian Blur -> Contrast -> Grayscale.
11+
*/
12+
public class PipelineDemo_Bing extends JFrame {
13+
14+
private final BufferedImage original;
15+
private final JLabel[] previewLabels = new JLabel[4];
16+
private final JLabel[] timeLabels = new JLabel[4];
17+
private final String[] stepNames = {"ORIGINAL", "BLUR GAUSSIAN", "CONTRAST", "GRAYSCALE"};
18+
19+
public PipelineDemo_Bing() {
20+
setTitle("FastImage Pipeline Showcase (Bing)");
21+
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
22+
setResizable(false);
23+
getContentPane().setBackground(new Color(20, 20, 20));
24+
setLayout(new BorderLayout());
25+
26+
original = generateTestImage(1200, 800);
27+
28+
// Header
29+
JLabel header = new JLabel("MULTI-STAGE SIMD PIPELINE", SwingConstants.CENTER);
30+
header.setForeground(Color.WHITE);
31+
header.setFont(new Font("Segoe UI", Font.BOLD, 22));
32+
header.setBorder(new EmptyBorder(20, 0, 20, 0));
33+
add(header, BorderLayout.NORTH);
34+
35+
// Grid for steps
36+
JPanel grid = new JPanel(new GridLayout(1, 4, 15, 0));
37+
grid.setOpaque(false);
38+
grid.setBorder(new EmptyBorder(0, 20, 0, 20));
39+
40+
for (int i = 0; i < 4; i++) {
41+
grid.add(createStepPanel(i));
42+
}
43+
add(grid, BorderLayout.CENTER);
44+
45+
// Start Button
46+
JButton btnRun = new JButton("▶ RUN PIPELINE");
47+
btnRun.setFont(new Font("Segoe UI", Font.BOLD, 18));
48+
btnRun.setBackground(new Color(50, 180, 80));
49+
btnRun.setForeground(Color.WHITE);
50+
btnRun.addActionListener(e -> {
51+
btnRun.setEnabled(false);
52+
runPipeline();
53+
});
54+
add(btnRun, BorderLayout.SOUTH);
55+
56+
pack();
57+
setSize(1300, 500);
58+
setLocationRelativeTo(null);
59+
60+
// Initial state
61+
previewLabels[0].setIcon(new ImageIcon(original.getScaledInstance(300, 200, Image.SCALE_SMOOTH)));
62+
}
63+
64+
private JPanel createStepPanel(int index) {
65+
JPanel p = new JPanel(new BorderLayout(5, 5));
66+
p.setOpaque(false);
67+
68+
JLabel name = new JLabel(stepNames[index], SwingConstants.CENTER);
69+
name.setForeground(new Color(180, 180, 180));
70+
name.setFont(new Font("Segoe UI", Font.BOLD, 12));
71+
p.add(name, BorderLayout.NORTH);
72+
73+
previewLabels[index] = new JLabel();
74+
previewLabels[index].setHorizontalAlignment(SwingConstants.CENTER);
75+
previewLabels[index].setBorder(BorderFactory.createLineBorder(new Color(50, 50, 50)));
76+
previewLabels[index].setPreferredSize(new Dimension(300, 200));
77+
p.add(previewLabels[index], BorderLayout.CENTER);
78+
79+
timeLabels[index] = new JLabel(index == 0 ? "-" : "WAITING...");
80+
timeLabels[index].setForeground(Color.GRAY);
81+
timeLabels[index].setHorizontalAlignment(SwingConstants.CENTER);
82+
timeLabels[index].setFont(new Font("Consolas", Font.PLAIN, 14));
83+
p.add(timeLabels[index], BorderLayout.SOUTH);
84+
85+
return p;
86+
}
87+
88+
private void runPipeline() {
89+
new Thread(() -> {
90+
try {
91+
// Step 0: Load (already done)
92+
93+
// Step 1: Blur
94+
long t1 = System.nanoTime();
95+
FastImage fi = FastImage.fromBufferedImage(original);
96+
fi.blurGaussian(10.0f);
97+
long d1 = (System.nanoTime() - t1) / 1_000_000;
98+
updateStep(1, fi.toBufferedImage(), d1);
99+
Thread.sleep(500);
100+
101+
// Step 2: Contrast
102+
long t2 = System.nanoTime();
103+
fi.adjustContrast(1.5f);
104+
long d2 = (System.nanoTime() - t2) / 1_000_000;
105+
updateStep(2, fi.toBufferedImage(), d2);
106+
Thread.sleep(500);
107+
108+
// Step 3: Grayscale
109+
long t3 = System.nanoTime();
110+
fi.grayscale();
111+
long d3 = (System.nanoTime() - t3) / 1_000_000;
112+
updateStep(3, fi.toBufferedImage(), d3);
113+
114+
fi.dispose();
115+
} catch (Exception ex) {
116+
ex.printStackTrace();
117+
}
118+
}).start();
119+
}
120+
121+
private void updateStep(int index, BufferedImage img, long ms) {
122+
SwingUtilities.invokeLater(() -> {
123+
previewLabels[index].setIcon(new ImageIcon(img.getScaledInstance(300, 200, Image.SCALE_SMOOTH)));
124+
timeLabels[index].setText(ms + " ms");
125+
timeLabels[index].setForeground(new Color(0, 200, 255));
126+
});
127+
}
128+
129+
private BufferedImage generateTestImage(int w, int h) {
130+
BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
131+
Graphics2D g = img.createGraphics();
132+
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
133+
134+
// Complex background
135+
for (int i = 0; i < 50; i++) {
136+
g.setColor(new Color((int)(Math.random()*255), (int)(Math.random()*255), (int)(Math.random()*255)));
137+
g.fillOval((int)(Math.random()*w), (int)(Math.random()*h), 100, 100);
138+
}
139+
140+
g.setColor(Color.WHITE);
141+
g.setFont(new Font("Segoe UI Black", Font.PLAIN, 120));
142+
g.drawString("PIPELINE TEST", 150, h/2);
143+
g.dispose();
144+
return img;
145+
}
146+
147+
public static void main(String[] args) {
148+
SwingUtilities.invokeLater(() -> new PipelineDemo_Bing().setVisible(true));
149+
}
150+
}

examples/README.md

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,23 @@
1-
# 🖼 FastImage Examples
1+
# FastImage Examples & Demos
22

3-
Self-contained example projects demonstrating the power and performance of FastImage.
3+
This directory contains several projects demonstrating the performance and features of the FastImage library.
44

5-
## 📂 Featured Examples
5+
## Core Demos
66

7-
* **[BasicUsage](./BasicUsage)**: Minimal integration example. Start here to learn the core API.
8-
* **[ResizeDemo](./ResizeDemo)**: Shows high-quality bilinear and bicubic resizing performance.
9-
* **[BlurGallery](./BlurGallery)**: A visual comparison of all blur algorithms (Gaussian, Stack, Kawase).
10-
* **[FilterChain](./FilterChain)**: Demonstrates how to chain multiple native operations without returning to the JVM heap.
11-
* **[VisualEditor](./VisualEditor)**: **Showcase Demo** - A real-time image editor showing SIMD speed in action.
12-
* **[Benchmark](./Benchmark)**: Side-by-side performance comparison with Java2D.
7+
- **[Visual Editor](./VisualEditor)**: Interactive real-time editor showing live previews of filters (Brightness, Contrast, Blur, Grayscale).
8+
- **[Blur Gallery](./BlurGallery)**: Asynchronous performance comparison between Java2D and SIMD-accelerated blurs.
9+
- **[Resize Demo](./ResizeDemo)**: Shows the difference between various interpolation methods (Bilinear vs Bicubic).
10+
- **[Basic Usage](./BasicUsage)**: Minimal boilerplate example for integration.
1311

14-
---
12+
## Bing Showcase Demos
1513

16-
## 🚀 Running Examples
14+
- **[Resize Benchmark](./ResizeBenchmark_Bing)**: Stress-test scaling 4K images to 1080p. Shows parallel progress bars and Ops/s.
15+
- **[Pipeline Demo](./PipelineDemo_Bing)**: Visualizes a multi-stage chain (Blur -> Contrast -> Grayscale) with per-step timing.
16+
- **[Batch Processing](./BatchProcessing_Bing)**: Demonstrates off-heap efficiency by processing 100 images in parallel.
1717

18-
Each example is a standalone Maven project. To run the Visual Editor (Showcase):
18+
## Running the Demos
1919

20+
You can run all demos using the root launcher:
2021
```powershell
21-
cd examples/VisualEditor
22-
mvn compile exec:java
22+
.\run-demo.bat
2323
```
24-
25-
> [!NOTE]
26-
> Ensure you have run `mvn install` in the root directory first so the examples can find the `fastimage` dependency.

0 commit comments

Comments
 (0)