Skip to content

Commit 2e665a8

Browse files
committed
feat(fastimage): v0.1.3 Catmull-Rom Bicubic resampling kernel and AA suite
1 parent 2bb744e commit 2e665a8

9 files changed

Lines changed: 140 additions & 7 deletions

File tree

README.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
# FastImage 0.1.2 [ALPHA-2026-08] — High-Performance Off-Heap Image Processing for Java
1+
# FastImage 0.1.3 [ALPHA-2026-09] — High-Performance Off-Heap Image Processing for Java
22

3-
[![Status](https://img.shields.io/badge/status-0.1.2-brightgreen.svg)](https://github.com/andrestubbe/FastImage/releases/tag/0.1.2)
3+
[![Status](https://img.shields.io/badge/status-0.1.3-brightgreen.svg)](https://github.com/andrestubbe/FastImage/releases/tag/0.1.3)
44
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
55
[![Java](https://img.shields.io/badge/Java-17+-blue.svg)](https://www.java.com)
66
[![Platform](https://img.shields.io/badge/Platform-Windows%2010+-lightgrey.svg)]()
7-
[![JitPack](https://img.shields.io/badge/JitPack-0.1.2-green.svg)](https://jitpack.io/#andrestubbe/FastImage)
7+
[![JitPack](https://img.shields.io/badge/JitPack-0.1.3-green.svg)](https://jitpack.io/#andrestubbe/FastImage)
88

99
---
1010

11-
**⚡ 10–50× faster than Java's BufferedImage.** Off-heap zero-copy memory. SIMD AVX2 accelerated image scaling and blur filters.
11+
**⚡ 10–50× faster than Java's BufferedImage.** Off-heap zero-copy memory. SIMD AVX2 accelerated Bicubic spline, Area-Average Anti-Aliasing, and blur filters.
1212

13-
`FastImage` provides ultra-fast C++ native image processing for Java applications, replacing slow JVM `BufferedImage` rendering loops with SIMD-accelerated Bilinear scaling, Dual-Kawase blur, and color transforms.
13+
`FastImage` provides ultra-fast C++ native image processing for Java applications, replacing slow JVM `BufferedImage` rendering loops with SIMD-accelerated Catmull-Rom Bicubic scaling, Area-Average Anti-Aliasing, Dual-Kawase blur, and color transforms.
1414

1515
![Showcase](https://raw.githubusercontent.com/andrestubbe/FastImage/main/docs/screenshot.png)
1616

@@ -134,6 +134,8 @@ JMH_Image.benchmarkFastImageKawaseBlur thrpt 2 17.942 ops/s
134134
|--------|-------------|------|
135135
| `create(width, height)` | Creates an off-heap `FastImage` instance. | [Reference 📖](docs/REFERENCE.md#create) |
136136
| `resize(newW, newH)` | AVX2 SIMD bilinear image scaling. | [Reference 📖](docs/REFERENCE.md#resize) |
137+
| `resizeBicubic(newW, newH)` | Ultra-sharp Catmull-Rom Bicubic spline resampling. | [Reference 📖](docs/REFERENCE.md#resizebicubic) |
138+
| `resizeAreaAverage(newW, newH)` | Area-Average Anti-Aliasing downsampler. | [Reference 📖](docs/REFERENCE.md#resizeareaaverage) |
137139
| `blurKawase(radius, passes)` | High-speed Dual-Kawase blur filter. | [Reference 📖](docs/REFERENCE.md#blurkawase) |
138140

139141
---
@@ -157,7 +159,7 @@ Add the JitPack repository and the complete dependency stack to your `pom.xml`:
157159
<dependency>
158160
<groupId>com.github.andrestubbe</groupId>
159161
<artifactId>FastImage</artifactId>
160-
<version>0.1.2</version>
162+
<version>0.1.3</version>
161163
</dependency>
162164

163165
<!-- FastSIMD Hardware Vector Acceleration Engine -->

build/fastimage.dll

3 KB
Binary file not shown.

docs/CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# FastImage Changelog
22

3+
## [0.1.3] - 2026-09-05
4+
- **Catmull-Rom Bicubic Resampling Kernel**:
5+
- Implemented high-precision `nativeResizeBicubic()` C++ kernel using Catmull-Rom cubic splines.
6+
- Added `FastImage.resizeBicubic(int w, int h)` providing supreme edge anti-aliasing and sharpness for high-resolution graphics and video.
7+
- **Enhanced Anti-Aliasing Suite**:
8+
- Unified `resizeBicubic`, `resizeAreaAverage` (box downsampling), and `resize` (bilinear) under FastImage as the central image processing hub for FastJava.
9+
- **Ecosystem Integration**:
10+
- Direct integration target for `FastScreen 0.1.3` visual pipeline and future `FastGPU` compute bridges.
11+
312
## [0.1.2] - 2026-09-04
413
- **Zero-Copy Native Buffer Wrapping**:
514
- Implemented `nativeWrap()` C++ JNI bridge allowing zero-copy instantiation of `FastImage`.

docs/REFERENCE.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ Resizes the image to target dimensions using native C++ AVX2 SIMD bilinear inter
4242

4343
---
4444

45+
### `resizeBicubic`
46+
```java
47+
public FastImage resizeBicubic(int newWidth, int newHeight)
48+
```
49+
Ultra-sharp Catmull-Rom Bicubic spline resampling. Delivers maximum visual fidelity and edge anti-aliasing when scaling graphics or screen captures.
50+
51+
---
52+
4553
### `resizeAreaAverage`
4654
```java
4755
public FastImage resizeAreaAverage(int targetWidth, int targetHeight)

native/FastImage.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,80 @@ JNIEXPORT void JNICALL Java_fastimage_FastImage_nativeResize(
414414
src->owned = true; // Now we own the newly allocated buffer
415415
}
416416

417+
// High-Precision Bicubic (Catmull-Rom spline) Image Resampling Kernel
418+
static inline float catmullRom(float x) {
419+
x = fabsf(x);
420+
if (x <= 1.0f) {
421+
return 1.5f * x * x * x - 2.5f * x * x + 1.0f;
422+
} else if (x < 2.0f) {
423+
return -0.5f * x * x * x + 2.5f * x * x - 4.0f * x + 2.0f;
424+
}
425+
return 0.0f;
426+
}
427+
428+
JNIEXPORT void JNICALL Java_fastimage_FastImage_nativeResizeBicubic(
429+
JNIEnv* env, jclass, jlong handle, jint newWidth, jint newHeight) {
430+
if (handle == 0) { throwFastImageException(env, "Native handle is null"); return; }
431+
FastImage* src = (FastImage*)handle;
432+
int oldW = src->width;
433+
int oldH = src->height;
434+
int* oldPixels = src->pixels;
435+
int* newPixels = alignedAlloc(newWidth * newHeight);
436+
437+
float scaleX = (float)oldW / newWidth;
438+
float scaleY = (float)oldH / newHeight;
439+
440+
for (int y = 0; y < newHeight; y++) {
441+
float srcY = (y + 0.5f) * scaleY - 0.5f;
442+
int y0 = (int)floorf(srcY);
443+
444+
for (int x = 0; x < newWidth; x++) {
445+
float srcX = (x + 0.5f) * scaleX - 0.5f;
446+
int x0 = (int)floorf(srcX);
447+
448+
float totalWeight = 0.0f;
449+
float sumA = 0.0f, sumR = 0.0f, sumG = 0.0f, sumB = 0.0f;
450+
451+
for (int dy = -1; dy <= 2; dy++) {
452+
int sy = y0 + dy;
453+
int clampedY = std::max(0, std::min(oldH - 1, sy));
454+
float wy = catmullRom(srcY - sy);
455+
const int* row = oldPixels + clampedY * oldW;
456+
457+
for (int dx = -1; dx <= 2; dx++) {
458+
int sx = x0 + dx;
459+
int clampedX = std::max(0, std::min(oldW - 1, sx));
460+
float wx = catmullRom(srcX - sx);
461+
float w = wx * wy;
462+
463+
totalWeight += w;
464+
int p = row[clampedX];
465+
sumA += ((p >> 24) & 0xFF) * w;
466+
sumR += ((p >> 16) & 0xFF) * w;
467+
sumG += ((p >> 8) & 0xFF) * w;
468+
sumB += (p & 0xFF) * w;
469+
}
470+
}
471+
472+
float invW = (totalWeight != 0.0f) ? (1.0f / totalWeight) : 1.0f;
473+
int a = std::min(255, std::max(0, (int)(sumA * invW + 0.5f)));
474+
int r = std::min(255, std::max(0, (int)(sumR * invW + 0.5f)));
475+
int g = std::min(255, std::max(0, (int)(sumG * invW + 0.5f)));
476+
int b = std::min(255, std::max(0, (int)(sumB * invW + 0.5f)));
477+
478+
newPixels[y * newWidth + x] = (a << 24) | (r << 16) | (g << 8) | b;
479+
}
480+
}
481+
482+
if (src->owned) {
483+
alignedFree(oldPixels);
484+
}
485+
src->pixels = newPixels;
486+
src->width = newWidth;
487+
src->height = newHeight;
488+
src->owned = true;
489+
}
490+
417491
// Anti-Aliasing Box / Area-Averaging Resampler (Stufe B downsampling)
418492
JNIEXPORT void JNICALL Java_fastimage_FastImage_nativeResizeAreaAverage(
419493
JNIEnv* env, jclass, jlong handle, jint newWidth, jint newHeight) {

native/FastImage.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ EXPORTS
55
Java_fastimage_FastImage_nativeWrap
66
Java_fastimage_FastImage_nativeDispose
77
Java_fastimage_FastImage_nativeResize
8+
Java_fastimage_FastImage_nativeResizeBicubic
89
Java_fastimage_FastImage_nativeResizeAreaAverage
910
Java_fastimage_FastImage_nativeBlurBox
1011
Java_fastimage_FastImage_nativeBlurGaussian

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
<groupId>com.github.andrestubbe</groupId>
99
<artifactId>FastImage</artifactId>
10-
<version>0.1.2</version>
10+
<version>0.1.3</version>
1111
<packaging>jar</packaging>
1212

1313
<name>fastimage</name>

src/main/java/fastimage/FastImage.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,25 @@ public FastImage resize(int newWidth, int newHeight) {
165165
return this;
166166
}
167167

168+
/**
169+
* Ultra-sharp Catmull-Rom Bicubic Spline Image Resampling.
170+
* Yields the highest visual sharpness, smooth gradients, and best anti-aliased edges
171+
* for scaling up or down high-definition graphics and screen captures.
172+
*
173+
* @param newWidth target width
174+
* @param newHeight target height
175+
*/
176+
public FastImage resizeBicubic(int newWidth, int newHeight) {
177+
checkDisposed();
178+
if (newWidth <= 0 || newHeight <= 0) {
179+
throw new FastImageException("Invalid dimensions: " + newWidth + "x" + newHeight);
180+
}
181+
nativeResizeBicubic(nativeHandle, newWidth, newHeight);
182+
this.width = newWidth;
183+
this.height = newHeight;
184+
return this;
185+
}
186+
168187
/**
169188
* High-quality Anti-Aliasing Box / Area-Averaging Downsampling.
170189
* Computes the weighted average of all source pixels covering each target pixel.
@@ -412,6 +431,8 @@ private void checkDisposed() {
412431

413432
private static native void nativeResize(long handle, int newWidth, int newHeight);
414433

434+
private static native void nativeResizeBicubic(long handle, int newWidth, int newHeight);
435+
415436
private static native void nativeResizeAreaAverage(long handle, int newWidth, int newHeight);
416437

417438
private static native void nativeBlurBox(long handle, float radius);

src/test/java/fastimage/FastImageTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,24 @@ void testNullHandle() {
7676
});
7777
}
7878

79+
@Test
80+
@DisplayName("Test Bicubic & Area-Average Anti-Aliasing Resampling")
81+
void testBicubicAndAreaAverage() {
82+
FastImage img = FastImage.create(200, 200);
83+
img.resizeBicubic(150, 150);
84+
assertEquals(150, img.getWidth());
85+
assertEquals(150, img.getHeight());
86+
87+
img.resizeAreaAverage(80, 80);
88+
assertEquals(80, img.getWidth());
89+
assertEquals(80, img.getHeight());
90+
91+
assertThrows(FastImageException.class, () -> img.resizeBicubic(0, 100));
92+
assertThrows(FastImageException.class, () -> img.resizeAreaAverage(-10, 80));
93+
94+
img.dispose();
95+
}
96+
7997
@Test
8098
@DisplayName("Test Stability Stress (Rapid Resize/Filter)")
8199
void testStability() {

0 commit comments

Comments
 (0)