Skip to content

Support configurable and auto-detected output format for cropped images#34

Open
paodb wants to merge 2 commits into
masterfrom
issue-23-output-format
Open

Support configurable and auto-detected output format for cropped images#34
paodb wants to merge 2 commits into
masterfrom
issue-23-output-format

Conversation

@paodb

@paodb paodb commented Jul 2, 2026

Copy link
Copy Markdown
Member

Reworks the fix for #23 following the approach agreed in the PR #27 discussion: a combination of an explicit server-side output-format property and zero-network auto-detection. Supersedes #27.

Problem

The cropped image was always encoded as PNG (canvas.toDataURL("image/png", ...)), so JPEGs (and any other format) were silently converted to PNG.

What this does

  • Explicit format property setOutputMimeType(String) lets the caller choose the output format (image/png, image/jpeg, image/webp).
  • Auto-detection (default) when the property is unset, the format is detected from the image source with a zero-network heuristic: the MIME type of a data: URI, or the file extension of a regular URL.
  • Validation the resolved type is validated against the formats canvas.toDataURL can actually encode (png/jpeg/webp); anything else falls back to image/png.
  • Circular crops are always encoded in a transparency-capable format, since JPEG has no alpha channel and would render the rounded corners black.
  • setOutputQuality(double) controls the encoding quality for lossy formats (jpeg/webp).

Notes

  • New feature → minor version bump (1.3.0-SNAPSHOT), in a separate build: commit.
  • Adds an "Image Crop Output Format" demo that lets you pick the format and shows the resulting MIME type.
  • Unit tests cover the new properties. The resolveOutputType heuristic lives in the frontend (no JS test runner in the repo) and is exercised via the demo.

Closes #23

Summary by CodeRabbit

  • New Features
    • Added configurable cropped-image output format with auto-detection plus selectable MIME types.
    • Added output quality (0–1) for lossy formats and updated encoding when output settings change.
    • Included a new demo to preview cropped images in different output formats.
  • Documentation
    • Updated README with new output MIME type and output quality configuration details.
  • Tests
    • Added unit tests for output MIME type/quality getters, setters, and default values.
  • Chores
    • Bumped the project snapshot version.

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Adds configurable cropped-image output MIME type and quality, with client-side format detection, circular-crop PNG fallback, a new demo, unit tests, README updates, and a version bump.

Changes

Output format configuration

Layer / File(s) Summary
Server-side output API
src/main/java/.../ImageCrop.java
Adds output MIME type and quality getters and setters, with defaults for unset values documented in the API.
Client-side MIME resolution and export
src/main/resources/META-INF/resources/frontend/src/image-crop.tsx
Adds MIME allowlist/normalization, source-based MIME detection, output state, an effect for output changes, and canvas export using resolved MIME type and configured quality.
Demo, tests, docs, and version
src/test/java/.../OutputFormatImageCropDemo.java, src/test/java/.../ImageCropDemoView.java, src/test/java/.../test/ImageCropTest.java, README.md, pom.xml
Adds the output-format demo, registers it in the demo view, covers the new properties in tests, documents the options, and bumps the project version.

Estimated code review effort: 2 (Simple) | ~15 minutes

Possibly related PRs

  • FlowingCode/ImageCrop#20: Both PRs update ImageCrop.setCrop(Crop) to trigger client-side _updateCroppedImage(...) refresh behavior.
  • FlowingCode/ImageCrop#32: Both PRs modify image-crop.tsx around _updateCroppedImage and canvas output behavior.

Suggested reviewers: mlopezFC, scardanzan

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes stop forced PNG encoding and add configurable, auto-detected output formats, matching issue #23's requirement.
Out of Scope Changes check ✅ Passed The docs, demo, tests, and version bump support the same feature and do not appear unrelated.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: configurable and auto-detected cropped-image output formats.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-23-output-format

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.

@paodb paodb changed the title Issue 23 output format Support configurable and auto-detected output format for cropped images Jul 2, 2026

@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: 3

🧹 Nitpick comments (1)
src/test/java/com/flowingcode/vaadin/addons/imagecrop/test/ImageCropTest.java (1)

48-61: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider adding tests for default (auto-detect) state.

These tests only verify explicit set/get round-trips. The PR's headline feature is auto-detection when outputMimeType/outputQuality are left unset (null). Consider adding a test asserting getOutputMimeType() returns null by default (before any setOutputMimeType call) to lock in the auto-detect contract.

