Skip to content

PDFium CMYK setters, CMYK JPEG images, ICC output intents and vector recolour - #165

Open
balazs-szucs wants to merge 6 commits into
Stirling-Tools:mainfrom
balazs-szucs:feat/cmyk-color-pipeline
Open

balazs-szucs wants to merge 6 commits into
Stirling-Tools:mainfrom
balazs-szucs:feat/cmyk-color-pipeline

Conversation

@balazs-szucs

Copy link
Copy Markdown
Collaborator

No description provided.

@coderabbitai

coderabbitai Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

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
📝 Summary

Summary by CodeRabbit

  • New Features

    • Added CMYK color conversion tools for supported PDF content, including vector graphics, forms, and eligible images. Availability depends on the PDFium build; unsupported builds report the capability as unavailable.
    • Added PDF/X-3 and PDF/X-4 metadata application with ICC output intents. Applying metadata does not certify PDF/X compliance.
    • Added PDF recoloring options for inversion, tinting, high contrast, and binarization.
    • Added configurable image quality, ICC profiles, black extraction, and strict conversion handling.
    • Added a bundled generic CMYK profile for use when applying output-intent metadata.
  • Documentation

    • Added guidance on color conversion, output intents, PDF/X metadata, build-dependent support, and recoloring behavior.

The change adds DeviceCMYK conversion for vector colors and eligible images, ICC output-intent and PDF/X metadata operations, and vector recoloring utilities. It also updates form-field cleanup bindings, PDFium build patches, capability checks, tests, and documentation.

Changes: CMYK conversion and PDF/X pipeline

