You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by fa...@apache.org on 2026/09/18 15:27:26 UTC

(poi) branch trunk updated: ImageUtils.getResolution: unusable pixel-size metadata falls back to 96 dpi instead of throwing (#1297)

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

pjfanning pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/poi.git


The following commit(s) were added to refs/heads/trunk by this push:
     new a6d6a99479 ImageUtils.getResolution: unusable pixel-size metadata falls back to 96 dpi instead of throwing (#1297)
a6d6a99479 is described below

commit a6d6a99479d38c186153ef006467e3775b594389
Author: PJ Fanning <pj...@users.noreply.github.com>
AuthorDate: Fri Sep 18 16:27:20 2026 +0100

    ImageUtils.getResolution: unusable pixel-size metadata falls back to 96 dpi instead of throwing (#1297)
    
    The HorizontalPixelSize/VerticalPixelSize an image's metadata reports is untrusted
    input. A value of 0 made 25.4/0 infinite and MathUtil.safeDoubleToInt threw
    IllegalArgumentException out of Picture.getImageDimension() and resize(); a
    non-numeric value threw NumberFormatException. Both now give the default 96 dpi,
    as a missing value already did.
    
    Co-authored-by: Claude Opus 5 (1M context) <no...@anthropic.com>
---
 .../java/org/apache/poi/ss/util/ImageUtils.java    | 30 +++++++++++++++++++---
 .../org/apache/poi/ss/util/TestImageUtils.java     | 20 +++++++++++++++
 2 files changed, 46 insertions(+), 4 deletions(-)

diff --git a/poi/src/main/java/org/apache/poi/ss/util/ImageUtils.java b/poi/src/main/java/org/apache/poi/ss/util/ImageUtils.java
index bd86cb49ca..0db836badc 100644
--- a/poi/src/main/java/org/apache/poi/ss/util/ImageUtils.java
+++ b/poi/src/main/java/org/apache/poi/ss/util/ImageUtils.java
@@ -46,6 +46,9 @@ import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
 
 public final class ImageUtils {
+
+    /** the dpi assumed when an image carries no usable resolution metadata */
+    private static final int DEFAULT_DPI = 96;
     private static final Logger LOG = PoiLogManager.getLogger(ImageUtils.class);
 
     private static final int WIDTH_UNITS = 1024;
@@ -119,24 +122,43 @@ public final class ImageUtils {
      * {96, 96} is the default.
      */
     public static int[] getResolution(ImageReader r) throws IOException {
-        int hdpi=96, vdpi=96;
-        double mm2inch = 25.4;
+        int hdpi=DEFAULT_DPI, vdpi=DEFAULT_DPI;
 
         NodeList lst;
         Element node = (Element)r.getImageMetadata(0).getAsTree("javax_imageio_1.0");
         lst = node.getElementsByTagName("HorizontalPixelSize");
         if(lst != null && lst.getLength() == 1) {
-            hdpi = MathUtil.safeDoubleToInt(mm2inch/Double.parseDouble(((Element)lst.item(0)).getAttribute("value")));
+            hdpi = dpiFromPixelSize(((Element)lst.item(0)).getAttribute("value"));
         }
 
         lst = node.getElementsByTagName("VerticalPixelSize");
         if(lst != null && lst.getLength() == 1) {
-            vdpi = MathUtil.safeDoubleToInt(mm2inch/Double.parseDouble(((Element)lst.item(0)).getAttribute("value")));
+            vdpi = dpiFromPixelSize(((Element)lst.item(0)).getAttribute("value"));
         }
 
         return new int[]{hdpi, vdpi};
     }
 
+    /**
+     * @param pixelSizeMm the size of a pixel in millimeters, as found in the image metadata
+     * @return the dpi that pixel size means, or {@link #DEFAULT_DPI} if the metadata is unusable
+     *  (not a number, zero, negative, or so small that the dpi does not fit an int)
+     */
+    static int dpiFromPixelSize(String pixelSizeMm) {
+        final double mm2inch = 25.4;
+        double pixelSize;
+        try {
+            pixelSize = Double.parseDouble(pixelSizeMm);
+        } catch (NumberFormatException | NullPointerException e) {
+            return DEFAULT_DPI;
+        }
+        double dpi = mm2inch / pixelSize;
+        if (!(dpi > 0 && dpi <= Integer.MAX_VALUE)) {
+            return DEFAULT_DPI;
+        }
+        return (int) dpi;
+    }
+
     /**
      * Calculate and set the preferred size (anchor) for this picture.
      *
diff --git a/poi/src/test/java/org/apache/poi/ss/util/TestImageUtils.java b/poi/src/test/java/org/apache/poi/ss/util/TestImageUtils.java
index 1487574a49..7a2f17591a 100644
--- a/poi/src/test/java/org/apache/poi/ss/util/TestImageUtils.java
+++ b/poi/src/test/java/org/apache/poi/ss/util/TestImageUtils.java
@@ -27,6 +27,7 @@ import org.junit.jupiter.api.Test;
 
 import java.io.IOException;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
 /**
@@ -87,4 +88,23 @@ final class TestImageUtils {
             );
         }
     }
+
+    /**
+     * The pixel size in an image's metadata is untrusted input: a zero, negative or garbage
+     * value must not throw (it used to give IllegalArgumentException from the int conversion)
+     */
+    @Test
+    void testDpiFromPixelSize() {
+        assertEquals(96, ImageUtils.dpiFromPixelSize("0.26458333"));
+        assertEquals(100, ImageUtils.dpiFromPixelSize("0.254"));
+        assertEquals(1, ImageUtils.dpiFromPixelSize("25.4"));
+        assertEquals(96, ImageUtils.dpiFromPixelSize("0"));
+        assertEquals(96, ImageUtils.dpiFromPixelSize("-0.1"));
+        assertEquals(96, ImageUtils.dpiFromPixelSize("1E-300"));
+        assertEquals(96, ImageUtils.dpiFromPixelSize("NaN"));
+        assertEquals(96, ImageUtils.dpiFromPixelSize("Infinity"));
+        assertEquals(96, ImageUtils.dpiFromPixelSize("abc"));
+        assertEquals(96, ImageUtils.dpiFromPixelSize(""));
+        assertEquals(96, ImageUtils.dpiFromPixelSize(null));
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org