From 11661f5a7feef0f2b29b8fa5c97241f06f238fe8 Mon Sep 17 00:00:00 2001 From: Yonghun Yi Date: Mon, 9 Feb 2026 11:23:41 +0900 Subject: [PATCH 1/5] docs: clarify defaults, NaN sanitization, and error policy --- README.MD | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/README.MD b/README.MD index b0d81b4..2d96515 100644 --- a/README.MD +++ b/README.MD @@ -11,6 +11,8 @@ Demo: https://2yh02.github.io/img-toolkit - [Usage](#usage) - [Functions](#functions) - [Options](#options) +- [Defaults and Input Validation](#defaults-and-input-validation) +- [Error Handling Policy](#error-handling-policy) - [Quality Behavior](#quality-behavior) - [Quality Comparison](#quality-comparison) - [Vite Setup for WASM](#vite-setup-for-wasm) @@ -95,7 +97,7 @@ adjustBrightness(file: File, options: BrightnessOptions): Promise | ------------ | ------ | ------------------------------------------------------------------------------------------------- | | `width` | number | (Optional) Target width in pixels. If omitted, width is auto-adjusted. | | `height` | number | (Optional) Target height in pixels. If omitted, height is auto-adjusted. | -| `quality` | number | (Optional) 0.0 to 1.0. Effective for JPEG and WebP output. | +| `quality` | number | (Optional) 0.0 to 1.0. Effective for JPEG and WebP output. Defaults to `0.7`. Non-finite values (e.g. `NaN`) are sanitized to the default. | | `format` | string | Output format (`"jpg"`, `"png"`, `"webp"`). | | `brightness` | number | (Optional) 0.0 to 1.0. Defaults to 0.5. | | `resampling` | number | (Optional) 0 to 10. Defaults to 4. | @@ -107,22 +109,39 @@ adjustBrightness(file: File, options: BrightnessOptions): Promise | `width` | number | (Optional) Target width in pixels. | | `height` | number | (Optional) Target height in pixels. | | `resampling` | number | (Optional) 0 to 10. Defaults to 4. | -| `quality` | number | (Optional) 0.0 to 1.0. Effective if source is JPEG. | +| `quality` | number | (Optional) 0.0 to 1.0. Effective if source is JPEG. Defaults to `0.7`. Non-finite values are sanitized to the default. | ### `ConvertFormatOptions` | Option | Type | Description | | --------- | ------ | ------------------------------------------------------ | | `format` | string | Output format (`"jpg"`, `"png"`, `"webp"`). | -| `quality` | number | (Optional) 0.0 to 1.0. Effective for JPEG and WebP output. | +| `quality` | number | (Optional) 0.0 to 1.0. Effective for JPEG and WebP output. Defaults to `0.7`. Non-finite values are sanitized to the default. | ### `BrightnessOptions` | Option | Type | Description | | ------------ | ------ | --------------------------------------------------- | -| `brightness` | number | 0.0 to 1.0 | +| `brightness` | number | 0.0 to 1.0. Defaults to `0.5`. Non-finite values are sanitized to the default. | | `quality` | number | (Optional) 0.0 to 1.0. Effective if source is JPEG. | +## Defaults and Input Validation + +- `quality` defaults to `0.7` when omitted. +- `brightness` defaults to `0.5` when omitted. +- `resampling` defaults to `4` when omitted. +- `quality` and `brightness` are clamped to valid ranges (`0.0..1.0`), and non-finite values such as `NaN` / `Infinity` are sanitized to safe defaults. +- `resampling` is clamped to `0..10`, and non-finite values are sanitized to default. + +## Error Handling Policy + +- User-facing errors are intentionally generic and safe for client contexts. +- Internal low-level encoder/decoder details are logged internally and are not returned directly to API consumers. +- Typical user-facing messages include: + - `Invalid options` + - `Unsupported format` + - `Image processing failed` + ## Quality Behavior - `jpg` output: `quality` is applied. From 69a593404bf5a069280521af9ae9ea8961299738 Mon Sep 17 00:00:00 2001 From: Yonghun Yi Date: Mon, 9 Feb 2026 11:24:57 +0900 Subject: [PATCH 2/5] test(rust): cover no-dimension, decode-failure, and webp paths --- src/lib.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index ead3714..03bd07f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -356,6 +356,60 @@ mod tests { assert!(matches!(err, ToolkitError::UnsupportedFormat)); } + #[test] + fn resize_image_without_dimensions_keeps_original_size() { + let input = make_test_png(120, 80); + let options = ResizeOptions { + width: None, + height: None, + quality: None, + format: "png".to_string(), + brightness: 0.5, + resampling: 4, + }; + + let output = resize_image_with_options(&input, options).unwrap(); + let (format, decoded) = decode_image(&output); + + assert_eq!(format, ImageFormat::Png); + assert_eq!(decoded.dimensions(), (120, 80)); + } + + #[test] + fn resize_image_returns_decode_error_for_invalid_input_bytes() { + let input = vec![0x00, 0x11, 0x22, 0x33]; + let options = ResizeOptions { + width: Some(32), + height: Some(32), + quality: None, + format: "jpg".to_string(), + brightness: 0.5, + resampling: 4, + }; + + let err = resize_image_with_options(&input, options).unwrap_err(); + assert!(matches!(err, ToolkitError::DecodeFailed(_))); + } + + #[test] + fn resize_image_encodes_as_webp() { + let input = make_test_png(96, 64); + let options = ResizeOptions { + width: Some(48), + height: Some(32), + quality: Some(0.7), + format: "webp".to_string(), + brightness: 0.5, + resampling: 4, + }; + + let output = resize_image_with_options(&input, options).unwrap(); + let (format, decoded) = decode_image(&output); + + assert_eq!(format, ImageFormat::WebP); + assert_eq!(decoded.dimensions(), (48, 32)); + } + #[test] fn toolkit_error_user_messages_follow_exposure_policy() { assert_eq!(ToolkitError::InvalidOptions("x".to_string()).user_message(), "Invalid options"); From 2682e5e7dbbe088696f07a150e9802478042e147 Mon Sep 17 00:00:00 2001 From: Yonghun Yi Date: Thu, 12 Feb 2026 13:20:49 +0900 Subject: [PATCH 3/5] docs: add AGENTS guide --- AGENTS.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..6c6bea8 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,29 @@ +# AGENTS.md + +## Project Overview +`img-toolkit` is a Rust + WebAssembly image processing library published to npm. +The Rust core handles decode/transform/encode, and the TypeScript wrapper exposes the browser-facing API. + +## Key Files +- `src/lib.rs`: Rust/WASM core pipeline (option parsing, resize/brightness, format encode/decode, Rust tests). +- `ts-wrapper/resizeImage.ts`: TypeScript public API wrapper used by app code. +- `example/imageWorker.js`: Worker-side integration example for async image processing. +- `Cargo.toml`: Rust crate config and dependencies. +- `package.json`: npm package metadata, scripts, and build entrypoints. +- `README.MD`: user-facing API docs and usage examples; update when behavior/API changes. + +## Common Commands +- `cargo test`: run Rust unit tests for core behavior. +- `npm run build:wasm`: build wasm artifacts from Rust (`wasm-pack build --target web`). +- `npm run build:ts`: compile TypeScript wrapper/types. +- `npm run build`: full package build (`build:wasm` + `build:ts`). + +Run the smallest relevant command first, then run the full build before final handoff. + +## Working Rules +- Preserve 2.x API compatibility unless a breaking change is explicitly requested. +- Keep user-facing errors safe and generic; avoid exposing low-level internals. +- Validate/sanitize options (clamp ranges, handle non-finite values). +- Do not remove `jpg/jpeg`, `png`, or `webp` support unless explicitly requested. +- Keep changes focused; avoid unrelated refactors. +- If API/default behavior changes, update `README.MD` and relevant examples in `example/`. From 607a0d35005a034faa9a7de29d4f754b4a8df4dc Mon Sep 17 00:00:00 2001 From: Yonghun Yi Date: Thu, 12 Feb 2026 13:51:23 +0900 Subject: [PATCH 4/5] test: allow format guess failure in invalid bytes case --- src/lib.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 03bd07f..912f493 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -388,7 +388,12 @@ mod tests { }; let err = resize_image_with_options(&input, options).unwrap_err(); - assert!(matches!(err, ToolkitError::DecodeFailed(_))); + assert!( + matches!( + err, + ToolkitError::FormatGuessFailed(_) | ToolkitError::DecodeFailed(_) + ) + ); } #[test] From 75dd5963d831d9ff0e40f96bee6507331fd8121e Mon Sep 17 00:00:00 2001 From: Yonghun Yi Date: Thu, 12 Feb 2026 13:53:58 +0900 Subject: [PATCH 5/5] fix(ts): make BrightnessOptions.brightness optional --- ts-wrapper/resizeImage.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ts-wrapper/resizeImage.ts b/ts-wrapper/resizeImage.ts index 59c7f75..87175f3 100644 --- a/ts-wrapper/resizeImage.ts +++ b/ts-wrapper/resizeImage.ts @@ -35,7 +35,7 @@ export type ConvertFormatOptions = { }; export type BrightnessOptions = { - brightness: number; + brightness?: number; /** * 0.0 to 1.0. Effective when the source image is JPEG. */