Layer / File(s) Summary
Native CMYK contracts and encoder
native/CMakeLists.txt, native/setup-pdfium.sh, native/bridge/include/*, native/bridge/src/*, native/rust/jpdfium-impl/*, reachability-metadata/*, NOTICE, native/licenses/NOTICE.txt
Adds optional native CMYK APIs, PDFium capability probes, and a Rust CMYK JPEG encoder. PDFium patches add color, form, and image-transparency APIs.
Java CMYK conversion and ICC transforms
jpdfium/src/main/java/stirling/software/jpdfium/doc/{IccCmykTransform,PdfColorConverter,PdfIccProfiles}.java, jpdfium/src/main/java/stirling/software/jpdfium/panama/ColorBindings.java, jpdfium/src/main/java/stirling/software/jpdfium/panama/PageEditBindings.java, jpdfium/src/test/java/stirling/software/jpdfium/doc/{IccCmykTransformTest,PdfImageLosslessTest,PdfBinaryFreeApiTest}.java, native/bridge/tests/smoke.cpp, jpdfium/build.gradle.kts
Adds ICC-based CMYK conversion, image conversion, recursive form traversal, capability reporting, and configurable conversion options. Tests cover ICC validation, image conversion, and capability-dependent behavior.
ICC output intents and PDF/X metadata
native/bridge/src/jpdfium_color.cpp, jpdfium/src/main/java/stirling/software/jpdfium/doc/{PdfIccProfiles,PdfOutputIntent,PdfXConverter,PdfXOptions,PdfXStandard}.java, native/tools/gen_compact_icc.c, jpdfium/src/main/resources/icc/*, jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfxMetadataSafetyTest.java, docs/*, NOTICE
Adds output-intent writing and PDF/X metadata bootstrapping. Java APIs provide profile, standard, options, conversion, and metadata-check operations. The change also adds a compact CMYK profile generator and documentation.

PDF object recoloring

Layer / File(s) Summary
Recoloring operations and documentation
jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfRecolor.java, docs/editing.md
Adds inversion, tinting, high contrast, and binarization for top-level text and path objects. Operations preserve alpha and skip unsupported color spaces. Documentation describes the supported operations and limitations.

Form-field cleanup

Layer / File(s) Summary
Field clearing and widget redraw
jpdfium/src/main/java/stirling/software/jpdfium/panama/FormFillBindings.java, jpdfium/src/main/java/stirling/software/jpdfium/transform/PdfPageGeometry.java
Adds optional field-value clearing and widget-redraw bindings. Unplaced-field cleanup prefers the new setter and retains the legacy reset fallback.

Priority: ➖ Normal

Merge Risk: 🟡 Moderate · up to af097

Untrusted PDF metadata with deep XML nesting can crash the process, and stroke colour conversion inside form XObjects can be lost, leaving RGB content in a CMYK or PDF/X output. Fix these two issues before merging; the remaining items are smaller follow-ups.

Pre-merge checks: Passed 3 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Description check Warning No pull request description was provided. The required change summary and checklist sections are missing. Add a description with a “Description of Changes” section explaining what changed and why. Complete the General, Library changes, Native or FFM changes, and Testing checklist items, including test and build results and any applicable issue …
Passed Passed checks: 3 passed
Check name Status Explanation
Title check Passed The title clearly summarizes the primary changes: PDFium CMYK setters, CMYK JPEG image support, ICC output intents, and vector recoloring.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Resolution

Add a description with a “Description of Changes” section explaining what changed and why. Complete the General, Library changes, Native or FFM changes, and Testing checklist items, including test and build results and any applicable issue or changelog references.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@balazs-szucs balazs-szucs changed the title Add DeviceCMYK colour pipeline: PDFium CMYK setters, CMYK JPEG images, ICC output intents and vector recolour PDFium CMYK setters, CMYK JPEG images, ICC output intents and vector recolour Oct 14, 2026
@balazs-szucs
balazs-szucs force-pushed the feat/cmyk-color-pipeline branch 2 times, most recently from 31e61dc to 35a6644 Compare October 14, 2026 12:35
@balazs-szucs
balazs-szucs requested a review from a team October 14, 2026 12:35
coderabbitai[bot]

This comment was marked as resolved.

@balazs-szucs
balazs-szucs force-pushed the feat/cmyk-color-pipeline branch 3 times, most recently from 3986f02 to af1d011 Compare October 14, 2026 15:36
Comment thread native/bridge/src/jpdfium_color.cpp Fixed
coderabbitai[bot]

This comment was marked as resolved.

@balazs-szucs
balazs-szucs force-pushed the feat/cmyk-color-pipeline branch from af1d011 to 51aace1 Compare October 14, 2026 15:49
Comment thread native/bridge/src/jpdfium_color.cpp Fixed
@balazs-szucs
balazs-szucs force-pushed the feat/cmyk-color-pipeline branch from 51aace1 to 3be4f33 Compare October 14, 2026 16:39
@balazs-szucs

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
✅ Action performed

Full review finished.

coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

Comment on lines +309 to +310
int ignored = (int) FormFillBindings.EPDFForm_RedrawFieldWidgets.invokeExact(
rawDoc, objNum, MemorySegment.NULL, 0L, MemorySegment.NULL);
Comment on lines +315 to +316
int ignored = (int) FormFillBindings.EPDFForm_ResetField.invokeExact(rawDoc, objNum,
MemorySegment.NULL, 0L, MemorySegment.NULL);
@balazs-szucs
balazs-szucs force-pushed the feat/cmyk-color-pipeline branch from 253efd4 to b626b59 Compare October 20, 2026 17:39
@balazs-szucs

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
✅ Action performed

Full review finished.

coderabbitai[bot]

This comment was marked as resolved.

@balazs-szucs

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
✅ Action performed

Full review finished.

coderabbitai[bot]

This comment was marked as resolved.

@balazs-szucs

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
✅ Action performed

Full review finished.

coderabbitai[bot]

This comment was marked as resolved.

@balazs-szucs
balazs-szucs force-pushed the feat/cmyk-color-pipeline branch from c61972e to c1f4528 Compare October 21, 2026 08:40
@balazs-szucs

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

♻️ Duplicate comments: 1
native/setup-pdfium.sh: 1

878-879: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

The metadata patch still uses slash-prefixed keys, so it copies no keys.

A past review comment flagged this, and the comment is marked "Addressed in commit 5dff0bd". Lines 878-879 still contain "/OC", "/Intent" and the other slash-prefixed keys.

  • CPDF_Dictionary stores keys without the leading /. Line 915 in this same script uses dict->KeyExist("SMask"), which follows that rule.
  • Because of the slash, old_dict->KeyExist(key) is always false. EPDFImageObj_SetJpeg then drops /OC, /Intent, /Interpolate and /Metadata.
  • Consequence: if an image belongs to an optional-content group, it becomes always visible after CMYK conversion. The script still prints "Patched ... to preserve image metadata".
  • /Alternate is not an image XObject key. The correct key is Alternates.
  • /Matte belongs to the SMask dictionary, not to the base image dictionary.

Line 859 checks for the text JPDFium: preserve image metadata. That text is already in trees patched by the broken version. If you fix only the key list, those trees keep the broken code until someone runs --clean. Change the marker text so the fixed patch replaces the old one, or detect the old slash form and fail.

Proposed fix
-        for (const char* key : {"/OC", "/Intent", "/Interpolate", "/Name",
-                                "/Metadata", "/Alternate", "/Matte"}) {
+        for (const char* key : {"OC", "Intent", "Interpolate", "Name",
+                                "Metadata", "Alternates"}) {

Add a regression test: convert an image that has /OC, reopen the saved PDF, and assert that /OC is still present.


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository: Stirling-Tools/JPDFium/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: afd04c9c-f7d1-4056-8c62-f4566a5f137c
📥 Commits

Reviewing files that changed from the base of the PR and between 5a35fef and c1f4528.

⛔ Files ignored due to path filters: 1
  • native/rust/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing: 36
  • .editorconfig-checker.json
  • .gitattributes
  • NOTICE
  • docs/README.md
  • docs/color-pipeline.md
  • docs/editing.md
  • jpdfium/build.gradle.kts
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/IccCmykTransform.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfColorConverter.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfIccProfiles.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfOutputIntent.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfRecolor.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXConverter.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXOptions.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXStandard.java
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/ColorBindings.java
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/FormFillBindings.java
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/PageEditBindings.java
  • jpdfium/src/main/java/stirling/software/jpdfium/transform/PdfPageGeometry.java
  • jpdfium/src/main/resources/META-INF/native-image/com.stirling/jpdfium/reachability-metadata.json
  • jpdfium/src/main/resources/icc/JPDFiumCompactCmyk.NOTICE.txt
  • jpdfium/src/main/resources/icc/JPDFiumCompactCmyk.icc
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfBinaryFreeApiTest.java
  • native/CMakeLists.txt
  • native/bridge/include/jpdfium.h
  • native/bridge/include/jpdfium_rust.h
  • native/bridge/jpdfium.def
  • native/bridge/src/jpdfium_color.cpp
  • native/bridge/src/jpdfium_stub.cpp
  • native/bridge/tests/smoke.cpp
  • native/licenses/NOTICE.txt
  • native/rust/jpdfium-impl/Cargo.toml
  • native/rust/jpdfium-impl/src/lib.rs
  • native/setup-pdfium.sh
  • native/tools/gen_compact_icc.c
  • reachability-metadata/metadata/com.stirling/jpdfium/1.2.0/reachability-metadata.json

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

📜 Review details
🧰 Additional context used
📚 Code guidelines: 1
.github/CODERABBIT_REVIEW.md — configured
📓 Path-based instructions: 5
Apply the native ownership, C ABI, C++23, engine integration, memory, and SIMD rules from .github/CODERABBIT_REVIEW.md.

⚙️ CodeRabbit configuration file

Files:

  • native/bridge/tests/smoke.cpp
  • native/bridge/src/jpdfium_stub.cpp
  • native/bridge/include/jpdfium_rust.h
  • native/bridge/include/jpdfium.h
  • native/tools/gen_compact_icc.c
  • native/bridge/src/jpdfium_color.cpp
Check target-scoped flags, exported ABI, reproducibility, sanitizer instrumentation, dependency compatibility, and portable CPU targets.

⚙️ CodeRabbit configuration file

Files:

  • native/CMakeLists.txt
Enforce meaningful assertions, deterministic concurrency, failure-path cleanup, and explicit native/stub requirements.

⚙️ CodeRabbit configuration file

Files:

  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfBinaryFreeApiTest.java
Apply the Java 25 and FFM rules from .github/CODERABBIT_REVIEW.md.

⚙️ CodeRabbit configuration file

Files:

  • jpdfium/src/main/java/stirling/software/jpdfium/panama/FormFillBindings.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfIccProfiles.java
  • jpdfium/src/main/java/stirling/software/jpdfium/transform/PdfPageGeometry.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXStandard.java
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/PageEditBindings.java
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfBinaryFreeApiTest.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfRecolor.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/IccCmykTransform.java
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/ColorBindings.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXOptions.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfOutputIntent.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXConverter.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfColorConverter.java
Source excerpt: Use imports rather than package-qualified type names in method bodies and signatures.

📄 CodeRabbit inference engine (.github/CODERABBIT_REVIEW.md)

Files:

  • docs/README.md
  • native/rust/jpdfium-impl/Cargo.toml
  • jpdfium/build.gradle.kts
  • native/bridge/jpdfium.def
  • NOTICE
  • reachability-metadata/metadata/com.stirling/jpdfium/1.2.0/reachability-metadata.json
  • native/bridge/tests/smoke.cpp
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/FormFillBindings.java
  • jpdfium/src/main/resources/icc/JPDFiumCompactCmyk.NOTICE.txt
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfIccProfiles.java
  • jpdfium/src/main/java/stirling/software/jpdfium/transform/PdfPageGeometry.java
  • native/licenses/NOTICE.txt
  • native/bridge/src/jpdfium_stub.cpp
  • jpdfium/src/main/resources/META-INF/native-image/com.stirling/jpdfium/reachability-metadata.json
  • native/bridge/include/jpdfium_rust.h
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXStandard.java
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/PageEditBindings.java
  • docs/editing.md
  • docs/color-pipeline.md
  • native/CMakeLists.txt
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfBinaryFreeApiTest.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfRecolor.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/IccCmykTransform.java
  • native/bridge/include/jpdfium.h
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/ColorBindings.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXOptions.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfOutputIntent.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXConverter.java
  • native/rust/jpdfium-impl/src/lib.rs
  • native/tools/gen_compact_icc.c
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfColorConverter.java
  • native/setup-pdfium.sh
  • native/bridge/src/jpdfium_color.cpp
🪛 GitHub Check: CodeQL
jpdfium/src/main/java/stirling/software/jpdfium/transform/PdfPageGeometry.java

[notice] 309-310: Unread local variable
Variable 'int ignored' is never read.


[notice] 315-316: Unread local variable
Variable 'int ignored' is never read.

🪛 LanguageTool
docs/color-pipeline.md

[uncategorized] ~82-~82: The official name of this software platform is spelled with a capital “H”.
Context: ...s future work. 4. Ghent gate in CI. .github/workflows/ghent.yml builds the patched...

(GITHUB)

🔇 Additional comments: 50
jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfRecolor.java: 6

288-291: Fix the narrowing cast in stretch before the clamp.

Math.round(double) returns a long. The code casts it to int before Math.clamp, so a large factor truncates to arbitrary bits first. For v > 128 and factor = +Infinity, the result is 0 instead of 255. NaN also yields 0, which is wrong for most inputs.

Pass the long to Math.clamp(long, int, int) directly. Also validate that contrastFactor is finite in the builder (Line 321).

This is a prior finding. The current code still has the narrowing cast. It is a duplicate of the earlier review comment on stretch, and the part about narrowing is still open.

Proposed fix
-            return Math.clamp((int) Math.round(centred), 0, 255);
+            return Math.clamp(Math.round(centred), 0, 255);
-            public Builder contrastFactor(double f) { this.contrastFactor = f; return this; }
+            public Builder contrastFactor(double f) {
+                if (!Double.isFinite(f)) {
+                    throw new IllegalArgumentException("contrastFactor must be finite: " + f);
+                }
+                this.contrastFactor = f;
+                return this;
+            }

As per coding guidelines: "Check conversions, integer arithmetic, sizes, alignment, finite floating-point inputs, and narrowing".

Source: Coding guidelines


194-197: Surface non-fatal downcall failures from recolorOne.

The catch (Throwable) calls rethrowFatal and then returns false. A non-fatal failure, such as WrongMethodTypeException from a wrong handle signature, looks like "no recolour needed". If a binding is wrong, every object is skipped and apply returns 0 without any error. The same pattern exists at Lines 96-99, 117-120 and 126-129.

Wrap non-fatal failures in JPDFiumException, as the FPDFPage_GenerateContent guard does.

This is a duplicate of the earlier review comment, which was marked as addressed. The current code still swallows these failures.

As per coding guidelines: "Do not catch Throwable merely to swallow or log it."

Source: Coding guidelines


150-154: Call NativeRuntime.rethrowFatal before wrapping the FPDFPage_GenerateContent failure.

The catch (Throwable t) wraps fatal errors, such as OutOfMemoryError, in JPDFiumException. Callers that catch JPDFiumException then treat a fatal VM error as an ordinary recolour failure. All other downcall guards in this file call rethrowFatal first.

Move the ok == 0 check out of the try block. Then remove the JPDFiumException rethrow branch.

Proposed fix
-            try {
-                int ok = (int) PageEditBindings.FPDFPage_GenerateContent.invokeExact(rawPage);
-                if (ok == 0) {
-                    throw new JPDFiumException("FPDFPage_GenerateContent failed");
-                }
-            } catch (JPDFiumException e) {
-                throw e;
-            } catch (Throwable t) {
-                throw new JPDFiumException("FPDFPage_GenerateContent failed", t);
-            }
+            int ok;
+            try {
+                ok = (int) PageEditBindings.FPDFPage_GenerateContent.invokeExact(rawPage);
+            } catch (Throwable t) {
+                NativeRuntime.rethrowFatal(t);
+                throw new JPDFiumException("FPDFPage_GenerateContent failed", t);
+            }
+            if (ok == 0) {
+                throw new JPDFiumException("FPDFPage_GenerateContent failed");
+            }

This is a duplicate of an earlier review comment. The current code still has the problem.

Source: Coding guidelines


307-307: Reject a null Mode in Builder.mode.

mode(null) is accepted. The switch (mode) at Line 233 then throws NullPointerException on the first eligible object. recolorOne catches that exception and returns false, so the object is silently skipped. The caller sees no error.

Validate the argument with Objects.requireNonNull. Add import java.util.Objects;.

This is a duplicate of an earlier review comment. The current code still accepts null.


270-285: Skip writes when HIGH_CONTRAST stretch and TINT leave the colour unchanged.

The contrast stretch branch and the tint method return true even when out equals the input. For example, black with factor = 2.0 stays (0,0,0). The object is still counted, dirty becomes true, and FPDFPage_GenerateContent rewrites the page for no change. This contradicts the map Javadoc at Line 231. The threshold branch already has the equality check.

Apply the equality check once in map.

Proposed fix
         boolean map(int r, int g, int b, int[] out) {
-            switch (mode) {
-                case INVERT:
-                    return invert(r, g, b, out);
-                case TINT:
-                    return tint(r, g, b, out);
-                case HIGH_CONTRAST:
-                default:
-                    return contrast(r, g, b, out);
-            }
+            boolean mapped = switch (mode) {
+                case INVERT -> invert(r, g, b, out);
+                case TINT -> tint(r, g, b, out);
+                case HIGH_CONTRAST -> contrast(r, g, b, out);
+            };
+            return mapped && (out[0] != r || out[1] != g || out[2] != b);
         }

This is a duplicate of an earlier review comment. The comment was marked as addressed, but the current code has no such check.


80-90: Reject null elements in pageIndices and hoist pageCount().

for (int i : pageIndices) unboxes each element. A null element throws NullPointerException. doc.pageCount() is also called on every iteration.

This is a duplicate of an earlier review comment. The current code is unchanged.

native/setup-pdfium.sh: 1

620-690: LGTM!

native/CMakeLists.txt: 2

646-649: These are still plain substring probes.

Both probes still use string(FIND ...). A comment or a longer identifier in either header can enable JPDFIUM_HAVE_CMYK_API or JPDFIUM_HAVE_EPDF_JPEG when no declaration exists. jpdfium_color.cpp then fails to compile. An earlier review already reported this.

Also applies to: 664-665


205-205: LGTM!

native/bridge/src/jpdfium_stub.cpp: 2

1681-1684: The stub returns JPDFIUM_ERR_NATIVE where the real bridge returns JPDFIUM_ERR_NOT_FOUND.

When the feature is unavailable, the real bridge returns JPDFIUM_ERR_NOT_FOUND for these two calls. The stub returns JPDFIUM_ERR_NATIVE through fail_native_bytes. An earlier review already reported this.

Also applies to: 1692-1696


1346-1350: LGTM!

Also applies to: 1675-1680, 1686-1690

NOTICE: 2

60-60: The jpeg-encoder license still omits IJG.

This line still says MIT OR Apache-2.0. It lacks the IJG term and the required attribution. An earlier review already reported this.


18-21: LGTM!

native/licenses/NOTICE.txt: 1

136-139: This entry still lacks the IJG license and attribution.

This is the same root cause as NOTICE line 60. An earlier review already reported this.

native/bridge/src/jpdfium_color.cpp: 4

32-34: The epdf_edit.h include is still unconditional.

CMakeLists.txt enables JPDFIUM_HAVE_EPDF_JPEG when EPDFImageObj_SetJpeg appears only in fpdf_edit.h. In that layout this include fails to compile. An earlier review already reported this.


620-634: The XMP update still matches only the element form.

When the source XMP uses the attribute form, AddPdfxAttributes appends duplicate attributes, which makes the XML ill-formed. This covers our own BuildPdfxXmp output and Acrobat files. An earlier review already reported this.


395-448: Windows staging and publishing still use narrow-path APIs on UTF-8 paths.

_sopen_s, std::filesystem::path(std::string) and MoveFileExA receive the UTF-8 paths that come from Java. qpdf reads the same paths as UTF-8. An earlier review already reported this.


44-180: LGTM!

Also applies to: 246-302, 668-952

jpdfium/src/main/java/stirling/software/jpdfium/panama/ColorBindings.java: 2

126-131: The ICC probes still bind unsigned long as JAVA_LONG.

On LLP64 Windows, unsigned long is 32-bit. The returned size can include garbage in the upper bits. An earlier review already reported this.


1-125: LGTM!

Also applies to: 133-479

jpdfium/src/main/java/stirling/software/jpdfium/panama/PageEditBindings.java: 2

67-68: These bindings still use JAVA_LONG for C unsigned long.

FPDFFormObj_GetObject and FPDFFormObj_GetObjectNumber both use native unsigned long. On LLP64 Windows, the returned object number is unreliable. An earlier review already reported this.

Also applies to: 79-80


5-5: LGTM!

Also applies to: 31-34, 62-66, 70-78, 82-105

jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfBinaryFreeApiTest.java: 2

74-83: The test still compares against vectorCmykAvailable() only.

supportsColorSpace(CMYK) also requires colorSpaceAvailable() and iccConversionAvailable(). An earlier review already reported this.


19-26: LGTM!

Also applies to: 97-99

native/bridge/tests/smoke.cpp: 2

218-219: The capability check is still unconditional when Rust is enabled.

The check fails on a supported build that has Rust but no EPDFImageObj_SetJpeg. An earlier review already reported this.


150-151: LGTM!

Also applies to: 209-217, 220-238

docs/editing.md: 2

199-199: The image-conversion probe description still omits EPDFImageObj_SetJpeg.

An earlier review already reported this.


180-198: LGTM!

Also applies to: 200-259, 269-308

jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXConverter.java: 2

31-39: PDF/X-3 output still does not reject transparency.

allowsTransparency() is never checked, so a source with transparency still gets PDF/X-3 metadata. An earlier review already reported this.


88-88: java.nio.charset.StandardCharsets is still package-qualified inline.

An earlier review already reported this.

native/tools/gen_compact_icc.c: 1

105-111: Results of cmsStageAllocCLut16bit, cmsPipelineInsertStage and cmsWriteTag are still unchecked.

A failed call still produces a profile without the A2B0 or B2A0 tag, and the tool exits 0. An earlier review already reported this.

jpdfium/build.gradle.kts: 2

452-453: jpdfium.test.cmykIcc is still not forwarded to the test JVM.

PdfColorPipelineTest and PdfXConverterTest read this property. Without it, the explicit-profile path never runs. An earlier review already reported this.


479-481: LGTM!

jpdfium/src/main/resources/icc/JPDFiumCompactCmyk.NOTICE.txt: 1

10-10: The MIT statement still conflicts with the generator.

gen_compact_icc.c still embeds "Public domain compact CMYK fallback profile" as the ICC copyright tag. An earlier review already reported this.

native/bridge/include/jpdfium.h: 1

710-771: LGTM!

native/bridge/include/jpdfium_rust.h: 1

115-120: LGTM!

native/bridge/jpdfium.def: 1

18-18: LGTM!

native/rust/jpdfium-impl/Cargo.toml: 1

22-27: LGTM!

native/rust/jpdfium-impl/src/lib.rs: 1

19-31: LGTM!

Also applies to: 138-138, 173-175, 319-319, 485-583

jpdfium/src/main/java/stirling/software/jpdfium/doc/IccCmykTransform.java: 1

1-145: LGTM!

jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfColorConverter.java: 1

7-665: LGTM!

jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfIccProfiles.java: 1

1-42: LGTM!

jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfOutputIntent.java: 1

1-139: LGTM!

jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXStandard.java: 1

1-55: LGTM!

jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXOptions.java: 1

1-197: LGTM!

.editorconfig-checker.json: 1

13-14: LGTM!

.gitattributes: 1

32-32: LGTM!

docs/README.md: 1

18-18: LGTM!

reachability-metadata/metadata/com.stirling/jpdfium/1.2.0/reachability-metadata.json: 1

233-267: 🗄️ Data Integrity & Integration

The registration-gap claim is refuted. Both metadata copies already contain the SAMPLES_TO_CMYK_JPEG, CMYK setter, and CMYK getter signatures. No metadata change is required for these descriptors.

jpdfium/src/main/resources/META-INF/native-image/com.stirling/jpdfium/reachability-metadata.json: 1

233-267: 🗄️ Data Integrity & Integration

The missing-registration claim is refuted. ColorBindings declares all listed CMYK, PDF/X, and ICC descriptors, and PageEditBindings.FPDFFormObj_GetObject matches the added (ADDRESS, ADDRESS, JAVA_LONG) descriptor. The removed seven-parameter signature is still registered at lines 1863-1871 for EmbedPdfDocumentBindings.EPDF_RenderAnnotBitmap, so the edit removes only a duplicate metadata entry. The stated native-image failure does not follow.

Comment thread docs/color-pipeline.md Outdated
Comment thread docs/editing.md Outdated
Comment thread native/bridge/src/jpdfium_stub.cpp
Comment thread native/setup-pdfium.sh
Comment thread native/setup-pdfium.sh Outdated
@balazs-szucs

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 20 minutes.

@balazs-szucs

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6


ℹ️ Review info
⚙️ Run configuration
📥 Commits

Reviewing files that changed from the base of the PR and between 5a35fef and 5d32fcb.

⛔ Files ignored due to path filters: 1
  • native/rust/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing: 39
  • .editorconfig-checker.json
  • .gitattributes
  • NOTICE
  • docs/README.md
  • docs/color-pipeline.md
  • docs/editing.md
  • jpdfium/build.gradle.kts
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/IccCmykTransform.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfColorConverter.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfIccProfiles.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfOutputIntent.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfRecolor.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXConverter.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXOptions.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXStandard.java
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/ColorBindings.java
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/FormFillBindings.java
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/PageEditBindings.java
  • jpdfium/src/main/java/stirling/software/jpdfium/transform/PdfPageGeometry.java
  • jpdfium/src/main/resources/META-INF/native-image/com.stirling/jpdfium/reachability-metadata.json
  • jpdfium/src/main/resources/icc/JPDFiumCompactCmyk.NOTICE.txt
  • jpdfium/src/main/resources/icc/JPDFiumCompactCmyk.icc
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/IccCmykTransformTest.java
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfBinaryFreeApiTest.java
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfImageLosslessTest.java
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfxMetadataSafetyTest.java
  • native/CMakeLists.txt
  • native/bridge/include/jpdfium.h
  • native/bridge/include/jpdfium_rust.h
  • native/bridge/jpdfium.def
  • native/bridge/src/jpdfium_color.cpp
  • native/bridge/src/jpdfium_stub.cpp
  • native/bridge/tests/smoke.cpp
  • native/licenses/NOTICE.txt
  • native/rust/jpdfium-impl/Cargo.toml
  • native/rust/jpdfium-impl/src/lib.rs
  • native/setup-pdfium.sh
  • native/tools/gen_compact_icc.c
  • reachability-metadata/metadata/com.stirling/jpdfium/1.2.0/reachability-metadata.json

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

📜 Review details
🧰 Additional context used
📚 Code guidelines: 1
.github/CODERABBIT_REVIEW.md — configured
📓 Path-based instructions: 5
Apply the native ownership, C ABI, C++23, engine integration, memory, and SIMD rules from .github/CODERABBIT_REVIEW.md.

⚙️ CodeRabbit configuration file

Files:

  • native/bridge/tests/smoke.cpp
  • native/bridge/include/jpdfium_rust.h
  • native/tools/gen_compact_icc.c
  • native/bridge/include/jpdfium.h
  • native/bridge/src/jpdfium_stub.cpp
  • native/bridge/src/jpdfium_color.cpp
Check target-scoped flags, exported ABI, reproducibility, sanitizer instrumentation, dependency compatibility, and portable CPU targets.

⚙️ CodeRabbit configuration file

Files:

  • native/CMakeLists.txt
Enforce meaningful assertions, deterministic concurrency, failure-path cleanup, and explicit native/stub requirements.

⚙️ CodeRabbit configuration file

Files:

  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfBinaryFreeApiTest.java
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfImageLosslessTest.java
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/IccCmykTransformTest.java
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfxMetadataSafetyTest.java
Apply the Java 25 and FFM rules from .github/CODERABBIT_REVIEW.md.

⚙️ CodeRabbit configuration file

Files:

  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfBinaryFreeApiTest.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfIccProfiles.java
  • jpdfium/src/main/java/stirling/software/jpdfium/transform/PdfPageGeometry.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXStandard.java
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/FormFillBindings.java
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/PageEditBindings.java
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfImageLosslessTest.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/IccCmykTransform.java
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/IccCmykTransformTest.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXOptions.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfOutputIntent.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXConverter.java
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/ColorBindings.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfRecolor.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfColorConverter.java
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfxMetadataSafetyTest.java
Source excerpt: Use imports rather than package-qualified type names in method bodies and signatures.

📄 CodeRabbit inference engine (.github/CODERABBIT_REVIEW.md)

Files:

  • native/licenses/NOTICE.txt
  • jpdfium/build.gradle.kts
  • docs/README.md
  • native/bridge/tests/smoke.cpp
  • reachability-metadata/metadata/com.stirling/jpdfium/1.2.0/reachability-metadata.json
  • jpdfium/src/main/resources/icc/JPDFiumCompactCmyk.NOTICE.txt
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfBinaryFreeApiTest.java
  • NOTICE
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfIccProfiles.java
  • native/bridge/include/jpdfium_rust.h
  • native/bridge/jpdfium.def
  • jpdfium/src/main/java/stirling/software/jpdfium/transform/PdfPageGeometry.java
  • jpdfium/src/main/resources/META-INF/native-image/com.stirling/jpdfium/reachability-metadata.json
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXStandard.java
  • native/rust/jpdfium-impl/Cargo.toml
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/FormFillBindings.java
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/PageEditBindings.java
  • native/CMakeLists.txt
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfImageLosslessTest.java
  • docs/editing.md
  • docs/color-pipeline.md
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/IccCmykTransform.java
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/IccCmykTransformTest.java
  • native/tools/gen_compact_icc.c
  • native/bridge/include/jpdfium.h
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXOptions.java
  • native/bridge/src/jpdfium_stub.cpp
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfOutputIntent.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXConverter.java
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/ColorBindings.java
  • native/rust/jpdfium-impl/src/lib.rs
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfRecolor.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfColorConverter.java
  • native/setup-pdfium.sh
  • native/bridge/src/jpdfium_color.cpp
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfxMetadataSafetyTest.java
🪛 GitHub Check: CodeQL
jpdfium/src/main/java/stirling/software/jpdfium/transform/PdfPageGeometry.java

[notice] 309-310: Unread local variable
Variable 'int ignored' is never read.


[notice] 315-316: Unread local variable
Variable 'int ignored' is never read.

🪛 LanguageTool
docs/color-pipeline.md

[uncategorized] ~85-~85: The official name of this software platform is spelled with a capital “H”.
Context: ...s future work. 4. Ghent gate in CI. .github/workflows/ghent.yml builds the patched...

(GITHUB)

🔇 Additional comments: 33
native/CMakeLists.txt: 1

646-649: Both PDFium probes still use substring matching.

string(FIND ...) matches comments and longer identifiers. In that case, the JPDFIUM_HAVE_CMYK_API or JPDFIUM_HAVE_EPDF_JPEG definition is set without a real declaration, and jpdfium_color.cpp then fails to compile. The earlier comment gives a declaration-aware regex for both probes.

Also applies to: 664-665

NOTICE: 1

60-60: jpeg-encoder is still listed as MIT OR Apache-2.0 only.

The earlier comment is marked as addressed, but this revision still omits the IJG term and the required "based in part on the work of the Independent JPEG Group" statement.

native/bridge/src/jpdfium_color.cpp: 1

498-504: Windows staging and publish still use narrow-path APIs.

_sopen_s and MoveFileExA interpret the UTF-8 path from ColorBindings in the ANSI code page. qpdf interprets the same path as UTF-8. For a non-ASCII path, these calls can address different files.

Also applies to: 532-537

native/bridge/src/jpdfium_stub.cpp: 1

1681-1684: The stub still returns JPDFIUM_ERR_NATIVE where the real bridge returns JPDFIUM_ERR_NOT_FOUND.

Also applies to: 1692-1696

native/bridge/tests/smoke.cpp: 1

218-219: The unconditional capability check is still present.

JPDFIUM_COLOR_CAP_CMYK_IMAGE also requires JPDFIUM_HAVE_EPDF_JPEG, and CMake treats that capability as optional. On a Rust build whose PDFium header lacks EPDFImageObj_SetJpeg, native_smoke fails. The earlier comment is marked as addressed, but this revision still has the check. Assert only that the capability bit implies Rust.

jpdfium/src/main/java/stirling/software/jpdfium/panama/ColorBindings.java: 1

134-139: The ICC getters are still bound with JAVA_LONG for C unsigned long.

On LLP64 Windows, unsigned long is 32 bits, so this descriptor does not match the native declaration. The earlier comment is marked as addressed in c61972e, but this revision still uses JAVA_LONG. The same mismatch exists in PageEditBindings for FPDFFormObj_GetObjectNumber and the FPDFFormObj_GetObject index.

jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfBinaryFreeApiTest.java: 1

74-83: The test still compares CMYK support with vectorCmykAvailable() only.

supportsColorSpace(CMYK) also requires colorSpaceAvailable() and iccConversionAvailable(). The earlier comment is marked as addressed, but this revision still uses the partial predicate.

jpdfium/build.gradle.kts: 1

452-453: The forwarding filter still omits jpdfium.test.*.

The earlier comment is marked as addressed, but -Djpdfium.test.cmykIcc still does not reach the forked test JVM.

docs/editing.md: 1

199-199: Line 199 still omits the EPDFImageObj_SetJpeg requirement for supportsImageConversion().

jpdfium/src/main/java/stirling/software/jpdfium/panama/PageEditBindings.java: 1

67-68: FPDFFormObj_GetObject and FPDFFormObj_GetObjectNumber still use JAVA_LONG for C unsigned long.

This is the LLP64 descriptor mismatch from the earlier comment, and it is still present.

Also applies to: 79-80

jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfRecolor.java: 1

144-154: Several earlier PdfRecolor findings are still present in this revision:

  • FPDFPage_GenerateContent failures are wrapped without rethrowFatal.
  • recolorOne turns non-fatal downcall errors into "unchanged".
  • stretch narrows a long to int before Math.clamp.
  • contrastFactor accepts non-finite values.
  • mode(null) is accepted.

Also applies to: 194-197, 288-291, 307-307, 321-321

jpdfium/src/main/java/stirling/software/jpdfium/transform/PdfPageGeometry.java: 1

299-317: Two earlier findings are still open, and CodeQL flags the unread ignored locals.

  • When EPDFForm_SetFieldValue returns 0 for a text or choice field, cleanup does not fail.
  • When EPDFForm_RedrawFieldWidgets is absent, the old /AP appearance stays in the file.

Both findings remain unresolved.

jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXConverter.java: 1

98-98: Line 98 still uses an inline java.nio.charset.StandardCharsets name.

jpdfium/src/main/resources/icc/JPDFiumCompactCmyk.NOTICE.txt: 1

10-10: The license conflict is still present.

This notice says MIT. native/tools/gen_compact_icc.c Line 116 still embeds "Public domain compact CMYK fallback profile" in the ICC copyright tag.

native/tools/gen_compact_icc.c: 1

105-118: The stage allocation, pipeline insertion and cmsWriteTag results are still unchecked.

If any of these calls fails, the tool still writes a profile without A2B0 or B2A0 and returns 0.

native/licenses/NOTICE.txt: 1

136-139: The jpeg-encoder entry still omits the IJG license term and attribution.

native/bridge/include/jpdfium.h: 1

710-787: LGTM!

native/bridge/jpdfium.def: 1

18-18: LGTM!

native/rust/jpdfium-impl/Cargo.toml: 1

22-27: LGTM!

native/rust/jpdfium-impl/src/lib.rs: 1

490-583: LGTM!

.gitattributes: 1

32-32: LGTM!

.editorconfig-checker.json: 1

13-14: LGTM!

jpdfium/src/main/java/stirling/software/jpdfium/doc/IccCmykTransform.java: 1

1-235: LGTM!

jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfIccProfiles.java: 1

1-42: LGTM!

jpdfium/src/test/java/stirling/software/jpdfium/doc/IccCmykTransformTest.java: 1

1-46: LGTM!

docs/README.md: 1

18-18: LGTM!

jpdfium/src/main/java/stirling/software/jpdfium/panama/FormFillBindings.java: 1

56-71: LGTM!

jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfOutputIntent.java: 1

1-161: LGTM!

jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXOptions.java: 1

1-218: LGTM!

jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXStandard.java: 1

1-62: LGTM!

jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfxMetadataSafetyTest.java: 1

1-141: LGTM!

native/bridge/include/jpdfium_rust.h: 1

115-120: LGTM!

jpdfium/src/main/resources/META-INF/native-image/com.stirling/jpdfium/reachability-metadata.json: 1

233-279: 🗄️ Data Integrity & Integration

The concern is refuted. All listed current FFM descriptor shapes are present in both JPDFium metadata files. The removed seven-parameter shape also remains once in each file, so a binding using that shape is covered. The scan found no missing descriptors.

Comment thread docs/color-pipeline.md
Comment thread docs/editing.md Outdated
Comment thread jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfImageLosslessTest.java Outdated
Comment thread native/bridge/src/jpdfium_color.cpp
Comment thread native/bridge/src/jpdfium_stub.cpp
@balazs-szucs
balazs-szucs force-pushed the feat/cmyk-color-pipeline branch 2 times, most recently from 221fc3d to af097bd Compare October 22, 2026 17:27
@balazs-szucs

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6


ℹ️ Review info
⚙️ Run configuration
📥 Commits

Reviewing files that changed from the base of the PR and between 5a35fef and af097bd.

⛔ Files ignored due to path filters: 1
  • native/rust/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing: 40
  • .editorconfig-checker.json
  • .gitattributes
  • NOTICE
  • buildSrc/src/main/kotlin/jpdfium.library-conventions.gradle.kts
  • docs/README.md
  • docs/color-pipeline.md
  • docs/editing.md
  • jpdfium/build.gradle.kts
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/IccCmykTransform.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfColorConverter.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfIccProfiles.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfOutputIntent.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfRecolor.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXConverter.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXOptions.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXStandard.java
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/ColorBindings.java
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/FormFillBindings.java
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/PageEditBindings.java
  • jpdfium/src/main/java/stirling/software/jpdfium/transform/PdfPageGeometry.java
  • jpdfium/src/main/resources/META-INF/native-image/com.stirling/jpdfium/reachability-metadata.json
  • jpdfium/src/main/resources/icc/JPDFiumCompactCmyk.NOTICE.txt
  • jpdfium/src/main/resources/icc/JPDFiumCompactCmyk.icc
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/IccCmykTransformTest.java
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfBinaryFreeApiTest.java
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfImageLosslessTest.java
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfxMetadataSafetyTest.java
  • native/CMakeLists.txt
  • native/bridge/include/jpdfium.h
  • native/bridge/include/jpdfium_rust.h
  • native/bridge/jpdfium.def
  • native/bridge/src/jpdfium_color.cpp
  • native/bridge/src/jpdfium_stub.cpp
  • native/bridge/tests/smoke.cpp
  • native/licenses/NOTICE.txt
  • native/rust/jpdfium-impl/Cargo.toml
  • native/rust/jpdfium-impl/src/lib.rs
  • native/setup-pdfium.sh
  • native/tools/gen_compact_icc.c
  • reachability-metadata/metadata/com.stirling/jpdfium/1.2.0/reachability-metadata.json

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

📜 Review details
⏰ Context from checks skipped due to timeout: 9
  • GitHub Check: prep-windows-icu
  • GitHub Check: Corpus (generate + native)
  • GitHub Check: JMH Benchmarks (FFM Downcall Overhead Gate)
  • GitHub Check: GraalVM Native Image Smoke & E2E Test (Linux x64)
  • GitHub Check: CLI correctness & no-corruption tests
  • GitHub Check: Native bridge libFuzzer (ASan/UBSan, real PDFium)
  • GitHub Check: build-natives (windows-arm64, windows-11-arm)
  • GitHub Check: Restricted-env compat (no execstack + hermetic bundle)
  • GitHub Check: CodeQL Analysis (c-cpp)
🧰 Additional context used
📚 Code guidelines: 1
.github/CODERABBIT_REVIEW.md — configured
📓 Path-based instructions: 5
Apply the native ownership, C ABI, C++23, engine integration, memory, and SIMD rules from .github/CODERABBIT_REVIEW.md.

⚙️ CodeRabbit configuration file

Files:

  • native/bridge/tests/smoke.cpp
  • native/bridge/include/jpdfium_rust.h
  • native/tools/gen_compact_icc.c
  • native/bridge/src/jpdfium_stub.cpp
  • native/bridge/include/jpdfium.h
  • native/bridge/src/jpdfium_color.cpp
Check target-scoped flags, exported ABI, reproducibility, sanitizer instrumentation, dependency compatibility, and portable CPU targets.

⚙️ CodeRabbit configuration file

Files:

  • native/CMakeLists.txt
Enforce meaningful assertions, deterministic concurrency, failure-path cleanup, and explicit native/stub requirements.

⚙️ CodeRabbit configuration file

Files:

  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfImageLosslessTest.java
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/IccCmykTransformTest.java
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfBinaryFreeApiTest.java
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfxMetadataSafetyTest.java
Apply the Java 25 and FFM rules from .github/CODERABBIT_REVIEW.md.

⚙️ CodeRabbit configuration file

Files:

  • jpdfium/src/main/java/stirling/software/jpdfium/transform/PdfPageGeometry.java
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfImageLosslessTest.java
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/IccCmykTransformTest.java
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfBinaryFreeApiTest.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfIccProfiles.java
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfxMetadataSafetyTest.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXStandard.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/IccCmykTransform.java
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/FormFillBindings.java
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/PageEditBindings.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfOutputIntent.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfRecolor.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXConverter.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXOptions.java
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/ColorBindings.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfColorConverter.java
Source excerpt: Use imports rather than package-qualified type names in method bodies and signatures.

📄 CodeRabbit inference engine (.github/CODERABBIT_REVIEW.md)

Files:

  • buildSrc/src/main/kotlin/jpdfium.library-conventions.gradle.kts
  • NOTICE
  • docs/README.md
  • jpdfium/src/main/resources/icc/JPDFiumCompactCmyk.NOTICE.txt
  • reachability-metadata/metadata/com.stirling/jpdfium/1.2.0/reachability-metadata.json
  • jpdfium/src/main/resources/META-INF/native-image/com.stirling/jpdfium/reachability-metadata.json
  • native/rust/jpdfium-impl/Cargo.toml
  • jpdfium/src/main/java/stirling/software/jpdfium/transform/PdfPageGeometry.java
  • native/licenses/NOTICE.txt
  • native/bridge/tests/smoke.cpp
  • native/bridge/jpdfium.def
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfImageLosslessTest.java
  • native/bridge/include/jpdfium_rust.h
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/IccCmykTransformTest.java
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfBinaryFreeApiTest.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfIccProfiles.java
  • jpdfium/build.gradle.kts
  • jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfxMetadataSafetyTest.java
  • docs/color-pipeline.md
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXStandard.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/IccCmykTransform.java
  • native/CMakeLists.txt
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/FormFillBindings.java
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/PageEditBindings.java
  • docs/editing.md
  • native/tools/gen_compact_icc.c
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfOutputIntent.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfRecolor.java
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXConverter.java
  • native/rust/jpdfium-impl/src/lib.rs
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXOptions.java
  • native/bridge/src/jpdfium_stub.cpp
  • jpdfium/src/main/java/stirling/software/jpdfium/panama/ColorBindings.java
  • native/setup-pdfium.sh
  • native/bridge/include/jpdfium.h
  • native/bridge/src/jpdfium_color.cpp
  • jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfColorConverter.java
🪛 ast-grep (0.45.3)
jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfxMetadataSafetyTest.java

[warning] 117-117: Use a randomly-generated IV
Context: byte[] utf16 = ("\uFEFF" + xmp).getBytes(StandardCharsets.UTF_16LE);
Note: [CWE-329] Generation of Predictable IV with CBC Mode.

(random-iv)

🪛 GitHub Check: CodeQL
jpdfium/src/main/java/stirling/software/jpdfium/transform/PdfPageGeometry.java

[notice] 309-310: Unread local variable
Variable 'int ignored' is never read.


[notice] 315-316: Unread local variable
Variable 'int ignored' is never read.

🪛 LanguageTool
docs/color-pipeline.md

[uncategorized] ~85-~85: The official name of this software platform is spelled with a capital “H”.
Context: ...s future work. 4. Ghent gate in CI. .github/workflows/ghent.yml builds the patched...

(GITHUB)

🔇 Additional comments: 48
jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfRecolor.java: 6

82-83: Duplicate of an earlier review comment. The code at these lines still has the issue. for (int i : pageIndices) unboxes each element, so a null element throws NullPointerException. doc.pageCount() is also called on every iteration. Hoist the page count and reject null elements.


150-153: Duplicate of an earlier review comment. The catch (Throwable t) around FPDFPage_GenerateContent does not call NativeRuntime.rethrowFatal(t). A fatal error such as OutOfMemoryError is therefore wrapped in JPDFiumException. Every other downcall guard in this file calls rethrowFatal first.


96-99: Duplicate of an earlier review comment. These catch (Throwable) blocks call rethrowFatal and then swallow the failure by returning 0, continuing, or returning false. A non-fatal binding failure, such as WrongMethodTypeException, is indistinguishable from "nothing to recolour". apply can then return 0 and look successful. Wrap these failures in JPDFiumException, as the GenerateContent path does.

Also applies to: 117-120, 126-129, 194-197


167-175: Duplicate of an earlier review comment. When sourceSpace is -1, the native color-space probe is unavailable or failed. Control then goes to the CMYK probe. If the CMYK probe also returns false, the object reaches the RGB getter. ICC or Separation colors can then be rewritten as DeviceRGB. Return false when sourceSpace < 0.


254-268: Duplicate of an earlier review comment. Three problems remain:

  • stretch casts the long from Math.round to int before Math.clamp. A large or infinite contrastFactor truncates to arbitrary bits instead of clamping. This violates the guideline "Check conversions, integer arithmetic, sizes, alignment, finite floating-point inputs, and narrowing".
  • contrastFactor(double) does not reject non-finite values.
  • tint and the stretch branch of contrast return true even when out equals the input. This contradicts the map Javadoc and causes no-op page rewrites that inflate the changed count.

Pass the long to Math.clamp directly, validate finiteness in the builder, and compare out with the input in map.

Also applies to: 280-290, 321-321


307-307: Duplicate of an earlier review comment. mode(null) is accepted. The NullPointerException then occurs later in map. recolorOne catches and hides that exception. Use Objects.requireNonNull(m, "mode") in the builder.

native/CMakeLists.txt: 2

646-648: The probes still use string(FIND ...). This repeats the open declaration-aware probe comment.

A substring match can find a comment or a longer identifier. In that case, CMake defines JPDFIUM_HAVE_CMYK_API or JPDFIUM_HAVE_EPDF_JPEG, and jpdfium_color.cpp then fails to compile. Apply the earlier proposed regex check to both probes.

Also applies to: 664-665


205-205: LGTM!

NOTICE: 2

60-60: The jpeg-encoder entry still omits the IJG license and attribution.

An earlier review marked this as addressed, but line 60 still reads MIT OR Apache-2.0. The crate's license is (MIT OR Apache-2.0) AND IJG. The statically linked binary therefore ships without the required IJG attribution.


18-21: LGTM!

native/bridge/src/jpdfium_stub.cpp: 2

1681-1684: The stub still returns JPDFIUM_ERR_NATIVE for features that are not available.

In a real build without these features, jpdfium_color_samples_to_cmyk_jpeg and jpdfium_color_output_intent_bytes return JPDFIUM_ERR_NOT_FOUND. The stub returns a different code, so stub-backed tests check a different error mapping. This matches the earlier open comment.

Also applies to: 1698-1702


1346-1350: LGTM!

Also applies to: 1675-1680, 1686-1697, 1704-1720

native/bridge/tests/smoke.cpp: 2

218-219: The capability assertion is still unconditional when Rust is present.

An earlier review marked this as addressed, but the code is unchanged. CMake treats EPDFImageObj_SetJpeg as optional. If a Rust-enabled build lacks it, jpdfium_has_rust() == 1 while JPDFIUM_COLOR_CAP_CMYK_IMAGE stays clear, and native_smoke fails. Assert only that the capability bit implies Rust.


150-151: LGTM!

Also applies to: 209-217, 220-238

native/licenses/NOTICE.txt: 1

136-139: The IJG terms and attribution are still missing for jpeg-encoder.

An earlier review marked this as addressed, but the entry still lists only MIT OR Apache-2.0. The root cause is the same as NOTICE line 60.

native/bridge/src/jpdfium_color.cpp: 1

498-504: The Windows narrow-path APIs are still in place.

_sopen_s and MoveFileExA interpret UTF-8 path bytes in the ANSI code page, while qpdf treats the same strings as UTF-8. A non-ASCII path can therefore refer to different files during staging and publication. This matches the earlier open comment.

Also applies to: 534-535

jpdfium/src/main/java/stirling/software/jpdfium/panama/ColorBindings.java: 1

134-139: The ICC getters are still bound with JAVA_LONG for C unsigned long.

An earlier review marked this as addressed, but the descriptors are unchanged. On LLP64 Windows, unsigned long is 4 bytes. The return value and the length argument therefore do not match the native ABI. Use Linker.nativeLinker().canonicalLayouts().get("long").

As per coding guidelines: "Audit LP64/LLP64 explicitly."

jpdfium/src/main/java/stirling/software/jpdfium/doc/IccCmykTransform.java: 1

107-117: The ICC path without a target profile still parses the source profile for every object.

An earlier review marked this as addressed, but sourceToCmyk is unchanged. For each fill and stroke, it calls staticSourceSpace and then ICC_Profile.getInstance plus new ICC_ColorSpace. The one-entry cache in sourceSpace is not used on this path.

jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfBinaryFreeApiTest.java: 2

74-83: The test still compares CMYK support with vectorCmykAvailable() alone.

An earlier review marked this as addressed, but the code is unchanged. supportsColorSpace(CMYK) also requires colorSpaceAvailable() and iccConversionAvailable(). The assertion therefore fails on a build that exports the setters but not the probes.


19-26: LGTM!

Also applies to: 97-99

docs/editing.md: 3

199-199: The supportsImageConversion() row still omits the EPDFImageObj_SetJpeg requirement.

An earlier review marked this as addressed, but the text is unchanged. A build that has only the encoder reports false.


233-233: The -1 sentinel still does not mention partial page rewrites.

If a page fails after earlier pages were converted, convertImagesToCmyk returns -1 and the document is partially rewritten. This matches the earlier open comment.


180-198: LGTM!

Also applies to: 200-232, 234-314

jpdfium/src/main/resources/icc/JPDFiumCompactCmyk.NOTICE.txt: 1

10-10: The license statement still conflicts with the profile's embedded copyright tag.

An earlier review marked this as addressed, but nothing changed. This notice says MIT. gen_compact_icc.c line 116 writes "Public domain compact CMYK fallback profile" into the ICC file.

native/tools/gen_compact_icc.c: 1

105-118: The stage allocations and the cmsWriteTag results are still unchecked.

An earlier review marked this as addressed, but nothing changed. If a stage allocation or tag write fails, the tool writes a profile without A2B0 or B2A0 and still exits 0.

native/setup-pdfium.sh: 1

381-951: LGTM!

native/bridge/include/jpdfium.h: 1

710-786: LGTM!

native/bridge/include/jpdfium_rust.h: 1

115-120: LGTM!

native/bridge/jpdfium.def: 1

18-18: LGTM!

native/rust/jpdfium-impl/Cargo.toml: 1

22-27: LGTM!

native/rust/jpdfium-impl/src/lib.rs: 1

19-31: LGTM!

Also applies to: 138-138, 173-175, 319-319, 485-583

reachability-metadata/metadata/com.stirling/jpdfium/1.2.0/reachability-metadata.json: 1

233-279: LGTM!

Also applies to: 1838-1885

.gitattributes: 1

32-32: LGTM!

.editorconfig-checker.json: 1

13-14: LGTM!

jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfColorConverter.java: 1

7-57: LGTM!

Also applies to: 67-71, 85-90, 104-112, 126-139, 141-266, 268-366, 371-521, 529-700

jpdfium/src/test/java/stirling/software/jpdfium/doc/IccCmykTransformTest.java: 1

1-46: LGTM!

jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfImageLosslessTest.java: 1

1-170: LGTM!

jpdfium/build.gradle.kts: 1

449-453: LGTM!

Also applies to: 479-481

docs/README.md: 1

18-18: LGTM!

docs/color-pipeline.md: 1

1-122: LGTM!

jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfOutputIntent.java: 1

1-161: LGTM!

jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXConverter.java: 1

1-149: LGTM!

jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXOptions.java: 1

1-218: LGTM!

jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfXStandard.java: 1

1-62: LGTM!

jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfIccProfiles.java: 1

1-42: LGTM!

jpdfium/src/test/java/stirling/software/jpdfium/doc/PdfxMetadataSafetyTest.java: 1

1-153: LGTM!

Also applies to: 158-182

buildSrc/src/main/kotlin/jpdfium.library-conventions.gradle.kts: 1

131-132: LGTM!

jpdfium/src/main/resources/META-INF/native-image/com.stirling/jpdfium/reachability-metadata.json: 1

233-279: 🗄️ Data Integrity & Integration

All listed downcall signatures are present.

The metadata contains the three cited signatures, and the bundled metadata files are identical. The missing-signature concern does not apply.

Comment on lines +367 to +370
int beforeConverted = state.converted;
boolean beforeDirty = state.dirty;
scanFormObjects(obj, options, xform, r, g, b, a, cmyk, state);
if (state.converted != beforeConverted || state.dirty != beforeDirty) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Stroke-only edits inside a form are lost when the page is already dirty.

The form is marked dirty only when state.converted or state.dirty changes. converted counts fill conversions only. In scanObject, a stroke conversion sets dirty = true and does not increment converted.

Trigger: an earlier object on the page converts, so beforeDirty is already true. A form then contains stroked paths with a DeviceRGB stroke and the default DeviceGray fill, which is preserved. The form's children are rewritten, but neither counter changes. As a result:

  • FPDFFormObj_MarkDirty is not called.
  • FPDFPage_GenerateContent discards the form edits.
  • The output keeps RGB strokes, which defeats the CMYK/PDF/X conversion.

The same gap exists for nested forms.

Fix: track an edit counter that every successful fill or stroke write increments, and compare that counter.

Proposed fix
     private static final class ConversionState {
         private final Set<Long> visitedForms;
         private int converted;
+        private int edits;
         private boolean dirty;
@@
-            int beforeConverted = state.converted;
-            boolean beforeDirty = state.dirty;
+            int beforeEdits = state.edits;
             scanFormObjects(obj, options, xform, r, g, b, a, cmyk, state);
-            if (state.converted != beforeConverted || state.dirty != beforeDirty) {
+            if (state.edits != beforeEdits) {
@@
         if (convertColor(obj, options, xform, r, g, b, a, cmyk, true)) {
             state.dirty = true;
+            state.edits++;
             state.converted++;
         }
         if (convertColor(obj, options, xform, r, g, b, a, cmyk, false)) {
             state.dirty = true;
+            state.edits++;
         }

Comment on lines +522 to +528
float[] comps = fill
? ColorBindings.fillColorComponents(obj)
: ColorBindings.strokeColorComponents(obj);
byte[] sourceIcc = fill
? ColorBindings.fillColorIccProfile(obj)
: ColorBindings.strokeColorIccProfile(obj);
if (comps == null || sourceIcc == null) return false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🔵 Trivial | 🏗️ Heavy lift

🔎 Supported by static analysis

🏁 Script executed:

sed -n '500,584p' jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfColorConverter.java
sed -n '224,274p' jpdfium/src/main/java/stirling/software/jpdfium/panama/ColorBindings.java

Repository: Stirling-Tools/JPDFium

Length of output: 5693


🏁 Script executed:

rg -n -F --glob '*.java' -e 'class IccCmykTransform' -e 'sourceSpace' -e 'convertIccToCmyk' -e 'fillColorIccProfile' -e 'strokeColorIccProfile' jpdfium/src/main/java
printf '\n--- transform and surrounding callers ---\n'
rg -n -F --glob '*.java' -e 'IccCmykTransform' jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfColorConverter.java
printf '\n--- transform source files ---\n'
rg --files jpdfium/src/main/java | rg 'Icc|Color'

Repository: Stirling-Tools/JPDFium

Length of output: 5076


🏁 Script executed:

printf '%s\n' '--- IccCmykTransform.java ---'
nl -ba jpdfium/src/main/java/stirling/software/jpdfium/doc/IccCmykTransform.java | sed -n '1,205p'
printf '%s\n' '--- PdfColorConverter dispatch ---'
nl -ba jpdfium/src/main/java/stirling/software/jpdfium/doc/PdfColorConverter.java | sed -n '430,470p'
printf '%s\n' '--- ColorBindings profile helper and handles ---'
nl -ba jpdfium/src/main/java/stirling/software/jpdfium/panama/ColorBindings.java | sed -n '190,270p'

Repository: Stirling-Tools/JPDFium

Length of output: 16438


Avoid copying the ICC profile before cache lookup.

Each reached ICCBased fill or stroke conversion performs two native profile calls, allocates a confined arena buffer, and copies the full profile into a new byte[]. IccCmykTransform.sourceSpace compares that copied array only afterward, so the cache avoids profile parsing but not the per-object transfer and allocation.

The “gigabytes” estimate depends on the number of objects and profile sizes, so do not state it without measurement. If an ICC-heavy fixture shows material cost, provide a stable native profile identity so the converter can reuse the cached profile before copying. Profile length alone is not sufficient.

Comment on lines +154 to +157
StringBuilder hostile = new StringBuilder(10 * 1024 * 1024 + prefix.length() + suffix.length());
hostile.append(prefix);
hostile.append("<rdf:li>".repeat(300_000));
hostile.append(suffix);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

The "huge" packet is below the 8 MiB cap, so this test never reaches the no-parse branch.

"<rdf:li>".repeat(300_000) is about 2.4 MB. kMaxXmpBytes is 8 MiB, so UpdateOrCreatePdfxMetadata sends the packet to pugixml. The parse fails on the unclosed tags, and the fallback replaces the packet. The test passes either way, so the xml.size() > kMaxXmpBytes branch has no coverage, although the test name claims it does. The 10 MiB StringBuilder capacity shows that the intent was a packet over the cap.

Proposed fix
-        hostile.append("<rdf:li>".repeat(300_000));
+        // 8 bytes * 1.1M = ~8.8 MB, above the native 8 MiB parse cap.
+        hostile.append("<rdf:li>".repeat(1_100_000));

As per path instructions: "Enforce meaningful assertions … Reject silently passing tests."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
StringBuilder hostile = new StringBuilder(10 * 1024 * 1024 + prefix.length() + suffix.length());
hostile.append(prefix);
hostile.append("<rdf:li>".repeat(300_000));
hostile.append(suffix);
StringBuilder hostile = new StringBuilder(10 * 1024 * 1024 + prefix.length() + suffix.length());
hostile.append(prefix);
// 8 bytes * 1.1M = ~8.8 MB, above the native 8 MiB parse cap.
hostile.append("<rdf:li>".repeat(1_100_000));
hostile.append(suffix);

Source: Path instructions

Comment on lines +255 to +257
// An image with an /SMask or /Mask loses that mask when its stream dict is
// replaced by a re-encoded JPEG (CMYK JPEG has no alpha channel), so those
[[maybe_unused]] bool ImageHasTransparency(FPDF_DOCUMENT doc, FPDF_PAGE page, FPDF_PAGEOBJECT obj) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

The comment for ImageHasTransparency stops mid-sentence.

The comment ends with "so those". Complete the sentence, for example: "so those images are skipped."

Comment thread native/bridge/src/jpdfium_color.cpp Outdated
Comment thread native/tools/gen_compact_icc.c Outdated
@balazs-szucs
balazs-szucs force-pushed the feat/cmyk-color-pipeline branch from af097bd to bd99c57 Compare October 22, 2026 17:50

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants