changeset 1590:bd71cb53e1a3

fix rounding bug with mo=crop and mo=fill. added tests for crop and fill.
author robcast
date Wed, 08 Feb 2017 17:28:02 +0100
parents 6892f39c1fdb
children 8dff61ffdbc3
files common/src/main/java/digilib/image/ImageJobDescription.java webapp/src/test/java/digilib/servlet/ScalerTest.java
diffstat 2 files changed, 61 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/common/src/main/java/digilib/image/ImageJobDescription.java	Wed Feb 08 14:52:46 2017 +0100
+++ b/common/src/main/java/digilib/image/ImageJobDescription.java	Wed Feb 08 17:28:02 2017 +0100
@@ -262,7 +262,7 @@
             /*
              * crop to fit -- don't scale
              */
-            imgArea = prepareCropToFit();
+            imgArea = prepareClipToFit();
 
         } else if (isAbsoluteScale()) {
             /*
@@ -280,6 +280,7 @@
      * Scale to fit: scale factor based on destination size dw/dh and user area.
      * 
      * Uses a uniform scale factor for x and y.
+     * 
      * Sets ScaleX and ScaleY.
      */
     protected Rectangle2D prepareScaleToFit() throws IOException {
@@ -327,21 +328,25 @@
             if (scaleX > scaleY) {
                 scaleY = scaleX;
                 // crop mode uses whole destination rect
-                long croppedAreaHeight = (long) (getDh() / scaleY);
+                long croppedAreaHeight = Math.round(getDh() / scaleY);
                 if (areaHeight > croppedAreaHeight) {
                 	// center cropped area
                 	areaY += (areaHeight - croppedAreaHeight) / 2;
                 }
                 areaHeight = croppedAreaHeight;
+                // re-compute scaleY
+                scaleY = getDh() / (double) areaHeight;
             } else {
                 scaleX = scaleY;
                 // crop mode uses whole destination rect
-                long croppedAreaWidth = (long) (getDw() / scaleX);
+                long croppedAreaWidth = Math.round(getDw() / scaleX);
                 if (areaWidth > croppedAreaWidth) {
                 	// center cropped area
                 	areaX += (areaWidth - croppedAreaWidth) / 2;
                 }
                 areaWidth = croppedAreaWidth;
+                // re-compute scaleX
+                scaleX = getDw() / (double) areaWidth;
             }
         } else {
             // use the smaller factor to get fit-in-box
@@ -349,23 +354,27 @@
                 scaleX = scaleY;
                 if (hasOption("fill")) {
                     // fill mode uses whole destination rect
-                    long filledAreaWidth = (long) (getDw() / scaleX);
+                    long filledAreaWidth = Math.round(getDw() / scaleX);
                     if (filledAreaWidth > areaWidth) {
                     	// center filled area
                     	areaX -= (filledAreaWidth - areaWidth) / 2;
                     }
                     areaWidth = filledAreaWidth;
+                    // re-compute scaleX
+                    scaleX = getDw() / (double) areaWidth;
                 }
             } else {
                 scaleY = scaleX;
                 if (hasOption("fill")) {
                     // fill mode uses whole destination rect
-                    long filledAreaHeight = (long) (getDh() / scaleY);
+                    long filledAreaHeight = Math.round(getDh() / scaleY);
                     if (filledAreaHeight > areaHeight) {
                     	// center filled area
                     	areaY -= (filledAreaHeight - areaHeight) / 2;
                     }
                     areaHeight = filledAreaHeight;
+                    // re-compute scaleY
+                    scaleY = getDh() / (double) areaHeight;
                 }
             }
         }
@@ -376,7 +385,8 @@
     /**
      * Squeeze to fit: scale factor based on destination size and user area.
      * 
-     * Uses separate scale factors for x and y
+     * Uses separate scale factors for x and y to fill destination size changing aspect ratio.
+     * 
      * Sets ScaleX and ScaleY.
      */
     protected Rectangle2D prepareSqueezeToFit() throws IOException {
@@ -419,7 +429,9 @@
      * Absolute scale factor: either original size, based on dpi, or absolute. 
      * 
      * Uses a uniform scale factor for x and y.
+     * 
      * Sets ScaleX and ScaleY.
+     * 
      * @throws ImageOpException 
      */
     protected Rectangle2D prepareAbsoluteScale() throws IOException, ImageOpException {
@@ -502,11 +514,11 @@
 
 
     /**
-     * Crop to fit: don't scale.
+     * Clip to fit: don't scale.
      * 
-     * Sets ScaleX and ScaleY.
+     * Sets ScaleX and ScaleY to 1.0.
      */
-    protected Rectangle2D prepareCropToFit() throws IOException {
+    protected Rectangle2D prepareClipToFit() throws IOException {
         /*
          * minimum source size = hires size
          */
@@ -789,6 +801,8 @@
     /**
      * Return the size of the selected input image.
      * 
+     * Note: may use getMinSourceSize().
+     * 
      * @return
      * @throws IOException
      */
--- a/webapp/src/test/java/digilib/servlet/ScalerTest.java	Wed Feb 08 14:52:46 2017 +0100
+++ b/webapp/src/test/java/digilib/servlet/ScalerTest.java	Wed Feb 08 17:28:02 2017 +0100
@@ -108,18 +108,38 @@
     }
 
     /**
-     * Test scaling with mo=fit
+     * Test scaling with mo=fit.
+     * 
+     * Fit selected area to destination image width, staying below destination image height.
+     * 
      * @throws Exception
      */
     @Test
-    public void testScaleFit() throws Exception {
+    public void testScaleFitWidth() throws Exception {
         BufferedImage img = loadImage("ww=0.0836&wh=0.0378&wx=0&wy=0.961&dw=173&dh=235&mo=fit,errcode", null);
         assertEquals("height", 125, img.getHeight());
         assertEquals("width", 173, img.getWidth());
     }
 
     /**
-     * Test scaling with mo=squeeze
+     * Test scaling with mo=fill.
+     * 
+     * Fit selected area to destination image width, expanding area to destination image height.
+     *  
+     * @throws Exception
+     */
+    @Test
+    public void testScaleFillHeight() throws Exception {
+        BufferedImage img = loadImage("ww=0.0836&wh=0.0378&wx=0.0833&wy=0.9224&dw=173&dh=235&mo=fill,errcode", null);
+        assertEquals("height", 235, img.getHeight());
+        assertEquals("width", 173, img.getWidth());
+    }
+
+    /**
+     * Test scaling with mo=squeeze.
+     * 
+     * Fit selected area to destination image width and height by changing aspect ratio.
+     * 
      * @throws Exception
      */
     @Test
@@ -130,6 +150,19 @@
     }
 
     /**
+     * Test scaling with mo=crop.
+     * 
+     * 
+     * @throws Exception
+     */
+    @Test
+    public void testScaleCrop() throws Exception {
+        BufferedImage img = loadImage("ww=0.0836&wh=0.0378&wx=0&wy=0.961&dw=173&dh=235&mo=fit,errcode", null);
+        assertEquals("height", 125, img.getHeight());
+        assertEquals("width", 173, img.getWidth());
+    }
+
+    /**
      * Test scaling with mo=clip
      * @throws Exception
      */
@@ -152,7 +185,7 @@
     }
 
     /**
-     * Test forced image type with mo=jpg
+     * Test content-type and pixel color of forced image type with mo=jpg
      * @throws Exception
      */
     @Test
@@ -163,7 +196,7 @@
     }
 
     /**
-     * Test forced image type with mo=png
+     * Test content-type and pixel color of forced image type with mo=png
      * @throws Exception
      */
     @Test