Skip to content

refactor(api)!: remove draw_contour_borders from labels_to_svg#283

Merged
Ryan-Millard merged 9 commits into
mainfrom
refactor!/api/labels_to_svg
Apr 9, 2026
Merged

refactor(api)!: remove draw_contour_borders from labels_to_svg#283
Ryan-Millard merged 9 commits into
mainfrom
refactor!/api/labels_to_svg

Conversation

@Ryan-Millard
Copy link
Copy Markdown
Owner

@Ryan-Millard Ryan-Millard commented Mar 25, 2026

What was changed & why

The labels_to_svg function signature has changed. It now marks more arguments as const and removes draw_contour_borders.

This is important as it ensures all the function has a single responsibility: vectorize labels.

Fixes: none

Changes

Entire API around labels_to_svg.

Testing & Verification

It runs and builds fine.

Additional Resources

  • BREAKING CHANGE: labels_to_svg signature changed; contour border visualization support has been removed across all bindings.
  • Affected scope: C, C++, JS

Summary by CodeRabbit

  • Breaking Changes

    • Removed the draw_contour_borders option from contour-to-SVG APIs.
    • Input pixel and label buffers are now read-only (const).
    • SVG is always produced; functions no longer modify input pixel buffers with recoloring.
  • Documentation

    • Updated docs, examples, and JS wrappers to reflect the removed parameter and read-only buffer behavior.

@github-actions github-actions Bot added documentation Improvements or additions to documentation c/cpp Changes to C or C++ files js/ts labels Mar 25, 2026
@Ryan-Millard Ryan-Millard marked this pull request as draft March 25, 2026 21:32
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 25, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Removed the draw_contour_borders flag from labels-to-SVG APIs across core, C bindings, JS/WASM, and examples; made data and labels pointer parameters const; and made SVG generation unconditional, always returning a malloc'd C string.

Changes

Cohort / File(s) Summary
Core API & Impl
core/include/img2num.h, core/src/internal/labels_to_svg.cpp
labels_to_svg signature: data and labels become const pointers and draw_contour_borders removed. Implementation no longer writes recolored pixels back to data; it always generates and returns a malloc'd SVG C string.
C API Headers & Impl
bindings/c/include/cimg2num.h, bindings/c/src/cimg2num.cpp
Exported C binding signature updated to const uint8_t *data, const int32_t *labels and to drop draw_contour_borders; wrapper lambda and internal invocation updated to match.
JS/WASM Bindings & JS Wrapper
bindings/js/src/wasm_wrapper.cpp, packages/js/safeWasmWrappers.js
WASM-exposed labels_to_svg and JS findContours signatures no longer accept draw_contour_borders; calls forward only (pixels, labels, width, height, min_area).
Examples
example-apps/console-c/main.c, example-apps/console-cpp/main.cpp
Updated calls to remove the final boolean argument from img2num_labels_to_svg / labels_to_svg; added proper error/cleanup and freed SVG in C example; removed repeat loop in C++ example.
Docs & Doxygen
docs/docs/internal/packages/js/index.md, doxygen/img2num.h.dox
Documentation and Doxygen examples updated to remove draw_contour_borders parameter from examples and comments.

Sequence Diagram(s)

sequenceDiagram
  rect rgba(200,200,255,0.5)
  participant JS as JS caller
  end
  rect rgba(200,255,200,0.5)
  participant WASM as WASM wrapper
  end
  rect rgba(255,200,200,0.5)
  participant C as C binding
  end
  participant Core as img2num core
  JS->>WASM: findContours(pixels, labels, width, height, min_area)
  WASM->>C: labels_to_svg(pixels, labels, width, height, min_area)
  C->>Core: labels_to_svg(const data, const labels, width, height, min_area)
  Core-->>C: malloc'd SVG char*
  C-->>WASM: SVG char*
  WASM-->>JS: { svg, visualization }
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

docs

Poem

🐇 I nibble through code, neat and sly,
No border switch left to try,
Inputs held steady, constant and true,
SVGs hop back, freshly new,
A happy rabbit hums adieu.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and directly summarizes the main breaking change: removing the draw_contour_borders parameter from labels_to_svg across all bindings.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor!/api/labels_to_svg

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Ryan-Millard Ryan-Millard force-pushed the refactor!/api/labels_to_svg branch from 7c87bb0 to 76783ff Compare March 25, 2026 21:33
- BREAKING CHANGE: labels_to_svg signature changed; contour border visualization support has been removed across all bindings.
- Affected scope: C, C++, JS
@Ryan-Millard Ryan-Millard force-pushed the refactor!/api/labels_to_svg branch from 76783ff to 25ca61c Compare March 25, 2026 21:33
@Ryan-Millard Ryan-Millard marked this pull request as ready for review April 1, 2026 23:38
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
core/src/internal/labels_to_svg.cpp (1)

212-220: ⚠️ Potential issue | 🟠 Major

Dead code: results image is computed but never used.

The results image is populated with recolored pixels, but since data is now const, the old code that copied results back into data was removed. This results variable is now computed but:

  1. Never returned
  2. Cannot be written to data (const)
  3. Goes out of scope at function end

This means the JS wrapper's visualization output will just return the original unmodified pixel data, not the recolored visualization.

If visualization is intentionally being removed (consistent with removing draw_contour_borders), this code block should be deleted to avoid confusion:

🔧 Option A: Remove dead code if visualization is no longer needed
-    // 5. recolor image on new regions
-    ImageLib::Image<ImageLib::RGBAPixel<uint8_t>> results{width, height};
-    for (auto &n : G.get_nodes()) {
-        if (n->area() == 0) continue;
-
-        auto [r, g, b] = n->color();
-        for (auto &[_, p] : n->get_pixels()) {
-            results(p.x, p.y) = {r, g, b};
-        }
-    }

If visualization should still work, consider adding an output parameter or changing the return type.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/src/internal/labels_to_svg.cpp` around lines 212 - 220, The block
building the ImageLib::Image<ImageLib::RGBAPixel<uint8_t>> results is dead
because results is never returned or written back into the now-const data;
either remove the entire loop (delete results and the loop over G.get_nodes(),
references to n->color() and n->get_pixels()) if visualization is intentionally
removed, or restore visualization by exposing a writable output (e.g., change
the function return or add an output parameter) and copy results into that
output instead of writing to const data; locate the code using symbols results,
G.get_nodes(), n->color(), and n->get_pixels() and apply one of these two fixes
consistently (also align with removal of draw_contour_borders).
🧹 Nitpick comments (2)
packages/js/safeWasmWrappers.js (1)

187-192: JSDoc describes "optional" visualization, but the option was removed.

The @returns description says "optionally pixels with visualized contours" and @variation says "optional visualization", but the draw_contour_borders parameter that controlled this behavior has been removed. The visualization output is now always populated with recolored pixels.

📝 Suggested fix
-* `@returns` {Promise<{svg: string, visualization: Uint8ClampedArray}>} Generated SVG and optionally pixels with visualized contours.
+* `@returns` {Promise<{svg: string, visualization: Uint8ClampedArray}>} Generated SVG and recolored pixels.
 * `@throws` {Error} If the WASM function fails or input labels are invalid.
 * `@example`
 * const { svg, visualization } = await findContours({ pixels, labels, width, height });
 * `@todo` Support additional visualization options like color-coded regions.
-* `@variation` Contour extraction with optional visualization
+* `@variation` Contour extraction with visualization
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/js/safeWasmWrappers.js` around lines 187 - 192, Update the JSDoc for
findContours in safeWasmWrappers.js to reflect that visualization is always
returned: remove references to "optionally" and "@variation" mentioning optional
visualization, delete any mention of the removed parameter draw_contour_borders,
and change the `@returns` description to state that both svg and visualization
(recolored pixels) are always provided; ensure the `@throws/`@example remain valid
and adjust the `@todo` if it implied optional visualization.
bindings/js/src/wasm_wrapper.cpp (1)

36-39: Consider adding const to match the C API signature.

The wrapper parameters data and labels are non-const, but img2num_labels_to_svg now expects const uint8_t* and const int32_t*. While this works (implicit conversion), matching the const-qualification would improve consistency across the API surface.

