Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Changelog

## 0.12.0 (2026-07-31)

### 新增
- 双三次缩放:`resize_bicubic(w, h)`,Catmull-Rom 4×4 核、中心对齐采样,同尺寸缩放为恒等
- 感知哈希:`average_hash()` / `difference_hash()` 返回 64 位指纹,`hamming_distance(a, b)` 度量相似度;区域均值缩略图保证跨后端确定性
- 确定性噪声:`add_gaussian_noise(seed, sigma)`(CLT 12 均匀和)与 `add_salt_pepper(seed, density)`,64 位 LCG 驱动,同 seed 逐字节可重现

### 变更
- 单元测试从 147 个增加到 163 个(含反相恰好翻转全部 64 位、中值滤波清除 ≥75% 椒盐噪声等强断言)

## 0.11.0 (2026-07-30)

代码审查驱动的加固(三视角审查后全量修复):
Expand Down
18 changes: 11 additions & 7 deletions README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ English | [简体中文](README.md)

## ✨ Features

- **26 filters & geometric transforms**: grayscale, invert, brightness, contrast, gaussian/box blur, sharpen, emboss, Laplacian/Sobel/Scharr/Canny edges, sepia, threshold, pixelate, median denoise, histogram equalization, posterize, gamma, vignette, saturate, hue rotate, horizontal/vertical flips — plus 90° rotation and nearest/bilinear resize.
- **26 filters & geometric transforms**: grayscale, invert, brightness, contrast, gaussian/box blur, sharpen, emboss, Laplacian/Sobel/Scharr/Canny edges, sepia, threshold, pixelate, median denoise, histogram equalization, posterize, gamma, vignette, saturate, hue rotate, horizontal/vertical flips — plus 90° rotation and nearest/bilinear/bicubic (Catmull-Rom) resize.
- **Morphology**: 3×3 erode / dilate / open / close.
- **Image codecs**: PNG (self-implemented full DEFLATE inflate with CRC-32/Adler-32 verification), GIF decoding (variable-width LZW, interlacing, transparency), QOI (complete spec, lossless round trip) and BMP (uncompressed 24/32-bit) — all in pure MoonBit.
- **Affine transforms**: an `Affine` matrix type (rotate/translate/scale/shear + composition + inversion) rendered by inverse mapping with bilinear sampling; arbitrary-angle `rotate(degrees)`.
Expand All @@ -28,15 +28,16 @@ English | [简体中文](README.md)
- **Unsharp mask**: `unsharp_mask(radius, amount)` reuses the Gaussian to extract and re-add high-frequency detail, sharpening edges.
- **Crop & pad**: `crop(x, y, w, h)` (clamped to bounds) and `pad(l, t, r, b, color)` (colored borders); `crop∘pad` round-trips losslessly.
- **Bilateral filter**: `bilateral(radius, σs, σr)` edge-preserving smoothing — denoises flat regions while keeping strong edges sharp.
- **Image analysis**: Otsu automatic thresholding (between-class variance), Floyd–Steinberg error-diffusion dithering, 4-connected component labeling and counting, chamfer (3,4) distance transform.
- **Image analysis**: Otsu automatic thresholding (between-class variance), Floyd–Steinberg error-diffusion dithering, 4-connected component labeling and counting, chamfer (3,4) distance transform, perceptual hashes (aHash/dHash + Hamming distance).
- **Integral image & O(1) box blur**: `integral_image()` builds a summed-area table (Int64, overflow-safe) that drives `box_blur(radius)` at O(1) per pixel for any radius.
- **Flood fill**: `flood_fill(x, y, color, tolerance)` 4-connected seed fill with per-channel tolerance.
- **Layer compositing**: `composite(top, mode)` — Porter-Duff source-over with 8 blend modes (multiply, screen, overlay, darken, lighten, difference, add), in rounded integer math.
- **Bitmap text**: built-in 5×7 font (digits, uppercase letters, basic punctuation), `draw_text` with integer scaling and clipping.
- **Color spaces**: exact round-trip RGB ↔ HSV and RGB ↔ YCbCr (BT.601) conversions.
- **Generic convolution engine**: `Kernel` + `Image::convolve` for custom odd-sized kernels.
- **Image statistics & tone**: `stats()` per-channel min/max/mean (Int64 accumulation), `auto_contrast()` automatic contrast stretch, `levels(black, white, gamma)` tonal remap.
- **Integer-first, deterministic**: filter math sticks to integers where possible (e.g. luma weights ×1000); results are reproducible and **all 147 unit tests are hand-verified** (including canonical CRC-32/Adler-32 check vectors and a hand-assembled DEFLATE bitstream).
- **Deterministic noise**: `add_gaussian_noise(seed, σ)` / `add_salt_pepper(seed, density)` driven by a 64-bit LCG — the same seed is byte-identical on every backend.
- **Integer-first, deterministic**: filter math sticks to integers where possible (e.g. luma weights ×1000); results are reproducible and **all 163 unit tests are hand-verified** (including canonical CRC-32/Adler-32 check vectors and a hand-assembled DEFLATE bitstream).
- **Zero dependencies**: only `moonbitlang/core`, no third-party libraries.
- **Multi-backend, zero-copy interop**: on the js backend a `FixedArray[Byte]` *is* a `Uint8Array`, so canvas `Uint8ClampedArray` buffers cross over without copies; the linear-memory wasm backend exports `memory` for bulk pixel access.
- **Browser Playground**: drag & drop / paste / upload images, stackable filter pipeline, JS/WASM engine switch with benchmarks, an optional **Web Worker background thread** for large images, and PNG downloads produced by the library's **own `png_encode`**.
Expand All @@ -62,6 +63,9 @@ pixelforge/
├── floodfill.mbt # flood fill (4-connected seed fill)
├── distance.mbt # chamfer (3,4) distance transform
├── stats.mbt # statistics / auto-contrast / levels
├── bicubic.mbt # bicubic resize (Catmull-Rom)
├── phash.mbt # perceptual hashes (aHash/dHash + Hamming)
├── noise.mbt # deterministic noise (gaussian / salt-pepper)
├── bilateral.mbt # bilateral filter (edge-preserving)
├── otsu.mbt # Otsu automatic threshold
├── dither.mbt # Floyd–Steinberg error diffusion
Expand All @@ -75,7 +79,7 @@ pixelforge/
├── transform.mbt # flips, 90° rotation
├── resize.mbt # nearest/bilinear resize
├── dispatch.mbt # Image::apply_filter_id shared dispatch table
├── *_test.mbt # 147 deterministic tests (blackbox + whitebox)
├── *_test.mbt # 163 deterministic tests (blackbox + whitebox)
├── cmd/main/ # native CLI example (moon run cmd/main)
├── cmd/ppm/ # PPM output example (moon run cmd/ppm > edges.ppm)
├── cmd/showcase/ # capstone demo (drawing+text+filter+PNG round trip)
Expand All @@ -94,7 +98,7 @@ pixelforge/
Install the [MoonBit toolchain](https://www.moonbitlang.com/download/) first.

```bash
moon test # run the 147 unit tests
moon test # run the 163 unit tests
moon run cmd/main # native example (builds an image, runs filters, prints checksums)
moon run cmd/ppm > edges.ppm # emit a Sobel edge-detected PPM image
```
Expand Down Expand Up @@ -164,7 +168,7 @@ let png_bytes = @pixelforge.png_encode(framed)
| 21 | Otsu auto threshold | `otsu()` | — |
| 22 | Floyd–Steinberg dither (mono) | `dither_mono()` | — |

> Size-changing transforms are library APIs rather than dispatch ids: `rotate90()`, `resize_nearest(w, h)`, `resize_bilinear(w, h)`. Likewise for multi-parameter APIs: `box_blur(radius)`, `flood_fill(x, y, color, tol)`, `distance_transform(t)`, `gaussian(radius)`, `unsharp_mask(radius, amount)`, `crop(x, y, w, h)`, `pad(l, t, r, b, color)`, `bilateral(radius, σs, σr)`, `dither_grayscale(levels)`/`dither_mono()`, `otsu_threshold()`, `label_components(t)`/`count_components(t)`, `composite(top, mode)`, `draw_text(...)`, `rotate(deg)`, `translate(dx, dy)`, `affine(t)`, the drawing primitives, `saturate(factor)`, `hue_rotate(deg)`, the morphology operators, `png_encode`/`png_decode`, `gif_decode`, `qoi_encode`/`qoi_decode`, `bmp_encode`/`bmp_decode` and the color-space functions.
> Size-changing transforms are library APIs rather than dispatch ids: `rotate90()`, `resize_nearest(w, h)`, `resize_bilinear(w, h)`, `resize_bicubic(w, h)`. Likewise for multi-parameter APIs: `average_hash()`/`difference_hash()`/`hamming_distance`, `add_gaussian_noise`/`add_salt_pepper`, `box_blur(radius)`, `flood_fill(x, y, color, tol)`, `distance_transform(t)`, `gaussian(radius)`, `unsharp_mask(radius, amount)`, `crop(x, y, w, h)`, `pad(l, t, r, b, color)`, `bilateral(radius, σs, σr)`, `dither_grayscale(levels)`/`dither_mono()`, `otsu_threshold()`, `label_components(t)`/`count_components(t)`, `composite(top, mode)`, `draw_text(...)`, `rotate(deg)`, `translate(dx, dy)`, `affine(t)`, the drawing primitives, `saturate(factor)`, `hue_rotate(deg)`, the morphology operators, `png_encode`/`png_decode`, `gif_decode`, `qoi_encode`/`qoi_decode`, `bmp_encode`/`bmp_decode` and the color-space functions.

## 🏗️ Architecture & backends

Expand All @@ -182,7 +186,7 @@ moon test # default backend (wasm-gc)
moon test --target js # js backend
```

147 tests cover every filter, transform, drawing primitive, blend mode, the font, the analysis algorithms and all four codecs. Every expected value is derived by hand — impulse responses, flat-field invariance, known edges, histogram remapping, exact encoded byte lengths, lossless round trips, canonical CRC-32/Adler-32 check vectors and hand-assembled DEFLATE and GIF LZW bitstreams — and passes on both the wasm-gc and js backends, with GitHub Actions CI.
163 tests cover every filter, transform, drawing primitive, blend mode, the font, the analysis algorithms and all four codecs. Every expected value is derived by hand — impulse responses, flat-field invariance, known edges, histogram remapping, exact encoded byte lengths, lossless round trips, canonical CRC-32/Adler-32 check vectors and hand-assembled DEFLATE and GIF LZW bitstreams — and passes on both the wasm-gc and js backends, with GitHub Actions CI.

## 📮 Published on mooncakes.io

Expand Down
18 changes: 11 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

## ✨ 特性

- **26 种滤镜与几何变换**:灰度、反色、亮度、对比度、高斯/盒式模糊、锐化、浮雕、拉普拉斯/Sobel/Scharr/Canny 边缘、棕褐色、二值化、像素化、中值降噪、直方图均衡、色调分离、伽马校正、暗角、饱和度、色相旋转、水平/垂直翻转;另有 90° 旋转与最近邻/双线性缩放
- **26 种滤镜与几何变换**:灰度、反色、亮度、对比度、高斯/盒式模糊、锐化、浮雕、拉普拉斯/Sobel/Scharr/Canny 边缘、棕褐色、二值化、像素化、中值降噪、直方图均衡、色调分离、伽马校正、暗角、饱和度、色相旋转、水平/垂直翻转;另有 90° 旋转与最近邻/双线性/双三次 (Catmull-Rom) 缩放
- **形态学运算**:3×3 腐蚀 / 膨胀 / 开运算 / 闭运算。
- **图像编解码**:PNG(自实现完整 DEFLATE inflate + CRC-32/Adler-32 校验)、GIF 解码(变长 LZW、交错、透明索引)、QOI(完整规范,无损往返)与 BMP(无压缩 24/32 位)纯 MoonBit 实现。
- **仿射变换**:`Affine` 矩阵(旋转/平移/缩放/错切 + 复合 + 求逆),逆映射双线性采样;任意角度 `rotate(degrees)`。
Expand All @@ -28,15 +28,16 @@
- **锐化蒙版**:`unsharp_mask(radius, amount)` 复用高斯模糊提取高频细节并回叠,锐化边缘。
- **裁剪与填充**:`crop(x, y, w, h)`(自动限幅)与 `pad(l, t, r, b, color)`(颜色边框),`crop∘pad` 可无损往返。
- **双边滤波**:`bilateral(radius, σs, σr)` 保边平滑——平坦区域降噪,强边缘保持锐利。
- **图像分析**:Otsu 自动阈值(类间方差最大化)、Floyd–Steinberg 误差扩散抖动、四连通连通域标记与计数、chamfer (3,4) 距离变换。
- **图像分析**:Otsu 自动阈值(类间方差最大化)、Floyd–Steinberg 误差扩散抖动、四连通连通域标记与计数、chamfer (3,4) 距离变换、感知哈希(aHash/dHash + 汉明距离)
- **积分图与 O(1) 盒式模糊**:`integral_image()` 求和面积表(Int64 防溢出)驱动 `box_blur(radius)`,任意半径每像素 O(1)。
- **泛洪填充**:`flood_fill(x, y, color, tolerance)` 四连通种子填充,逐通道容差。
- **图层合成**:`composite(top, mode)` Porter-Duff source-over + 8 种混合模式(正片叠底/滤色/叠加/变暗/变亮/差值/线性减淡等),纯整数舍入运算。
- **位图文字**:内置 5×7 字体(数字/大写字母/基本标点),`draw_text` 整数倍缩放、自动裁剪。
- **色彩空间**:RGB ↔ HSV、RGB ↔ YCbCr (BT.601) 精确往返转换。
- **通用卷积引擎**:`Kernel` + `Image::convolve`,可自定义任意奇数尺寸卷积核。
- **图像统计与色调**:`stats()` 逐通道 min/max/mean(Int64 累加)、`auto_contrast()` 自动对比度拉伸、`levels(black, white, gamma)` 色阶重映射。
- **纯整数、确定性**:滤镜数学尽量用整数(如亮度权重 ×1000),结果可复现、**147 个单元测试全部手算验证**(含 CRC-32/Adler-32 公开参考向量与手工汇编的 DEFLATE 位流)。
- **确定性噪声**:`add_gaussian_noise(seed, σ)` / `add_salt_pepper(seed, density)`,64 位 LCG 驱动,同 seed 跨后端逐字节一致。
- **纯整数、确定性**:滤镜数学尽量用整数(如亮度权重 ×1000),结果可复现、**163 个单元测试全部手算验证**(含 CRC-32/Adler-32 公开参考向量与手工汇编的 DEFLATE 位流)。
- **零依赖**:只用 `moonbitlang/core`,不引入任何第三方库。
- **多后端 + 零拷贝互操作**:js 后端下 `FixedArray[Byte]` 就是 `Uint8Array`,与 canvas 的 `Uint8ClampedArray` 零拷贝互通;线性内存 wasm 后端导出 `memory`,宿主直接批量读写像素。
- **浏览器 Playground**:拖拽 / 粘贴 / 上传图片,滤镜可叠加成管线,JS/WASM 引擎切换与性能对比,可切换到 **Web Worker 后台线程**处理大图不卡 UI,处理结果用**自家 `png_encode`** 一键下载 PNG。
Expand All @@ -62,6 +63,9 @@ pixelforge/
├── floodfill.mbt # 泛洪填充(四连通种子填充)
├── distance.mbt # chamfer (3,4) 距离变换
├── stats.mbt # 图像统计 / 自动对比度 / 色阶
├── bicubic.mbt # 双三次缩放(Catmull-Rom)
├── phash.mbt # 感知哈希(aHash/dHash + 汉明距离)
├── noise.mbt # 确定性噪声(高斯 / 椒盐,LCG)
├── bilateral.mbt # 双边滤波(保边平滑)
├── otsu.mbt # Otsu 自动阈值(类间方差最大化)
├── dither.mbt # Floyd–Steinberg 误差扩散抖动
Expand All @@ -75,7 +79,7 @@ pixelforge/
├── transform.mbt # 水平/垂直翻转、90° 旋转
├── resize.mbt # 最近邻/双线性缩放
├── dispatch.mbt # Image::apply_filter_id 统一派发(各绑定共用)
├── *_test.mbt # 147 个确定性测试(黑盒 + 白盒)
├── *_test.mbt # 163 个确定性测试(黑盒 + 白盒)
├── cmd/main/ # 原生 CLI 示例(moon run cmd/main)
├── cmd/ppm/ # PPM 图像输出示例(moon run cmd/ppm > edges.ppm)
├── cmd/showcase/ # 综合展示(绘图+文字+滤镜+PNG 往返自检)
Expand All @@ -93,7 +97,7 @@ pixelforge/
先安装 [MoonBit 工具链](https://www.moonbitlang.cn/download/)。

```bash
moon test # 运行 147 个单元测试
moon test # 运行 163 个单元测试
moon run cmd/main # 运行原生示例(生成图像并跑滤镜,打印校验和)
moon run cmd/showcase > showcase.ppm # 综合展示:绘图+文字+滤镜+PNG 往返自检
moon run cmd/ppm > edges.ppm # 生成一张 Sobel 边缘检测的 PPM 图片
Expand Down Expand Up @@ -162,7 +166,7 @@ let bytes = out.data // FixedArray[Byte],长度 = width*height*4
| 21 | Otsu 自动阈值 | `otsu()` | — |
| 22 | Floyd–Steinberg 抖动(二值) | `dither_mono()` | — |

> 会改变尺寸的变换不走 id 派发,直接调用库 API:`rotate90()`、`resize_nearest(w, h)`、`resize_bilinear(w, h)`。多参数 / 非图像→图像的 API 同理:`box_blur(radius)`、`flood_fill(x, y, color, tol)`、`distance_transform(t)`、`gaussian(radius)`、`unsharp_mask(radius, amount)`、`crop(x, y, w, h)`、`pad(l, t, r, b, color)`、`bilateral(radius, σs, σr)`、`dither_grayscale(levels)`/`dither_mono()`、`otsu_threshold()`、`label_components(t)`/`count_components(t)`、`composite(top, mode)`、`draw_text(...)`、`rotate(deg)`、`translate(dx, dy)`、`affine(t)`、`draw_line`/`draw_rect`/`draw_circle` 等绘图原语、`saturate(factor)`、`hue_rotate(deg)`、`erode()`/`dilate()`/`morph_open()`/`morph_close()`、`png_encode`/`png_decode`、`gif_decode`、`qoi_encode`/`qoi_decode`、`bmp_encode`/`bmp_decode`、`rgb_to_hsv` 等色彩空间函数。
> 会改变尺寸的变换不走 id 派发,直接调用库 API:`rotate90()`、`resize_nearest(w, h)`、`resize_bilinear(w, h)`、`resize_bicubic(w, h)`。多参数 / 非图像→图像的 API 同理:`average_hash()`/`difference_hash()`/`hamming_distance`、`add_gaussian_noise`/`add_salt_pepper`、`box_blur(radius)`、`flood_fill(x, y, color, tol)`、`distance_transform(t)`、`gaussian(radius)`、`unsharp_mask(radius, amount)`、`crop(x, y, w, h)`、`pad(l, t, r, b, color)`、`bilateral(radius, σs, σr)`、`dither_grayscale(levels)`/`dither_mono()`、`otsu_threshold()`、`label_components(t)`/`count_components(t)`、`composite(top, mode)`、`draw_text(...)`、`rotate(deg)`、`translate(dx, dy)`、`affine(t)`、`draw_line`/`draw_rect`/`draw_circle` 等绘图原语、`saturate(factor)`、`hue_rotate(deg)`、`erode()`/`dilate()`/`morph_open()`/`morph_close()`、`png_encode`/`png_decode`、`gif_decode`、`qoi_encode`/`qoi_decode`、`bmp_encode`/`bmp_decode`、`rgb_to_hsv` 等色彩空间函数。

## 🏗️ 架构与多后端

Expand All @@ -180,7 +184,7 @@ moon test # 默认后端(wasm-gc)
moon test --target js # js 后端
```

147 个测试覆盖每个滤镜、变换、绘图原语、合成模式、字体、分析算法与编解码器,期望值均为手工推导(脉冲响应、平场不变性、已知边缘、直方图重映射、编码字节精确长度、无损往返、CRC-32/Adler-32 公开参考向量、手工汇编的 DEFLATE 与 GIF LZW 位流等),在 wasm-gc 与 js 后端下均通过;GitHub Actions 持续集成。
163 个测试覆盖每个滤镜、变换、绘图原语、合成模式、字体、分析算法与编解码器,期望值均为手工推导(脉冲响应、平场不变性、已知边缘、直方图重映射、编码字节精确长度、无损往返、CRC-32/Adler-32 公开参考向量、手工汇编的 DEFLATE 与 GIF LZW 位流等),在 wasm-gc 与 js 后端下均通过;GitHub Actions 持续集成。

## 📮 发布到 mooncakes.io

Expand Down
2 changes: 1 addition & 1 deletion moon.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "0717lee/pixelforge"

version = "0.11.0"
version = "0.12.0"

readme = "README.md"

Expand Down
Loading