✅ Suggested additional test
+  `@Test`
+  public void testGetOutputMimeTypeDefaultsToNull() {
+    assertNull(imageCrop.getOutputMimeType());
+  }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/com/flowingcode/vaadin/addons/imagecrop/test/ImageCropTest.java`
around lines 48 - 61, Add a test in ImageCropTest that exercises the default
auto-detect state before any setters are called: verify
imageCrop.getOutputMimeType() returns null initially, and if applicable do the
same for outputQuality. Use the existing ImageCrop test fixture and the
getOutputMimeType()/getOutputQuality() accessors to lock in the unset/null
contract, instead of only testing set/get round-trips.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/java/com/flowingcode/vaadin/addons/imagecrop/ImageCrop.java`:
- Around line 143-154: The refreshCroppedImage() flow currently depends on
setState(...) having already been applied before
getElement().executeJs("_updateCroppedImage(...)") runs, which is not guaranteed
by Vaadin. Update the ImageCrop logic so the re-encode uses client-side state
consistently, either by moving the update into a client-side effect or by
passing the new crop/mime/quality values directly from the caller into
refreshCroppedImage()/_updateCroppedImage(). Ensure the fix is applied where
property-change handlers trigger refreshCroppedImage() so the client always uses
the intended latest values.
- Around line 378-398: `ImageCrop#getOutputQuality()` can still fail if the
server-side state has never been initialized, even though the client defaults to
1.0. Update `ImageCrop` to initialize `outputQuality` on the Java side
(preferably in the constructor) or make `getOutputQuality()` fall back to 1.0
when the state is absent, and keep the existing `setOutputQuality` /
`refreshCroppedImage` flow unchanged.

In `@src/main/resources/META-INF/resources/frontend/src/image-crop.tsx`:
- Around line 300-302: The server-side output quality path can unbox a null
primitive before the client initializes its fallback value, so mirror the
client’s 1.0 default there. Update the relevant server-side getter or
initializer for output quality so it safely falls back to 1.0 when the nullable
state is unset, keeping behavior aligned with the frontend’s `this.outputQuality
?? 1.0` in `image-crop.tsx`.

---

Nitpick comments:
In
`@src/test/java/com/flowingcode/vaadin/addons/imagecrop/test/ImageCropTest.java`:
- Around line 48-61: Add a test in ImageCropTest that exercises the default
auto-detect state before any setters are called: verify
imageCrop.getOutputMimeType() returns null initially, and if applicable do the
same for outputQuality. Use the existing ImageCrop test fixture and the
getOutputMimeType()/getOutputQuality() accessors to lock in the unset/null
contract, instead of only testing set/get round-trips.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 50c61048-98f9-49a4-bbb3-29d5cccd1bbb

📥 Commits

Reviewing files that changed from the base of the PR and between 0a322d8 and 63bd5fa.

📒 Files selected for processing (7)
  • README.md
  • pom.xml
  • src/main/java/com/flowingcode/vaadin/addons/imagecrop/ImageCrop.java
  • src/main/resources/META-INF/resources/frontend/src/image-crop.tsx
  • src/test/java/com/flowingcode/vaadin/addons/imagecrop/ImageCropDemoView.java
  • src/test/java/com/flowingcode/vaadin/addons/imagecrop/OutputFormatImageCropDemo.java
  • src/test/java/com/flowingcode/vaadin/addons/imagecrop/test/ImageCropTest.java

Comment thread src/main/java/com/flowingcode/vaadin/addons/imagecrop/ImageCrop.java Outdated
Comment thread src/main/resources/META-INF/resources/frontend/src/image-crop.tsx
@paodb paodb force-pushed the issue-23-output-format branch from 63bd5fa to 3545968 Compare July 2, 2026 19:11

@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.

🧹 Nitpick comments (1)
src/main/java/com/flowingcode/vaadin/addons/imagecrop/ImageCrop.java (1)

387-389: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider validating outputQuality bounds.

setOutputQuality accepts any double with no range check, though the Javadoc states "a value between 0 and 1". Out-of-range values are silently passed through to canvas.toDataURL on the client.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/flowingcode/vaadin/addons/imagecrop/ImageCrop.java` around
lines 387 - 389, `ImageCrop.setOutputQuality` currently passes any double
through without enforcing the documented 0-to-1 range. Add validation in this
setter to reject or clamp out-of-bounds values before calling
`setState("outputQuality", ...)`, so the method matches its Javadoc and only
sends valid quality values to the client.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/main/java/com/flowingcode/vaadin/addons/imagecrop/ImageCrop.java`:
- Around line 387-389: `ImageCrop.setOutputQuality` currently passes any double
through without enforcing the documented 0-to-1 range. Add validation in this
setter to reject or clamp out-of-bounds values before calling
`setState("outputQuality", ...)`, so the method matches its Javadoc and only
sends valid quality values to the client.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b6eb90f1-5355-405a-b6a3-23064cb9a113

📥 Commits

Reviewing files that changed from the base of the PR and between 63bd5fa and 3545968.