♻️ Optional: align const-qualification
-EMSCRIPTEN_KEEPALIVE char *labels_to_svg(uint8_t *data, int32_t *labels, const int width,
+EMSCRIPTEN_KEEPALIVE char *labels_to_svg(const uint8_t *data, const int32_t *labels, const int width,
                                          const int height, const int min_area) {
     return img2num_labels_to_svg(data, labels, width, height, min_area);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bindings/js/src/wasm_wrapper.cpp` around lines 36 - 39, Update the
EMSCRIPTEN_KEEPALIVE wrapper function labels_to_svg so its parameter
const-qualification matches the underlying API: change the types of data and
labels to const uint8_t* and const int32_t* respectively in the labels_to_svg
signature and then forward them unchanged to img2num_labels_to_svg; this keeps
the wrapper consistent with img2num_labels_to_svg's signature and avoids
implicit non-const-to-const conversions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/docs/internal/packages/js/index.md`:
- Around line 132-136: The documentation snippet uses an invalid
function-call-like expression inside the args block; update the example so args
is a proper object containing the properties pixels, labels, width, height, and
min_area (e.g., args: { pixels, labels, width, height, min_area }) rather than
(pixels, labels, width, height, min_area); — edit the code block under the args
example (look for the args: { ... } block) and replace the parenthesized
expression with the comma-separated property list.

---

Outside diff comments:
In `@core/src/internal/labels_to_svg.cpp`:
- Around line 212-220: The block building the
ImageLib::Image<ImageLib::RGBAPixel<uint8_t>> results is dead because results is
never returned or written back into the now-const data; either remove the entire
loop (delete results and the loop over G.get_nodes(), references to n->color()
and n->get_pixels()) if visualization is intentionally removed, or restore
visualization by exposing a writable output (e.g., change the function return or
add an output parameter) and copy results into that output instead of writing to
const data; locate the code using symbols results, G.get_nodes(), n->color(),
and n->get_pixels() and apply one of these two fixes consistently (also align
with removal of draw_contour_borders).

---

Nitpick comments:
In `@bindings/js/src/wasm_wrapper.cpp`:
- Around line 36-39: Update the EMSCRIPTEN_KEEPALIVE wrapper function
labels_to_svg so its parameter const-qualification matches the underlying API:
change the types of data and labels to const uint8_t* and const int32_t*
respectively in the labels_to_svg signature and then forward them unchanged to
img2num_labels_to_svg; this keeps the wrapper consistent with
img2num_labels_to_svg's signature and avoids implicit non-const-to-const
conversions.

In `@packages/js/safeWasmWrappers.js`:
- Around line 187-192: Update the JSDoc for findContours in safeWasmWrappers.js
to reflect that visualization is always returned: remove references to
"optionally" and "@variation" mentioning optional visualization, delete any
mention of the removed parameter draw_contour_borders, and change the `@returns`
description to state that both svg and visualization (recolored pixels) are
always provided; ensure the `@throws/`@example remain valid and adjust the `@todo`
if it implied optional visualization.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2ee38b33-d510-4d61-bcb7-e077d0420560

📥 Commits

Reviewing files that changed from the base of the PR and between f859f62 and 29e34bb.

📒 Files selected for processing (8)
  • bindings/c/include/cimg2num.h
  • bindings/c/src/cimg2num.cpp
  • bindings/js/src/wasm_wrapper.cpp
  • core/include/img2num.h
  • core/src/internal/labels_to_svg.cpp
  • docs/docs/internal/packages/js/index.md
  • doxygen/img2num.h.dox
  • packages/js/safeWasmWrappers.js
💤 Files with no reviewable changes (1)
  • doxygen/img2num.h.dox

Comment thread docs/docs/internal/packages/js/index.md
@github-actions github-actions Bot added the docs label Apr 3, 2026
@Ryan-Millard Ryan-Millard removed the js/ts label Apr 4, 2026
@github-actions github-actions Bot added the js/ts label Apr 5, 2026
@Ryan-Millard Ryan-Millard requested a review from Krasner April 5, 2026 23:03
@Ryan-Millard
Copy link
Copy Markdown
Owner Author

@Krasner, please have a look at this. This PR just removes the draw_contour_borders option from the list since it is not related to vectorization.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
example-apps/console-c/main.c (1)

94-94: ⚠️ Potential issue | 🔴 Critical

Use assignment, not comparison, in the fopen error path.

Line 94 uses == instead of =, so exit_code is never set on file-open failure.

Proposed fix
-        exit_code == 1;
+        exit_code = 1;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@example-apps/console-c/main.c` at line 94, The fopen error path currently
uses a comparison instead of an assignment (exit_code == 1), so exit_code is
never set; change that to an assignment (exit_code = 1) in the error handling
branch where fopen fails, ensuring the variable exit_code is updated before
returning/exiting from main or the surrounding function that handles file open
errors.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@example-apps/console-c/main.c`:
- Line 77: The call to img2num_labels_to_svg may return NULL (res_svg) but the
code writes it with fputs unguarded; add a NULL check after the call to
img2num_labels_to_svg (check res_svg != NULL) and handle the failure before
calling fputs/printf or fclose: log or print an error, skip writing the SVG, and
ensure any allocated resources (img_data, out_labels, file handles) are still
cleaned up; specifically guard the use of res_svg where it’s passed to fputs and
free the buffer (or avoid fputs) only if res_svg is non-NULL.

---

Outside diff comments:
In `@example-apps/console-c/main.c`:
- Line 94: The fopen error path currently uses a comparison instead of an
assignment (exit_code == 1), so exit_code is never set; change that to an
assignment (exit_code = 1) in the error handling branch where fopen fails,
ensuring the variable exit_code is updated before returning/exiting from main or
the surrounding function that handles file open errors.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d97df2ac-b9f5-4c5f-893a-51fdb3dab472

📥 Commits

Reviewing files that changed from the base of the PR and between cd971d2 and 6e8a95a.

📒 Files selected for processing (2)
  • example-apps/console-c/main.c
  • example-apps/console-cpp/main.cpp

Comment thread example-apps/console-c/main.c Outdated
@Ryan-Millard Ryan-Millard removed the docs label Apr 5, 2026
@github-actions github-actions Bot added example-app Updates to code related to demonstration (example) applications core docs labels Apr 7, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
example-apps/console-cpp/main.cpp (2)

55-57: Remove commented-out dead code.

The commented-out allocation on line 56 is redundant since img_data is already allocated at line 49. This appears to be leftover from the refactor.

🧹 Proposed fix
     // Allocate a copy of the original image
-    // uint8_t* img_data{new uint8_t[width * height * NUM_CHANNELS]};
     std::memcpy(img_data, image_data_original, static_cast<size_t>(width) * static_cast<size_t>(height) * NUM_CHANNELS);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@example-apps/console-cpp/main.cpp` around lines 55 - 57, Remove the dead
commented-out allocation statement "uint8_t* img_data{new uint8_t[width * height
* NUM_CHANNELS]};"—it is redundant because img_data is already allocated earlier
(see img_data) and the subsequent std::memcpy uses image_data_original and
NUM_CHANNELS; simply delete that commented line to clean up the code.

24-24: Remove unused MAX_ITER constant.

This constant is no longer used after the iteration loop was removed.

🧹 Proposed fix
 constexpr int NUM_CHANNELS{4};
 constexpr double SIGMA_WIDTH_RATIO{0.005};
-constexpr int MAX_ITER{100};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@example-apps/console-cpp/main.cpp` at line 24, Remove the now-unused constant
MAX_ITER from the file by deleting the declaration "constexpr int
MAX_ITER{100};" (referenced symbol: MAX_ITER) in main (main.cpp); ensure no
remaining references to MAX_ITER exist and run a build to confirm nothing else
depends on it.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@example-apps/console-cpp/main.cpp`:
- Line 65: The call to img2num::labels_to_svg can return nullptr on allocation
failure but res_svg is used unguarded when writing to svgFile; add a null check
after char* res_svg{...} and handle the failure path (e.g., log an
error/throw/return non-zero) before using svgFile << res_svg, and ensure any
allocated res_svg is freed when successful; reference res_svg,
img2num::labels_to_svg, and svgFile to locate the code to change.

---

Nitpick comments:
In `@example-apps/console-cpp/main.cpp`:
- Around line 55-57: Remove the dead commented-out allocation statement
"uint8_t* img_data{new uint8_t[width * height * NUM_CHANNELS]};"—it is redundant
because img_data is already allocated earlier (see img_data) and the subsequent
std::memcpy uses image_data_original and NUM_CHANNELS; simply delete that
commented line to clean up the code.
- Line 24: Remove the now-unused constant MAX_ITER from the file by deleting the
declaration "constexpr int MAX_ITER{100};" (referenced symbol: MAX_ITER) in main
(main.cpp); ensure no remaining references to MAX_ITER exist and run a build to
confirm nothing else depends on it.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 34d24b20-24df-4aa5-8bc3-6030cf741995

📥 Commits

Reviewing files that changed from the base of the PR and between 5b0e9ad and 64ced44.

📒 Files selected for processing (2)
  • example-apps/console-c/main.c
  • example-apps/console-cpp/main.cpp
🚧 Files skipped from review as they are similar to previous changes (1)
  • example-apps/console-c/main.c

Comment thread example-apps/console-cpp/main.cpp
…emory management

- check for NULL return from labels_to_svg
- fix assignment bug (== → =) when setting exit_code
- free res_svg after use in C example to avoid memory leak
- simplify C++ example by removing unnecessary loop and redundant reallocations
- ensure proper ownership and cleanup of SVG buffer in C++ example
@Ryan-Millard Ryan-Millard force-pushed the refactor!/api/labels_to_svg branch from 64ced44 to 22fe897 Compare April 7, 2026 21:38
@Ryan-Millard Ryan-Millard merged commit eee9b31 into main Apr 9, 2026
14 checks passed
@Ryan-Millard Ryan-Millard deleted the refactor!/api/labels_to_svg branch April 9, 2026 11:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c/cpp Changes to C or C++ files core docs documentation Improvements or additions to documentation example-app Updates to code related to demonstration (example) applications js/ts

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant