Skip to content

Conversation

@hexaredecimal
Copy link
Collaborator

@hexaredecimal hexaredecimal commented Aug 9, 2025

Before we were compiling the source code each frame in order to draw on the screen. Now I simply render to a bufferedImage that is the same size as the render window and then draw that image on top of the grid.

  • This change reduced the CPU usage from 45%-55% to 6%-8%
  • This also reduced the Memory usage from 400MB-450MB when rendering to 250MB-280MB
image This change also introduces the first commits for JHLabs filters support

Summary by CodeRabbit

  • New Features

    • Added support for creating and manipulating images and image filters within the Piccode environment, including new native functions for image creation, filter application, and brushed metal filter customization.
  • Refactor

    • Improved the rendering pipeline for the canvas, separating rendering into an offscreen image and updating how custom drawing logic is supplied and executed.
  • Bug Fixes

    • Enhanced resource management by explicitly disposing of graphics contexts after use.

@hexaredecimal hexaredecimal added this to the Road to 1.0 milestone Aug 9, 2025
@hexaredecimal hexaredecimal self-assigned this Aug 9, 2025
@hexaredecimal hexaredecimal added the enhancement New feature or request label Aug 9, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 9, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

This update refactors the rendering logic in CanvasFrame to use an offscreen image and a new compile method, decoupling compilation from painting. It also adds three new modules for native image and filter manipulation in the Piccode runtime, introducing functions to create images, apply filters, and work with brushed metal effects. Event handling is updated to use the new compile method.

Changes

Cohort / File(s) Change Summary
CanvasFrame Rendering Refactor
src/main/java/org/editor/CanvasFrame.java
Refactored to remove static fields and compileFrame(); introduced a new compile(Supplier<PiccodeValue>) method for offscreen rendering; updated paintComponent to draw the offscreen image; constructor and grid drawing logic updated accordingly.
Event Handling Update
src/main/java/org/editor/events/AccessEvents.java
Modified compileAndRender to call the new CanvasFrame.the().compile() method with a lambda, instead of setting static fields; retains success messaging.
Native Image Module
src/main/java/org/editor/nativemods/PiccodeImageModule.java
Added a module registering native functions for image creation (image_new, image_new_typed) and context retrieval (image_get_context) in the Piccode runtime, with type checks and error handling.
Native Filter Module
src/main/java/org/editor/nativemods/PiccodeFilterModule.java
Added a module registering a native function filter_apply to apply a Java BufferedImageOp filter to a BufferedImage in the Piccode runtime, with type verification and error reporting.
Brushed Metal Filter Module
src/main/java/org/editor/nativemods/PiccodeBrushedMetalFilterModule.java
Added a module registering native functions for creating and modifying a BrushedMetalFilter (brush_metal_new, brush_metal_set_rad, brush_metal_set_amount, brush_metal_set_shine) in the Piccode runtime, with type checks and error handling.
Build Configuration Update
pom.xml
Added a new Maven dependency for JHLabs library to support image filtering functionality.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant AccessEvents
    participant CanvasFrame
    participant Compiler

    User->>AccessEvents: compileAndRender(file, code)
    AccessEvents->>CanvasFrame: the().compile(() -> Compiler.compile(file, code))
    CanvasFrame->>CanvasFrame: Create offscreen image, run lambda
    CanvasFrame->>CanvasFrame: Store render image
    CanvasFrame->>User: (On repaint) paintComponent draws render image
Loading
sequenceDiagram
    participant PiccodeRuntime
    participant PiccodeImageModule
    participant PiccodeFilterModule
    participant PiccodeBrushedMetalFilterModule
    participant JavaImageAPI

    PiccodeRuntime->>PiccodeImageModule: image_new(w, h)
    PiccodeImageModule->>JavaImageAPI: new BufferedImage(w, h)
    JavaImageAPI-->>PiccodeImageModule: BufferedImage
    PiccodeImageModule-->>PiccodeRuntime: PiccodeReference(BufferedImage)

    PiccodeRuntime->>PiccodeFilterModule: filter_apply(filter, image)
    PiccodeFilterModule->>JavaImageAPI: filter.filter(image)
    JavaImageAPI-->>PiccodeFilterModule: Filtered BufferedImage
    PiccodeFilterModule-->>PiccodeRuntime: PiccodeReference(Filtered BufferedImage)

    PiccodeRuntime->>PiccodeBrushedMetalFilterModule: brush_metal_new()
    PiccodeBrushedMetalFilterModule->>JavaImageAPI: new BrushedMetalFilter()
    JavaImageAPI-->>PiccodeBrushedMetalFilterModule: BrushedMetalFilter
    PiccodeBrushedMetalFilterModule-->>PiccodeRuntime: PiccodeReference(BrushedMetalFilter)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

In a frame where colors blend and play,
The rabbit hops—new modules on display!
Offscreen we render, with filters anew,
Brushed metal shines with a silvery hue.
Images are born, transformed with delight—
The code hops forward, painting day and night!
🐇✨

Note

🔌 MCP (Model Context Protocol) integration is now available in Early Access!

Pro users can now connect to remote MCP servers under the Integrations page to get reviews and chat conversations that understand additional development context.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 273ff64 and 6e74751.

📒 Files selected for processing (1)
  • pom.xml (1 hunks)
✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch Sibusiso

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@hexaredecimal hexaredecimal merged commit b60365b into main Aug 9, 2025
1 check passed
Copy link
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: 7

🧹 Nitpick comments (3)
src/main/java/org/editor/events/AccessEvents.java (1)

26-26: Nit: message typo