📒 Files selected for processing (7)
  • README.md
  • pom.xml
  • src/main/java/com/flowingcode/vaadin/addons/imagecrop/ImageCrop.java
  • src/main/resources/META-INF/resources/frontend/src/image-crop.tsx
  • src/test/java/com/flowingcode/vaadin/addons/imagecrop/ImageCropDemoView.java
  • src/test/java/com/flowingcode/vaadin/addons/imagecrop/OutputFormatImageCropDemo.java
  • src/test/java/com/flowingcode/vaadin/addons/imagecrop/test/ImageCropTest.java
✅ Files skipped from review due to trivial changes (2)
  • pom.xml
  • README.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/test/java/com/flowingcode/vaadin/addons/imagecrop/ImageCropDemoView.java
  • src/test/java/com/flowingcode/vaadin/addons/imagecrop/OutputFormatImageCropDemo.java
  • src/main/resources/META-INF/resources/frontend/src/image-crop.tsx

@paodb paodb force-pushed the issue-23-output-format branch from 3545968 to 9f06011 Compare July 2, 2026 19:24
@sonarqubecloud

sonarqubecloud Bot commented Jul 2, 2026

Copy link
Copy Markdown

@paodb

paodb commented Jul 3, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 3, 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.

🧹 Nitpick comments (1)
src/main/java/com/flowingcode/vaadin/addons/imagecrop/ImageCrop.java (1)

340-392: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract property-name constants to fix SonarCloud duplication failures.

"outputMimeType" and "outputQuality" are each repeated 3 times (setter, getPropertyRaw check, getState call). SonarCloud flags both as quality-gate failures.

♻️ Proposed fix
+  private static final String OUTPUT_MIME_TYPE_PROPERTY = "outputMimeType";
+  private static final String OUTPUT_QUALITY_PROPERTY = "outputQuality";
+
   public void setOutputMimeType(String outputMimeType) {
-    setState("outputMimeType", outputMimeType);
+    setState(OUTPUT_MIME_TYPE_PROPERTY, outputMimeType);
   }

   public String getOutputMimeType() {
-    if (getElement().getPropertyRaw("outputMimeType") == null) {
+    if (getElement().getPropertyRaw(OUTPUT_MIME_TYPE_PROPERTY) == null) {
       return null;
     }
-    return getState("outputMimeType", String.class);
+    return getState(OUTPUT_MIME_TYPE_PROPERTY, String.class);
   }

   public void setOutputQuality(double outputQuality) {
-    setState("outputQuality", outputQuality);
+    setState(OUTPUT_QUALITY_PROPERTY, outputQuality);
   }

   public double getOutputQuality() {
-    if (getElement().getPropertyRaw("outputQuality") == null) {
+    if (getElement().getPropertyRaw(OUTPUT_QUALITY_PROPERTY) == null) {
       return 1.0;
     }
-    return getState("outputQuality", Double.class);
+    return getState(OUTPUT_QUALITY_PROPERTY, Double.class);
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/flowingcode/vaadin/addons/imagecrop/ImageCrop.java` around
lines 340 - 392, The ImageCrop output property names are duplicated in multiple
places, triggering SonarCloud duplication warnings. Extract shared constants for
the state keys used by setOutputMimeType/getOutputMimeType and
setOutputQuality/getOutputQuality, and reuse those constants in the setState,
getPropertyRaw, and getState calls. Keep the existing behavior unchanged while
centralizing the literal names in ImageCrop.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/main/java/com/flowingcode/vaadin/addons/imagecrop/ImageCrop.java`:
- Around line 340-392: The ImageCrop output property names are duplicated in
multiple places, triggering SonarCloud duplication warnings. Extract shared
constants for the state keys used by setOutputMimeType/getOutputMimeType and
setOutputQuality/getOutputQuality, and reuse those constants in the setState,
getPropertyRaw, and getState calls. Keep the existing behavior unchanged while
centralizing the literal names in ImageCrop.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9659a7f1-801d-41a8-93f9-210f59c060f9

📥 Commits

Reviewing files that changed from the base of the PR and between 0a322d8 and 9f06011.

📒 Files selected for processing (7)
  • README.md
  • pom.xml
  • src/main/java/com/flowingcode/vaadin/addons/imagecrop/ImageCrop.java
  • src/main/resources/META-INF/resources/frontend/src/image-crop.tsx
  • src/test/java/com/flowingcode/vaadin/addons/imagecrop/ImageCropDemoView.java
  • src/test/java/com/flowingcode/vaadin/addons/imagecrop/OutputFormatImageCropDemo.java
  • src/test/java/com/flowingcode/vaadin/addons/imagecrop/test/ImageCropTest.java

@paodb paodb requested review from javier-godoy and scardanzan July 3, 2026 12:45
@paodb paodb marked this pull request as ready for review July 3, 2026 12:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: To Do

Development

Successfully merging this pull request may close these issues.

JPEGs are silently converted to PNGs

1 participant