This is an automated email from the ASF dual-hosted git repository.

mattcasters pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git


The following commit(s) were added to refs/heads/main by this push:
     new 8c2135a883 Fix image notepad rendering issue #8869 (#8945)
8c2135a883 is described below

commit 8c2135a88375581605599b686dc41e39160c18b9
Author: William Evan Lomanto <[email protected]>
AuthorDate: Mon Oct 19 19:57:41 2026 +0700

    Fix image notepad rendering issue #8869 (#8945)
    
    * Fix image notepad rendering issue
    
    Reviewer Changes Suggestion
    
    * spotless
    
    ---------
    
    Co-authored-by: Hans Van Akelyen <[email protected]>
---
 .../hop/core/gui/markdown/NoteImageSupport.java    | 37 +++++++++++++++++++---
 .../core/gui/markdown/NoteImageSupportTest.java    | 20 ++++++++++++
 .../org/apache/hop/ui/hopgui/shared/SwtGc.java     | 16 +++++++---
 3 files changed, 64 insertions(+), 9 deletions(-)

diff --git 
a/engine/src/main/java/org/apache/hop/core/gui/markdown/NoteImageSupport.java 
b/engine/src/main/java/org/apache/hop/core/gui/markdown/NoteImageSupport.java
index 164fc1c3b7..144d3dc5f9 100644
--- 
a/engine/src/main/java/org/apache/hop/core/gui/markdown/NoteImageSupport.java
+++ 
b/engine/src/main/java/org/apache/hop/core/gui/markdown/NoteImageSupport.java
@@ -42,6 +42,12 @@ public final class NoteImageSupport {
   /** Soft cap on rendered image height in canvas units. */
   public static final int DEFAULT_MAX_HEIGHT = 200;
 
+  /** Minimum rendered image dimension in canvas units; avoids degenerate 1px 
rasters. */
+  public static final int MIN_RENDERED_SIZE = 8;
+
+  /** Hard cap on any rendered image dimension in canvas units; guards against 
huge rasters. */
+  public static final int MAX_RENDERED_SIZE = 2048;
+
   private static final Map<String, ImageInfo> SIZE_CACHE = new 
ConcurrentHashMap<>();
 
   private NoteImageSupport() {}
@@ -177,22 +183,45 @@ public final class NoteImageSupport {
     return lower.endsWith(".svg");
   }
 
-  /** Fit image into max box preserving aspect ratio. */
+  /**
+   * Fit an image into the given max box, preserving aspect ratio. The result 
never exceeds the box
+   * or {@link #MAX_RENDERED_SIZE}. A very wide or tall image keeps its thin 
axis short rather than
+   * being grown past the box.
+   */
   public static Point fit(int srcW, int srcH, int maxWidth, int maxHeight) {
     if (srcW <= 0 || srcH <= 0) {
-      return new Point(Math.max(1, maxWidth), Math.max(1, maxHeight));
+      return new Point(bound(maxWidth), bound(maxHeight));
     }
-    int mw = Math.max(1, maxWidth);
-    int mh = Math.max(1, maxHeight);
+    int mw = bound(maxWidth);
+    int mh = bound(maxHeight);
     double scale = Math.min((double) mw / srcW, (double) mh / srcH);
     if (scale > 1.0) {
       scale = 1.0; // do not upscale small icons excessively on canvas
     }
     int w = Math.max(1, (int) Math.round(srcW * scale));
     int h = Math.max(1, (int) Math.round(srcH * scale));
+
+    if (w < MIN_RENDERED_SIZE || h < MIN_RENDERED_SIZE) {
+      double up = Math.max((double) MIN_RENDERED_SIZE / w, (double) 
MIN_RENDERED_SIZE / h);
+      up = Math.min(up, Math.min((double) mw / w, (double) mh / h));
+      if (up > 1.0) {
+        w = Math.clamp(Math.round(w * up), 1, mw);
+        h = Math.clamp(Math.round(h * up), 1, mh);
+      }
+    }
+    // Never rasterise an enormous bitmap on the canvas
+    if (w > MAX_RENDERED_SIZE || h > MAX_RENDERED_SIZE) {
+      double down = Math.min((double) MAX_RENDERED_SIZE / w, (double) 
MAX_RENDERED_SIZE / h);
+      w = Math.max(1, (int) Math.round(w * down));
+      h = Math.max(1, (int) Math.round(h * down));
+    }
     return new Point(w, h);
   }
 
+  private static int bound(int value) {
+    return Math.max(1, Math.min(value, MAX_RENDERED_SIZE));
+  }
+
   /** Test helper / memory bound. */
   static void clearCache() {
     SIZE_CACHE.clear();
diff --git 
a/engine/src/test/java/org/apache/hop/core/gui/markdown/NoteImageSupportTest.java
 
b/engine/src/test/java/org/apache/hop/core/gui/markdown/NoteImageSupportTest.java
index 83c2d40980..109e39a9a5 100644
--- 
a/engine/src/test/java/org/apache/hop/core/gui/markdown/NoteImageSupportTest.java
+++ 
b/engine/src/test/java/org/apache/hop/core/gui/markdown/NoteImageSupportTest.java
@@ -91,6 +91,26 @@ class NoteImageSupportTest {
     assertEquals(50, shrink.y);
   }
 
+  @Test
+  void fitBoundsExtremeDimensions() {
+    Point wide = NoteImageSupport.fit(2000, 100, 20, 200);
+    assertTrue(wide.x <= 20 && wide.y <= 200);
+
+    Point banner = NoteImageSupport.fit(2000, 40, 100, 200);
+    assertTrue(banner.x <= 100 && banner.y <= 200);
+
+    Point sliver = NoteImageSupport.fit(100000, 1, 500, 200);
+    assertTrue(sliver.x <= 500 && sliver.y <= 200);
+
+    Point max = NoteImageSupport.fit(100000, 100000, 100000, 100000);
+    assertTrue(max.x <= NoteImageSupport.MAX_RENDERED_SIZE);
+    assertTrue(max.y <= NoteImageSupport.MAX_RENDERED_SIZE);
+
+    Point tall = NoteImageSupport.fit(3, 10, 20, 200);
+    assertTrue(tall.x <= 20 && tall.y <= 200);
+    assertEquals(0.3, (double) tall.x / tall.y, 0.05);
+  }
+
   private static void writePng(Path path, int w, int h) throws Exception {
     BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
     Graphics2D g = image.createGraphics();
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/shared/SwtGc.java 
b/ui/src/main/java/org/apache/hop/ui/hopgui/shared/SwtGc.java
index 59aeb296e3..a4a6822ad9 100644
--- a/ui/src/main/java/org/apache/hop/ui/hopgui/shared/SwtGc.java
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/shared/SwtGc.java
@@ -617,19 +617,25 @@ public class SwtGc implements IGc {
       }
       try (java.io.InputStream in = 
org.apache.hop.core.vfs.HopVfs.getInputStream(path)) {
         org.eclipse.swt.graphics.ImageData data = new 
org.eclipse.swt.graphics.ImageData(in);
+        // Scale the decoded raster to the logical size; the DPI provider only 
applies monitor zoom.
+        int w = Math.max(1, width);
+        int h = Math.max(1, height);
+        org.eclipse.swt.graphics.ImageData scaled =
+            (data.width == w && data.height == h) ? data : data.scaledTo(w, h);
         Image img =
             SwtUniversalImage.createDpiAwareImage(
                 gc.getDevice(),
                 zoom -> {
                   if (zoom == 100) {
-                    return data;
+                    return scaled;
                   }
-                  int w = Math.max(1, data.width * zoom / 100);
-                  int h = Math.max(1, data.height * zoom / 100);
-                  return data.scaledTo(w, h);
+                  int zw = Math.max(1, Math.round(scaled.width * (zoom / 
100f)));
+                  int zh = Math.max(1, Math.round(scaled.height * (zoom / 
100f)));
+
+                  return scaled.scaledTo(zw, zh);
                 });
         try {
-          gc.drawImage(img, 0, 0, data.width, data.height, x, y, width, 
height);
+          gc.drawImage(img, 0, 0, scaled.width, scaled.height, x, y, w, h);
         } finally {
           img.dispose();
         }

Reply via email to