"Cannot compiler unsaved code" → "Cannot compile unsaved code".

-EditorWindow.current_file.setText("Cannot compiler unsaved code");
+EditorWindow.current_file.setText("Cannot compile unsaved code");

Also applies to: 43-43

src/main/java/org/editor/nativemods/PiccodeFilterModule.java (1)

41-43: Clarify error message and type name

Minor: "Expected a buffer image" → "Expected a BufferedImage" for clarity.

-throw new PiccodeException(caller.file, caller.line, caller.column, "Expected a buffer image. Found " + _buffered_image);
+throw new PiccodeException(caller.file, caller.line, caller.column, "Expected a BufferedImage. Found " + _buffered_image);
src/main/java/org/editor/nativemods/PiccodeImageModule.java (1)

69-88: Typo fix and message clarity; document disposal of the returned Graphics2D

  • Rename local var for readability.
  • Message: "BufferedImage".
  • Consider a note in docs that callers must dispose contexts via gfx_drop.
 var _buffered_image = ((PiccodeReference)img).deref();
 
 if (!(_buffered_image instanceof BufferedImage)) {
-  throw new PiccodeException(caller.file, caller.line, caller.column, "Expected a buffer image. Found " + _buffered_image);
+  throw new PiccodeException(caller.file, caller.line, caller.column, "Expected a BufferedImage. Found " + _buffered_image);
 }
 
-var bufferedmage = (BufferedImage) _buffered_image;
-var gfx = bufferedmage.createGraphics();
+var bufferedImage = (BufferedImage) _buffered_image;
+var gfx = bufferedImage.createGraphics();
 return new PiccodeReference(gfx);

Please ensure documentation or examples mention disposing the returned context: use the existing gfx_drop native function to avoid leaks.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6bb4ef6 and 273ff64.

