]> source.dussan.org Git - poi.git/commitdiff
fix handling of hsl and linear rgb (%-values)
authorAndreas Beeker <kiwiwings@apache.org>
Tue, 24 May 2016 23:39:23 +0000 (23:39 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Tue, 24 May 2016 23:39:23 +0000 (23:39 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1745412 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/sl/draw/DrawPaint.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFColor.java
src/ooxml/testcases/org/apache/poi/xslf/TestXSLFBugs.java
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFColor.java

index 2bebffc2036a1110b82f2f45b70b8b001342a21d..25dbe68d746f78abaacd8ccb7b9cda2a12020b2c 100644 (file)
@@ -384,7 +384,7 @@ public class DrawPaint {
      *\r
      *  @returns the RGB Color object\r
      */\r
-    private static Color HSL2RGB(double h, double s, double l, double alpha) {\r
+    public static Color HSL2RGB(double h, double s, double l, double alpha) {\r
         // we clamp the values, as it possible to come up with more than 100% sat/lum\r
         // (see links in applyColorTransform() for more info)\r
         s = Math.max(0, Math.min(100, s));\r
@@ -491,5 +491,34 @@ public class DrawPaint {
 \r
         return new double[] {h, s * 100, l * 100};\r
     }\r
-\r
+    \r
+    /**\r
+     * Convert sRGB float component [0..1] from sRGB to linear RGB [0..100000]\r
+     * \r
+     * @see Color#getRGBColorComponents(float[])\r
+     */\r
+    public static int srgb2lin(float sRGB) {\r
+        // scRGB has a linear gamma of 1.0, scale the AWT-Color which is in sRGB to linear RGB\r
+        // see https://en.wikipedia.org/wiki/SRGB (the reverse transformation)\r
+        if (sRGB <= 0.04045d) {\r
+            return (int)Math.rint(100000d * sRGB / 12.92d);\r
+        } else {\r
+            return (int)Math.rint(100000d * Math.pow((sRGB + 0.055d) / 1.055d, 2.4d));\r
+        }\r
+    }\r
+    \r
+    /**\r
+     * Convert linear RGB [0..100000] to sRGB float component [0..1]\r
+     * \r
+     * @see Color#getRGBColorComponents(float[])\r
+     */\r
+    public static float lin2srgb(int linRGB) {\r
+        // color in percentage is in linear RGB color space, i.e. needs to be gamma corrected for AWT color\r
+        // see https://en.wikipedia.org/wiki/SRGB (The forward transformation)\r
+        if (linRGB <= 0.0031308d) {\r
+            return (float)(linRGB / 100000d * 12.92d);\r
+        } else {\r
+            return (float)(1.055d * Math.pow(linRGB / 100000d, 1.0d/2.4d) - 0.055d);\r
+        }\r
+    }\r
 }
\ No newline at end of file
index f2e94faeaf41506bf028bb078741a08344689932..e9a889d766032bcc7877612b391032528c8d89cb 100644 (file)
@@ -30,6 +30,7 @@ import org.apache.poi.util.POILogger;
 import org.apache.xmlbeans.XmlObject;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTColor;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTHslColor;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveFixedPercentage;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetColor;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTScRgbColor;\r
@@ -122,9 +123,7 @@ public class XSLFColor {
                 int h = hsl.getHue2();\r
                 int s = hsl.getSat2();\r
                 int l = hsl.getLum2();\r
-                // This conversion is not correct and differs from PowerPoint.\r
-                // TODO: Revisit and improve.\r
-                color = Color.getHSBColor(h / 60000f, s / 100000f, l / 100000f);\r
+                color = DrawPaint.HSL2RGB(h / 60000d, s / 1000d, l / 1000d, 1d);\r
             } else if (ch instanceof CTPresetColor) {\r
                 CTPresetColor prst = (CTPresetColor)ch;\r
                 String colorName = prst.getVal().toString();\r
@@ -143,13 +142,11 @@ public class XSLFColor {
                 CTColor ctColor = theme.getCTColor(colorRef);\r
                 if(ctColor != null) color = toColor(ctColor, null);\r
             } else if (ch instanceof CTScRgbColor) {\r
-                // same as CTSRgbColor but with values expressed in percents\r
+                // color in percentage is in linear RGB color space, i.e. needs to be gamma corrected for AWT color\r
                 CTScRgbColor scrgb = (CTScRgbColor)ch;\r
-                int r = scrgb.getR();\r
-                int g = scrgb.getG();\r
-                int b = scrgb.getB();\r
-                color = new Color(255 * r / 100000, 255 * g / 100000, 255 * b / 100000);\r
+                color = new Color(DrawPaint.lin2srgb(scrgb.getR()), DrawPaint.lin2srgb(scrgb.getG()), DrawPaint.lin2srgb(scrgb.getB()));\r
             } else if (ch instanceof CTSRgbColor) {\r
+                // color in sRGB color space, i.e. same as AWT Color\r
                 CTSRgbColor srgb = (CTSRgbColor)ch;\r
                 byte[] val = srgb.getVal();\r
                 color = new Color(0xFF & val[0], 0xFF & val[1], 0xFF & val[2]);\r
@@ -190,24 +187,11 @@ public class XSLFColor {
         if (fill.isSetSrgbClr()) {\r
             fill.unsetSrgbClr();\r
         }\r
-        \r
-        CTSRgbColor rgb = fill.addNewSrgbClr();\r
-        \r
-        float[] rgbaf = color.getRGBComponents(null);\r
-        int r = color.getRed(), g = color.getGreen(), b = color.getBlue();\r
-        if (rgbaf[0]*255f == r && rgbaf[1]*255f == g && rgbaf[2]*255f == b) {\r
-            rgb.setVal(new byte[]{(byte)r, (byte)g, (byte)b });\r
-        } else {\r
-            rgb.addNewRed().setVal((int)(100000 * rgbaf[0]));\r
-            rgb.addNewGreen().setVal((int)(100000 * rgbaf[1]));\r
-            rgb.addNewBlue().setVal((int)(100000 * rgbaf[2]));\r
-        }\r
 \r
-        // alpha (%)\r
-        if (rgbaf.length == 4 && rgbaf[3] < 1f) {\r
-            rgb.addNewAlpha().setVal((int)(100000 * rgbaf[3]));\r
+        if (fill.isSetScrgbClr()) {\r
+            fill.unsetScrgbClr();\r
         }\r
-\r
+        \r
         if (fill.isSetHslClr()) {\r
             fill.unsetHslClr();\r
         }\r
@@ -220,13 +204,41 @@ public class XSLFColor {
             fill.unsetSchemeClr();\r
         }\r
         \r
-        if (fill.isSetScrgbClr()) {\r
-            fill.unsetScrgbClr();\r
-        }\r
-        \r
         if (fill.isSetSysClr()) {\r
             fill.unsetSysClr();\r
         }\r
+\r
+        float[] rgbaf = color.getRGBComponents(null);\r
+        boolean addAlpha = (rgbaf.length == 4 && rgbaf[3] < 1f);\r
+        CTPositiveFixedPercentage alphaPct;\r
+        \r
+        // see office open xml part 4 - 5.1.2.2.30 and 5.1.2.2.32\r
+        if (isInt(rgbaf[0]) && isInt(rgbaf[1]) && isInt(rgbaf[2])) {\r
+            // sRGB has a gamma of 2.2\r
+            CTSRgbColor rgb = fill.addNewSrgbClr();\r
+            \r
+            byte rgbBytes[] = { (byte)color.getRed(), (byte)color.getGreen(), (byte)color.getBlue() };\r
+            rgb.setVal(rgbBytes);\r
+            alphaPct = (addAlpha) ? rgb.addNewAlpha() : null;\r
+        } else {\r
+            CTScRgbColor rgb = fill.addNewScrgbClr();\r
+            rgb.setR(DrawPaint.srgb2lin(rgbaf[0]));\r
+            rgb.setG(DrawPaint.srgb2lin(rgbaf[1]));\r
+            rgb.setB(DrawPaint.srgb2lin(rgbaf[2]));\r
+            alphaPct = (addAlpha) ? rgb.addNewAlpha() : null;\r
+        }\r
+\r
+        // alpha (%)\r
+        if (alphaPct != null) {\r
+            alphaPct.setVal((int)(100000 * rgbaf[3]));\r
+        }\r
+    }\r
+    \r
+    /**\r
+     * @return true, if this is an integer color value\r
+     */\r
+    private static boolean isInt(float f) {\r
+        return Math.abs((f*255f) - Math.rint(f*255f)) < 0.00001f;\r
     }\r
     \r
     private int getRawValue(String elem) {\r
index 7c55ce7fb7198b7a1181e2109f031c3d17803642..b0c0e52431405a5738dfe3a71531d3be90282fd2 100644 (file)
@@ -40,10 +40,13 @@ import javax.imageio.ImageIO;
 import org.apache.poi.POIDataSamples;
 import org.apache.poi.POIXMLDocumentPart;
 import org.apache.poi.POIXMLDocumentPart.RelationPart;
+import org.apache.poi.sl.draw.DrawPaint;
+import org.apache.poi.sl.usermodel.PaintStyle;
 import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
 import org.apache.poi.sl.usermodel.PictureData;
 import org.apache.poi.sl.usermodel.PictureData.PictureType;
 import org.apache.poi.sl.usermodel.ShapeType;
+import org.apache.poi.sl.usermodel.VerticalAlignment;
 import org.apache.poi.xslf.usermodel.DrawingParagraph;
 import org.apache.poi.xslf.usermodel.DrawingTextBody;
 import org.apache.poi.xslf.usermodel.XMLSlideShow;
@@ -56,6 +59,7 @@ import org.apache.poi.xslf.usermodel.XSLFShape;
 import org.apache.poi.xslf.usermodel.XSLFSlide;
 import org.apache.poi.xslf.usermodel.XSLFSlideLayout;
 import org.apache.poi.xslf.usermodel.XSLFSlideMaster;
+import org.apache.poi.xslf.usermodel.XSLFTextRun;
 import org.junit.Ignore;
 import org.junit.Test;
 
@@ -478,25 +482,39 @@ public class TestXSLFBugs {
 
     @Test
     public void bug58217() throws IOException {
+        Color fillColor = new Color(1f,1f,0f,0.1f);
+        Color lineColor = new Color(25.3f/255f,1f,0f,0.4f);
+        Color textColor = new Color(1f,1f,0f,0.6f);
+        
         XMLSlideShow ppt1 = new XMLSlideShow();
         XSLFSlide sl = ppt1.createSlide();
         XSLFAutoShape as = sl.createAutoShape();
         as.setShapeType(ShapeType.STAR_10);
         as.setAnchor(new Rectangle2D.Double(100,100,300,300));
-        as.setFillColor(new Color(1f,1f,0f,0.1f));
-        as.setLineColor(new Color(1f,1f,0f,0.4f));
+        as.setFillColor(fillColor);
+        as.setLineColor(lineColor);
         as.setText("Alpha");
-        as.getTextParagraphs().get(0).getTextRuns().get(0).setFontColor(new Color(1f,1f,0f,0.6f));
+        as.setVerticalAlignment(VerticalAlignment.MIDDLE);
+        as.setHorizontalCentered(true);
+        XSLFTextRun tr = as.getTextParagraphs().get(0).getTextRuns().get(0);
+        tr.setFontSize(32d);
+        tr.setFontColor(textColor);
         XMLSlideShow ppt2 = XSLFTestDataSamples.writeOutAndReadBack(ppt1);
         ppt1.close();
         sl = ppt2.getSlides().get(0);
         as = (XSLFAutoShape)sl.getShapes().get(0);
-        SolidPaint ps = (SolidPaint)as.getFillStyle().getPaint();
-        assertEquals(10000, ps.getSolidColor().getAlpha());
-        ps = (SolidPaint)as.getStrokeStyle().getPaint();
-        assertEquals(40000, ps.getSolidColor().getAlpha());
-        ps = (SolidPaint)as.getTextParagraphs().get(0).getTextRuns().get(0).getFontColor();
-        assertEquals(60000, ps.getSolidColor().getAlpha());
+        checkColor(fillColor, as.getFillStyle().getPaint());
+        checkColor(lineColor, as.getStrokeStyle().getPaint());
+        checkColor(textColor, as.getTextParagraphs().get(0).getTextRuns().get(0).getFontColor());
         ppt2.close();
     }
+    
+    private static void checkColor(Color expected, PaintStyle actualStyle) {
+        assertTrue(actualStyle instanceof SolidPaint);
+        SolidPaint ps = (SolidPaint)actualStyle;
+        Color actual = DrawPaint.applyColorTransform(ps.getSolidColor());
+        float expRGB[] = expected.getRGBComponents(null);
+        float actRGB[] = actual.getRGBComponents(null);
+        assertArrayEquals(expRGB, actRGB, 0.0001f);
+    }
 }
index 8a923c29d66fc2c3f192f51ba08482a9bf2d76c2..659f4beae7fa6989e9f98174dd0090a9b0c182c4 100644 (file)
@@ -104,7 +104,7 @@ public class TestXSLFColor {
         c.setLum2(50000);\r
 \r
         XSLFColor color = new XSLFColor(xml, null, null);\r
-        assertEquals(new Color(128, 00, 00), color.getColor());\r
+        assertEquals(Color.BLUE, color.getColor());\r
     }\r
 \r
     @Test\r