📒 Files selected for processing (5)
  • src/main/java/org/editor/CanvasFrame.java (6 hunks)
  • src/main/java/org/editor/events/AccessEvents.java (1 hunks)
  • src/main/java/org/editor/nativemods/PiccodeBrushedMetalFilterModule.java (1 hunks)
  • src/main/java/org/editor/nativemods/PiccodeFilterModule.java (1 hunks)
  • src/main/java/org/editor/nativemods/PiccodeImageModule.java (1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: hexaredecimal
PR: Glimmr-Lang/PicassoCode#26
File: tests/test_readme_validation.py:233-236
Timestamp: 2025-08-06T23:34:19.770Z
Learning: The PicassoCode project README has specific formatting requirements including: app icon at "./src/main/resources/applogo/appicon.png" with 40% width, repository URL "gitgithub.com:hexaredecimal/Piccode.git", JAR file "Piccode-1.0-SNAPSHOT-jar-with-dependencies.jar", and elaborate ASCII art with "Creativity + Logic + Math" tagline in the license section.
📚 Learning: 2025-05-14T10:49:23.453Z
Learnt from: hexaredecimal
PR: Glimmr-Lang/PicassoCode#1
File: src/main/java/org/editor/EditorWindow.java:204-209
Timestamp: 2025-05-14T10:49:23.453Z
Learning: The VLDocking library (com.vlsolutions.swing.docking) expects dockable components to be owned by the frame while being managed by the docking desktop. Unlike standard Swing components that can only have one parent, the DockingDesktop acts as a manager for dockable components rather than being their parent in the component hierarchy.

Applied to files:

  • src/main/java/org/editor/CanvasFrame.java
📚 Learning: 2025-05-14T10:49:23.453Z
Learnt from: hexaredecimal
PR: Glimmr-Lang/PicassoCode#1
File: src/main/java/org/editor/EditorWindow.java:204-209
Timestamp: 2025-05-14T10:49:23.453Z
Learning: The VLDocking library (com.vlsolutions.swing.docking) has a distinct component management model where UI components are added to both the frame's content pane AND registered with the DockingDesktop. Unlike standard Swing where components can only have one parent, VLDocking expects dockables to be owned by the frame while being managed by the docking desktop for layout, docking states, and behaviors.

Applied to files:

  • src/main/java/org/editor/CanvasFrame.java
📚 Learning: 2025-08-06T23:34:19.770Z
Learnt from: hexaredecimal
PR: Glimmr-Lang/PicassoCode#26
File: tests/test_readme_validation.py:233-236
Timestamp: 2025-08-06T23:34:19.770Z
Learning: The PicassoCode project README has specific formatting requirements including: app icon at "./src/main/resources/applogo/appicon.png" with 40% width, repository URL "gitgithub.com:hexaredecimal/Piccode.git", JAR file "Piccode-1.0-SNAPSHOT-jar-with-dependencies.jar", and elaborate ASCII art with "Creativity + Logic + Math" tagline in the license section.

Applied to files:

  • src/main/java/org/editor/nativemods/PiccodeImageModule.java
🧬 Code Graph Analysis (3)
src/main/java/org/editor/events/AccessEvents.java (2)
src/main/java/org/editor/CanvasFrame.java (1)
  • CanvasFrame (43-348)
src/main/java/org/editor/AccessFrame.java (1)
  • AccessFrame (40-279)
src/main/java/org/editor/CanvasFrame.java (1)
src/main/java/org/editor/nativemods/PiccodeGfxModule.java (3)
  • PiccodeGfxModule (23-106)
  • args (31-63)
  • args (26-29)
src/main/java/org/editor/nativemods/PiccodeImageModule.java (2)
src/main/java/org/editor/nativemods/PiccodePenModule.java (6)
  • PiccodePenModule (23-170)
  • addFunctions (25-168)
  • args (61-93)
  • args (95-133)
  • args (135-167)
  • args (27-59)
src/main/java/org/editor/nativemods/PiccodeGfxModule.java (4)
  • addFunctions (25-104)
  • PiccodeGfxModule (23-106)
  • args (31-63)
  • args (64-83)
🪛 GitHub Actions: Java CI with Maven
src/main/java/org/editor/nativemods/PiccodeBrushedMetalFilterModule.java

[error] 3-3: Compilation error: package com.jhlabs.image does not exist.


[error] 28-102: Compilation error: cannot find symbol class BrushedMetalFilter in multiple locations within the file.

🔇 Additional comments (6)
src/main/java/org/editor/CanvasFrame.java (3)

78-78: Good initialization

Priming the offscreen buffer once in the constructor via compile(() -> null) is a sensible default.


116-118: Offscreen buffer draw is correct

Rendering the cached render image onto the panel decouples painting from compilation and is the right direction for performance.


299-301: Good: disposing grid graphics

Explicitly disposing the grid Graphics2D is correct and prevents native resource leaks.

src/main/java/org/editor/nativemods/PiccodeFilterModule.java (1)

49-52: Filter application flow looks good

Type verification and BufferedImageOp.filter usage are correct. Returning a new reference to the filtered image is appropriate.

src/main/java/org/editor/nativemods/PiccodeBrushedMetalFilterModule.java (2)

28-30: Creation function looks fine

Creating and returning a BrushedMetalFilter wrapped in PiccodeReference is correct.


32-56: Radius setter is correct

Type checks and setRadius usage look good.

Comment on lines +302 to 323
public void compile(Supplier<PiccodeValue> fx) {
int width = getWidth();
int height = getHeight();
if (width <= 0 || height <= 0) {
return;
}

render = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);

// Get the Graphics2D object
gfx = render.createGraphics();

// Enable transparency by drawing a fully transparent background
gfx.setComposite(AlphaComposite.Clear);
gfx.fillRect(0, 0, width, height);

gfx.setColor(Color.BLACK);
// Switch back to normal composite mode for drawing
gfx.setComposite(AlphaComposite.SrcOver);

fx.get();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Dispose previous gfx and reuse buffers; avoid leaks and allocations; repaint after compile

The current compile always allocates a new BufferedImage, reassigns gfx, and never disposes the previous Graphics2D. This leaks native resources and increases GC pressure. Also, if the component size hasn't changed, you can reuse the existing buffer.

Proposed fix:

  • Dispose the previous gfx before creating a new one (or reuse existing when size unchanged).
  • Reuse render if width/height are unchanged and just clear it.
  • Set useful rendering hints on gfx.
  • Trigger a repaint after updating the offscreen buffer.
 public void compile(Supplier<PiccodeValue> fx) {
   int width = getWidth();
   int height = getHeight();
   if (width <= 0 || height <= 0) {
     return;
   }
-
-  render = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
-
-  // Get the Graphics2D object
-  gfx = render.createGraphics();
-
-  // Enable transparency by drawing a fully transparent background
-  gfx.setComposite(AlphaComposite.Clear);
-  gfx.fillRect(0, 0, width, height);
-
-  gfx.setColor(Color.BLACK);
-  // Switch back to normal composite mode for drawing
-  gfx.setComposite(AlphaComposite.SrcOver);
-
-  fx.get();
+  // Reuse buffer if size unchanged; otherwise dispose and recreate
+  boolean recreate = render == null || render.getWidth() != width || render.getHeight() != height;
+  if (recreate) {
+    if (gfx != null) {
+      try { gfx.dispose(); } catch (Exception ignore) {}
+    }
+    render = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+    gfx = render.createGraphics();
+    // Optional: quality hints for higher fidelity drawing to the offscreen buffer
+    gfx.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+    gfx.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
+    gfx.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+  }
+
+  // Clear buffer to full transparency
+  gfx.setComposite(AlphaComposite.Clear);
+  gfx.fillRect(0, 0, width, height);
+  gfx.setComposite(AlphaComposite.SrcOver);
+  gfx.setColor(Color.BLACK);
+
+  // Execute supplied drawing/compilation logic
+  fx.get();
+
+  // Ensure the latest image is presented
+  repaint(getVisibleRect());
 }

Note: If you plan to allow long-running drawing from background threads into gfx, consider guarding gfx and render with a lock and using a snapshot for painting to avoid tearing/races.

📝 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
public void compile(Supplier<PiccodeValue> fx) {
int width = getWidth();
int height = getHeight();
if (width <= 0 || height <= 0) {
return;
}
render = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
// Get the Graphics2D object
gfx = render.createGraphics();
// Enable transparency by drawing a fully transparent background
gfx.setComposite(AlphaComposite.Clear);
gfx.fillRect(0, 0, width, height);
gfx.setColor(Color.BLACK);
// Switch back to normal composite mode for drawing
gfx.setComposite(AlphaComposite.SrcOver);
fx.get();
}
public void compile(Supplier<PiccodeValue> fx) {
int width = getWidth();
int height = getHeight();
if (width <= 0 || height <= 0) {
return;
}
// Reuse buffer if size unchanged; otherwise dispose and recreate
boolean recreate = render == null
|| render.getWidth() != width
|| render.getHeight() != height;
if (recreate) {
if (gfx != null) {
try {
gfx.dispose();
} catch (Exception ignore) {
}
}
render = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
gfx = render.createGraphics();
// Optional: quality hints for higher-fidelity drawing to the offscreen buffer
gfx.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
gfx.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
gfx.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
}
// Clear buffer to full transparency
gfx.setComposite(AlphaComposite.Clear);
gfx.fillRect(0, 0, width, height);
gfx.setComposite(AlphaComposite.SrcOver);
gfx.setColor(Color.BLACK);
// Execute supplied drawing/compilation logic
fx.get();
// Ensure the latest image is presented
repaint(getVisibleRect());
}
🤖 Prompt for AI Agents
In src/main/java/org/editor/CanvasFrame.java lines 302 to 323, the compile
method leaks native resources by not disposing the previous gfx Graphics2D
object and always allocating a new BufferedImage even if the size is unchanged.
Fix this by checking if the current render buffer matches the component size; if
so, reuse it by clearing its content instead of creating a new one. If a new
BufferedImage is needed, dispose the old gfx before creating a new one. Also,
set appropriate rendering hints on gfx for better quality and call repaint()
after updating the buffer to refresh the display.

CanvasFrame.file = file;
CanvasFrame.code = code;
CanvasFrame.start = true;
CanvasFrame.the().compile(() -> Compiler.compile(file, code));
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Avoid blocking the EDT during compilation

Compiler.compile(file, code) likely does non-trivial work. Invoking it inside compile(...) from an ActionEvent runs on the Swing EDT and can freeze the UI. Consider splitting CanvasFrame.compile into:

  • a lightweight EDT setup that (re)creates the offscreen buffer/graphics, then
  • executing fx.get() on a background worker, drawing into the offscreen Graphics2D, and finally repaint() on EDT.

At minimum, ensure heavy parts of fx.get() aren't executed on the EDT.


🏁 Script executed:

#!/bin/bash
set -e
# Locate CanvasFrame source file
file=$(rg -l "class CanvasFrame" src | head -n1)
echo "CanvasFrame file: $file"
# Show occurrences of compile( within CanvasFrame, with context
rg -n "compile(" -C3 "$file"

Length of output: 363


🏁 Script executed:

#!/bin/bash
set -e
# Inspect all compile( calls in CanvasFrame.java using fixed-string search to avoid regex errors
file="src/main/java/org/editor/CanvasFrame.java"
echo "CanvasFrame file: $file"
rg -n -F 'compile(' -C3 "$file"

Length of output: 702


🏁 Script executed:

#!/bin/bash
set -e
file="src/main/java/org/editor/CanvasFrame.java"
echo "Extracting `compile(Supplier<PiccodeValue> fx)` implementation:"
sed -n '300,360p' "$file"

Length of output: 1572


Offload heavy compilation from the Swing EDT

Currently, CanvasFrame.compile(Supplier<PiccodeValue> fx) (src/main/java/org/editor/CanvasFrame.java around line 302) does all setup and then calls fx.get() on the EDT. When fx.get() wraps Compiler.compile(file, code), the UI will freeze until compilation finishes.

To fix:

  • In compile(...), perform only the offscreen-buffer creation and Graphics2D setup on the EDT.
  • Move the blocking fx.get() call into a background worker (e.g., SwingWorker or an ExecutorService).
  • In the worker’s completion callback, invoke repaint(getVisibleRect()) on the EDT to update the display.

Example sketch using SwingWorker:

public void compileAsync(Supplier<PiccodeValue> fx) {
    int w = getWidth(), h = getHeight();
    if (w <= 0 || h <= 0) return;

    // EDT: prepare offscreen buffer
    render = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
    gfx = render.createGraphics();
    gfx.setComposite(AlphaComposite.Clear);
    gfx.fillRect(0, 0, w, h);
    gfx.setComposite(AlphaComposite.SrcOver);
    gfx.setColor(Color.BLACK);

    // Background: run heavy work
    new SwingWorker<PiccodeValue, Void>() {
        @Override
        protected PiccodeValue doInBackground() {
            return fx.get();  // compiles off EDT
        }
        @Override
        protected void done() {
            // EDT: repaint with new contents
            try { get(); } catch (Exception ignored) {}
            repaint(getVisibleRect());
        }
    }.execute();
}

Then update your call in AccessEvents to use compileAsync(...) instead of compile(...).

🤖 Prompt for AI Agents
In src/main/java/org/editor/events/AccessEvents.java at line 32, the call to
CanvasFrame.the().compile(...) runs the heavy compilation on the Swing EDT,
causing UI freezes. To fix this, update CanvasFrame to add a
compileAsync(Supplier<PiccodeValue>) method that does offscreen buffer setup on
the EDT, then runs fx.get() in a SwingWorker background thread, and repaints on
completion. Then change this line to call compileAsync(...) instead of
compile(...), ensuring compilation happens off the EDT and the UI remains
responsive.

@@ -0,0 +1,112 @@
package org.editor.nativemods;

import com.jhlabs.image.BrushedMetalFilter;
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Build failing: missing JHLabs Filters dependency

CI error: “package com.jhlabs.image does not exist”. Add the JHLabs Filters library to your build (Maven/Gradle) or vendor the jar.

If using Maven, add the dependency to pom.xml once confirmed, e.g.:

<dependency>
  <groupId><!-- com.jhlabs or correct groupId --></groupId>
  <artifactId><!-- filters or correct artifactId --></artifactId>
  <version><!-- latest stable version --></version>
</dependency>

🌐 Web query:

What are the correct Maven coordinates (groupId/artifactId/version) for the JHLabs image filters containing com.jhlabs.image.BrushedMetalFilter?

💡 Result:

The correct Maven coordinates for the JHLabs image filters library containing com.jhlabs.image.BrushedMetalFilter are:

  • groupId: com.jhlabs
  • artifactId: filters
  • version: 2.0.235-1

A typical Maven dependency block would look like:

<dependency>
  <groupId>com.jhlabs</groupId>
  <artifactId>filters</artifactId>
  <version>2.0.235-1</version>
</dependency>

This version is the most current and recommended for use from Maven Central, according to multiple authoritative sources[4][6][10]. The class com.jhlabs.image.BrushedMetalFilter is included in this artifact[5].

Alternative version:

  • Slightly older versions, such as 2.0.235, may also contain the filter but 2.0.235-1 is newer and preferred[6][10].

Notes:

  • The library is licensed under the Apache 2.0 License[10].
  • The official homepage for more information is [http://www.jhlabs.com/ip/filters/][10].
  • No additional compile dependencies are required for basic usage[10].

Citations:


🏁 Script executed:

#!/bin/bash
# Locate all usages of BrushedMetalFilter to inspect setter methods
rg -n 'BrushedMetalFilter' -n src/main/java

Length of output: 1195


🏁 Script executed:

#!/bin/bash
# Inspect all setter calls on the BrushedMetalFilter instance
rg -n "filter\.set" -n src/main/java/org/editor/nativemods/PiccodeBrushedMetalFilterModule.java

Length of output: 195


🌐 Web query:

List the setter methods available on com.jhlabs.image.BrushedMetalFilter in version 2.0.235-1

💡 Result:

The setter methods available on com.jhlabs.image.BrushedMetalFilter in version 2.0.235-1 are not listed explicitly in the provided search results, but essential parameters and likely corresponding setters are documented in the JHLabs Brushed Metal Filter documentation[5]. The filter has the following configurable properties:

  • Color (the color of the metal)
  • Radius (the "radius" of the blur)
  • Amount (the amount of noise to add, range 0-1)
  • Monochrome (true if the noise should be monochrome)
  • Shine (the amount of shine to add, range 0-1)

Based on standard JavaBeans conventions, the corresponding setter methods are highly likely to be:

  • setColor(int color)
  • setRadius(float radius)
  • setAmount(float amount)
  • setMonochrome(boolean monochrome)
  • setShine(float shine)

This inference is grounded in the fact that these parameters are explicitly documented as the adjustable parameters for the filter in the official documentation[5], and the naming pattern is consistent with other JHLabs filters[1].

Summary Table of Expected Setter Methods

Property Setter Method Parameter Type
Color setColor int
Radius setRadius float
Amount setAmount float
Monochrome setMonochrome boolean
Shine setShine float

If you require the precise method signatures from the actual source, examining the source code for version 2.0.235-1 directly would guarantee accuracy[2]. However, all available documentation and usage examples point to the existence of these methods with the names and types shown above[5][1].

Citations:


Add JHLabs Filters dependency & correct BrushedMetalFilter setters

Ensure you’ve added the JHLabs Filters library so the import resolves, and fix two incorrect setter calls for amount and shine.

• In your build (Maven), add to pom.xml:

<dependency>
  <groupId>com.jhlabs</groupId>
  <artifactId>filters</artifactId>
  <version>2.0.235-1</version>
</dependency>

• In PiccodeBrushedMetalFilterModule.java, update the two misplaced setRadius calls:

– At line 79:

- filter.setRadius(_amount);
+ filter.setAmount(_amount);

– At line 105:

- filter.setRadius(_shine);
+ filter.setShine(_shine);

The original filter.setRadius(radius) (line 53) is correct; only the amount and shine setters were misplaced.

🧰 Tools
🪛 GitHub Actions: Java CI with Maven

[error] 3-3: Compilation error: package com.jhlabs.image does not exist.

🤖 Prompt for AI Agents
In src/main/java/org/editor/nativemods/PiccodeBrushedMetalFilterModule.java at
line 3, ensure the JHLabs Filters library is added to your Maven pom.xml as a
dependency with groupId com.jhlabs, artifactId filters, and version 2.0.235-1 to
resolve the import. Then, in the same file around lines 79 and 105, replace the
incorrect calls to filter.setRadius with the correct setters filter.setAmount
and filter.setShine respectively, keeping the original filter.setRadius call at
line 53 unchanged.

Comment on lines +58 to +82
NativeFunctionFactory.create("brush_metal_set_amount", List.of("filter", "amount"), (args, namedArgs, frame) -> {
var _filter = namedArgs.get("filter");
var amount = namedArgs.get("amount");

var ctx = frame == null
? Context.top
: Context.getContextAt(frame);
var caller = ctx.getTopFrame().caller;

PiccodeValue.verifyType(caller, _filter, Type.REFERENCE);
PiccodeValue.verifyType(caller, amount, Type.NUMBER);

var obj = (PiccodeReference) _filter;
var _filter_object = obj.deref();
if (!(_filter_object instanceof BrushedMetalFilter)) {
throw new PiccodeException(caller.file, caller.line, caller.column, "Filter is not a correct object.");
}

var filter = (BrushedMetalFilter) _filter_object;
var _amount = (int) (double) ((PiccodeNumber) amount).raw();

filter.setRadius(_amount);

return new PiccodeReference(_filter_object);
}, null);
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Bug: using setRadius for 'amount'; use the correct setter and type

brush_metal_set_amount calls filter.setRadius(_amount). That’s incorrect. Use the actual amount setter (likely setAmount) and match parameter type (amount is typically float/double in JHLabs).

- var _amount = (int) (double) ((PiccodeNumber) amount).raw();
-
- filter.setRadius(_amount);
+ var _amount = (float) (double) ((PiccodeNumber) amount).raw();
+ filter.setAmount(_amount);

Please confirm the exact setter signature for BrushedMetalFilter amount and adjust the cast accordingly.


🌐 Web query:

What is the method signature of setAmount in com.jhlabs.image.BrushedMetalFilter?

💡 Result:

The BrushedMetalFilter class from the JH Labs Java Image Filters library includes a method named setAmount. This method allows you to adjust the intensity of the brushed metal effect applied to an image. The method signature is:

public void setAmount(float amount)

Here, amount is a floating-point value that specifies the strength of the effect. A higher value results in a more pronounced brushed metal appearance.

For more details on the BrushedMetalFilter class and its methods, you can refer to the JH Labs Java Image Filters repository on GitHub.


Use setAmount(float) instead of setRadius(int) in brush_metal_set_amount

We’ve confirmed that BrushedMetalFilter#setAmount is declared as:

public void setAmount(float amount)

Update the code in src/main/java/org/editor/nativemods/PiccodeBrushedMetalFilterModule.java (lines 58–82) accordingly:

- var _amount = (int) (double) ((PiccodeNumber) amount).raw();
- filter.setRadius(_amount);
+ var _amount = (float) (double) ((PiccodeNumber) amount).raw();
+ filter.setAmount(_amount);
🤖 Prompt for AI Agents
In src/main/java/org/editor/nativemods/PiccodeBrushedMetalFilterModule.java
between lines 58 and 82, the method brush_metal_set_amount incorrectly calls
setRadius(int) on BrushedMetalFilter. Replace this call with setAmount(float) by
converting the amount argument to a float instead of an int, and then invoke
filter.setAmount with that float value.

Comment on lines +84 to +108
NativeFunctionFactory.create("brush_metal_set_shine", List.of("filter", "shine"), (args, namedArgs, frame) -> {
var _filter = namedArgs.get("filter");
var shine = namedArgs.get("shine");

var ctx = frame == null
? Context.top
: Context.getContextAt(frame);
var caller = ctx.getTopFrame().caller;

PiccodeValue.verifyType(caller, _filter, Type.REFERENCE);
PiccodeValue.verifyType(caller, shine, Type.NUMBER);

var obj = (PiccodeReference) _filter;
var _filter_object = obj.deref();
if (!(_filter_object instanceof BrushedMetalFilter)) {
throw new PiccodeException(caller.file, caller.line, caller.column, "Filter is not a correct object.");
}

var filter = (BrushedMetalFilter) _filter_object;
var _shine = (int) (double) ((PiccodeNumber) shine).raw();

filter.setRadius(_shine);

return new PiccodeReference(_filter_object);
}, null);
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Bug: using setRadius for 'shine'; use the correct setter and type

brush_metal_set_shine also calls setRadius. Use the shine setter (likely setShine) with the correct type (likely float).

- var _shine = (int) (double) ((PiccodeNumber) shine).raw();
-
- filter.setRadius(_shine);
+ var _shine = (float) (double) ((PiccodeNumber) shine).raw();
+ filter.setShine(_shine);

Please verify BrushedMetalFilter API for the correct setter name and parameter type.


🏁 Script executed:

#!/bin/bash
# Search for the BrushedMetalFilter class to inspect its API
rg "class BrushedMetalFilter" -A 100

# Check for any setShine methods in the codebase
rg "setShine" -n

# Confirm existing setRadius usages on BrushedMetalFilter
rg "setRadius" -n

Length of output: 390


🌐 Web query:

com.jhlabs.image.BrushedMetalFilter Javadoc methods list

💡 Result:

The com.jhlabs.image.BrushedMetalFilter class provides image processing functionality to generate a brushed metal texture. While direct, complete Javadoc for its methods is not available in the provided search results, typical JHLabs image filters—including BrushedMetalFilter—expose a consistent set of methods based on Java image filter conventions and documentation[1][6].

Here is the most likely list of methods (based on JHLabs filter conventions and third-party documentation):

BrushedMetalFilter Methods (typical):

  • filter(BufferedImage src, BufferedImage dest)
    Applies the filter to a source image and produces a destination image.

  • setColor(Color color)
    Sets the base color of the brushed metal texture.

  • getColor()
    Returns the current base color setting.

  • setBrushLength(float length)
    Sets the length of the brush strokes in the texture.

  • getBrushLength()
    Returns the currently set brush length.

  • setAmount(float amount)
    Sets the amount of noise or intensity in the texture effect.

  • getAmount()
    Returns the current noise/intensity amount.

  • setMonochrome(boolean mono)
    Enables or disables a monochrome effect for the brushed metal.

  • isMonochrome()
    Returns if the monochrome effect is enabled.

  • setShine(float shine)
    Adjusts how shiny the metal effect appears.

  • getShine()
    Returns the currently set shine value.

  • Other inherited or utility methods from BufferedImageOp (e.g., createCompatibleDestImage, getBounds2D, getPoint2D) are typically present in JHLabs filters[1].

Context and Details:

  • JHLabs filters commonly use setXXX() and corresponding getXXX() methods for each configurable parameter[1].
  • The main processing is typically performed by the filter() method, which takes input and output BufferedImage instances and returns the result[1].
  • Parameters like color, brush length, amount, monochrome, and shine allow precise control over the metal texture, as described in official documentation and articles on JHLabs[6].

If you need method signatures or more technical documentation, access to the actual source code (e.g., via GitHub or the official JHLabs site) is recommended. However, the methods listed above reflect the standard configuration pattern for this class within the JHLabs filter library[1][6].

Citations:


Replace setRadius with setShine(float) in the shine setter

Based on the JHLabs BrushedMetalFilter API, setShine(float) is the correct method and it accepts a float, not an int.

• File: src/main/java/org/editor/nativemods/PiccodeBrushedMetalFilterModule.java
Lines: 84–108 (inside the "brush_metal_set_shine" factory)

-   var _shine = (int) (double) ((PiccodeNumber) shine).raw();
-   filter.setRadius(_shine);
+   var _shine = (float) ((PiccodeNumber) shine).raw();
+   filter.setShine(_shine);
📝 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
NativeFunctionFactory.create("brush_metal_set_shine", List.of("filter", "shine"), (args, namedArgs, frame) -> {
var _filter = namedArgs.get("filter");
var shine = namedArgs.get("shine");
var ctx = frame == null
? Context.top
: Context.getContextAt(frame);
var caller = ctx.getTopFrame().caller;
PiccodeValue.verifyType(caller, _filter, Type.REFERENCE);
PiccodeValue.verifyType(caller, shine, Type.NUMBER);
var obj = (PiccodeReference) _filter;
var _filter_object = obj.deref();
if (!(_filter_object instanceof BrushedMetalFilter)) {
throw new PiccodeException(caller.file, caller.line, caller.column, "Filter is not a correct object.");
}
var filter = (BrushedMetalFilter) _filter_object;
var _shine = (int) (double) ((PiccodeNumber) shine).raw();
filter.setRadius(_shine);
return new PiccodeReference(_filter_object);
}, null);
NativeFunctionFactory.create("brush_metal_set_shine", List.of("filter", "shine"), (args, namedArgs, frame) -> {
var _filter = namedArgs.get("filter");
var shine = namedArgs.get("shine");
var ctx = frame == null
? Context.top
: Context.getContextAt(frame);
var caller = ctx.getTopFrame().caller;
PiccodeValue.verifyType(caller, _filter, Type.REFERENCE);
PiccodeValue.verifyType(caller, shine, Type.NUMBER);
var obj = (PiccodeReference) _filter;
var _filter_object = obj.deref();
if (!(_filter_object instanceof BrushedMetalFilter)) {
throw new PiccodeException(caller.file, caller.line, caller.column, "Filter is not a correct object.");
}
var filter = (BrushedMetalFilter) _filter_object;
var _shine = (float) ((PiccodeNumber) shine).raw();
filter.setShine(_shine);
return new PiccodeReference(_filter_object);
}, null);
🤖 Prompt for AI Agents
In src/main/java/org/editor/nativemods/PiccodeBrushedMetalFilterModule.java
lines 84 to 108, replace the call to filter.setRadius(_shine) with
filter.setShine(_shine) and ensure _shine is converted to a float instead of an
int. This aligns with the JHLabs BrushedMetalFilter API which requires
setShine(float) for setting the shine value.

Comment on lines +28 to +45
NativeFunctionFactory.create("image_new", List.of("w", "h"), (args, namedArgs, frame) -> {
var w = namedArgs.get("w");
var h = namedArgs.get("h");

var ctx = frame == null ?
Context.top
: Context.getContextAt(frame);
var caller = ctx.getTopFrame().caller;

PiccodeValue.verifyType(caller, w, Type.NUMBER);
PiccodeValue.verifyType(caller, h, Type.NUMBER);

var _w = (int) (double) ((PiccodeNumber) w).raw();
var _h = (int) (double) ((PiccodeNumber) h).raw();

var image = new BufferedImage(_w, _h, BufferedImage.TYPE_INT_ARGB);
return new PiccodeReference(image);
}, null);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Validate image dimensions and surface IllegalArgumentException as PiccodeException

Creating a BufferedImage with non-positive dimensions throws IllegalArgumentException. Validate inputs and raise a PiccodeException with caller info for better diagnostics.

 PiccodeValue.verifyType(caller, w, Type.NUMBER);
 PiccodeValue.verifyType(caller, h, Type.NUMBER);
 
 var _w = (int) (double) ((PiccodeNumber) w).raw();
 var _h = (int) (double) ((PiccodeNumber) h).raw();
 
-var image = new BufferedImage(_w, _h, BufferedImage.TYPE_INT_ARGB);
+if (_w <= 0 || _h <= 0) {
+  throw new PiccodeException(caller.file, caller.line, caller.column, "Image dimensions must be > 0. Got: " + _w + "x" + _h);
+}
+BufferedImage image;
+try {
+  image = new BufferedImage(_w, _h, BufferedImage.TYPE_INT_ARGB);
+} catch (IllegalArgumentException iae) {
+  throw new PiccodeException(caller.file, caller.line, caller.column, "Invalid image dimensions: " + _w + "x" + _h);
+}
 return new PiccodeReference(image);
📝 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
NativeFunctionFactory.create("image_new", List.of("w", "h"), (args, namedArgs, frame) -> {
var w = namedArgs.get("w");
var h = namedArgs.get("h");
var ctx = frame == null ?
Context.top
: Context.getContextAt(frame);
var caller = ctx.getTopFrame().caller;
PiccodeValue.verifyType(caller, w, Type.NUMBER);
PiccodeValue.verifyType(caller, h, Type.NUMBER);
var _w = (int) (double) ((PiccodeNumber) w).raw();
var _h = (int) (double) ((PiccodeNumber) h).raw();
var image = new BufferedImage(_w, _h, BufferedImage.TYPE_INT_ARGB);
return new PiccodeReference(image);
}, null);
NativeFunctionFactory.create("image_new", List.of("w", "h"), (args, namedArgs, frame) -> {
var w = namedArgs.get("w");
var h = namedArgs.get("h");
var ctx = frame == null
? Context.top
: Context.getContextAt(frame);
var caller = ctx.getTopFrame().caller;
PiccodeValue.verifyType(caller, w, Type.NUMBER);
PiccodeValue.verifyType(caller, h, Type.NUMBER);
var _w = (int) (double) ((PiccodeNumber) w).raw();
var _h = (int) (double) ((PiccodeNumber) h).raw();
if (_w <= 0 || _h <= 0) {
throw new PiccodeException(
caller.file, caller.line, caller.column,
"Image dimensions must be > 0. Got: " + _w + "x" + _h
);
}
BufferedImage image;
try {
image = new BufferedImage(_w, _h, BufferedImage.TYPE_INT_ARGB);
} catch (IllegalArgumentException iae) {
throw new PiccodeException(
caller.file, caller.line, caller.column,
"Invalid image dimensions: " + _w + "x" + _h
);
}
return new PiccodeReference(image);
}, null);
🤖 Prompt for AI Agents
In src/main/java/org/editor/nativemods/PiccodeImageModule.java around lines 28
to 45, the code creates a BufferedImage without validating that width and height
are positive, which can throw IllegalArgumentException. Add checks after
extracting _w and _h to verify they are greater than zero. If not, throw a new
PiccodeException including the caller information and a clear message about
invalid image dimensions to improve error handling and diagnostics.

Comment on lines +47 to +67
NativeFunctionFactory.create("image_new_typed", List.of("w", "h", "type"), (args, namedArgs, frame) -> {
var w = namedArgs.get("w");
var h = namedArgs.get("h");
var type = namedArgs.get("type");

var ctx = frame == null ?
Context.top
: Context.getContextAt(frame);
var caller = ctx.getTopFrame().caller;

PiccodeValue.verifyType(caller, w, Type.NUMBER);
PiccodeValue.verifyType(caller, h, Type.NUMBER);
PiccodeValue.verifyType(caller, type, Type.NUMBER);

var _w = (int) (double) ((PiccodeNumber) w).raw();
var _h = (int) (double) ((PiccodeNumber) h).raw();
var _type = (int) (double) ((PiccodeNumber) type).raw();

var image = new BufferedImage(_w, _h, _type);
return new PiccodeReference(image);
}, null);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Same validation for typed image creation

Apply the same dimension validation and exception mapping for image_new_typed.

 var _w = (int) (double) ((PiccodeNumber) w).raw();
 var _h = (int) (double) ((PiccodeNumber) h).raw();
 var _type = (int) (double) ((PiccodeNumber) type).raw();
 
-var image = new BufferedImage(_w, _h, _type);
+if (_w <= 0 || _h <= 0) {
+  throw new PiccodeException(caller.file, caller.line, caller.column, "Image dimensions must be > 0. Got: " + _w + "x" + _h);
+}
+BufferedImage image;
+try {
+  image = new BufferedImage(_w, _h, _type);
+} catch (IllegalArgumentException iae) {
+  throw new PiccodeException(caller.file, caller.line, caller.column, "Invalid image args: " + _w + "x" + _h + ", type=" + _type);
+}
 return new PiccodeReference(image);
📝 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
NativeFunctionFactory.create("image_new_typed", List.of("w", "h", "type"), (args, namedArgs, frame) -> {
var w = namedArgs.get("w");
var h = namedArgs.get("h");
var type = namedArgs.get("type");
var ctx = frame == null ?
Context.top
: Context.getContextAt(frame);
var caller = ctx.getTopFrame().caller;
PiccodeValue.verifyType(caller, w, Type.NUMBER);
PiccodeValue.verifyType(caller, h, Type.NUMBER);
PiccodeValue.verifyType(caller, type, Type.NUMBER);
var _w = (int) (double) ((PiccodeNumber) w).raw();
var _h = (int) (double) ((PiccodeNumber) h).raw();
var _type = (int) (double) ((PiccodeNumber) type).raw();
var image = new BufferedImage(_w, _h, _type);
return new PiccodeReference(image);
}, null);
NativeFunctionFactory.create("image_new_typed", List.of("w", "h", "type"), (args, namedArgs, frame) -> {
var w = namedArgs.get("w");
var h = namedArgs.get("h");
var type = namedArgs.get("type");
var ctx = frame == null ?
Context.top
: Context.getContextAt(frame);
var caller = ctx.getTopFrame().caller;
PiccodeValue.verifyType(caller, w, Type.NUMBER);
PiccodeValue.verifyType(caller, h, Type.NUMBER);
PiccodeValue.verifyType(caller, type, Type.NUMBER);
var _w = (int) (double) ((PiccodeNumber) w).raw();
var _h = (int) (double) ((PiccodeNumber) h).raw();
var _type = (int) (double) ((PiccodeNumber) type).raw();
if (_w <= 0 || _h <= 0) {
throw new PiccodeException(caller.file, caller.line, caller.column,
"Image dimensions must be > 0. Got: " + _w + "x" + _h);
}
BufferedImage image;
try {
image = new BufferedImage(_w, _h, _type);
} catch (IllegalArgumentException iae) {
throw new PiccodeException(caller.file, caller.line, caller.column,
"Invalid image args: " + _w + "x" + _h + ", type=" + _type);
}
return new PiccodeReference(image);
}, null);
🤖 Prompt for AI Agents
In src/main/java/org/editor/nativemods/PiccodeImageModule.java lines 47 to 67,
the image_new_typed function lacks dimension validation and exception mapping
present in other image creation functions. Add checks to ensure width and height
are positive integers and wrap the BufferedImage creation in a try-catch block
to map exceptions to Piccode exceptions, providing consistent validation and
error handling.

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants