fix handling of hsl and linear rgb (%-values)

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1745412 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2016-05-24 23:39:23 +00:00
parent 1afe952ca9
commit 334ec509fa
4 changed files with 99 additions and 40 deletions

View File

@ -384,7 +384,7 @@ public class DrawPaint {
*
* @returns the RGB Color object
*/
private static Color HSL2RGB(double h, double s, double l, double alpha) {
public static Color HSL2RGB(double h, double s, double l, double alpha) {
// we clamp the values, as it possible to come up with more than 100% sat/lum
// (see links in applyColorTransform() for more info)
s = Math.max(0, Math.min(100, s));
@ -491,5 +491,34 @@ public class DrawPaint {
return new double[] {h, s * 100, l * 100};
}
/**
* Convert sRGB float component [0..1] from sRGB to linear RGB [0..100000]
*
* @see Color#getRGBColorComponents(float[])
*/
public static int srgb2lin(float sRGB) {
// scRGB has a linear gamma of 1.0, scale the AWT-Color which is in sRGB to linear RGB
// see https://en.wikipedia.org/wiki/SRGB (the reverse transformation)
if (sRGB <= 0.04045d) {
return (int)Math.rint(100000d * sRGB / 12.92d);
} else {
return (int)Math.rint(100000d * Math.pow((sRGB + 0.055d) / 1.055d, 2.4d));
}
}
/**
* Convert linear RGB [0..100000] to sRGB float component [0..1]
*
* @see Color#getRGBColorComponents(float[])
*/
public static float lin2srgb(int linRGB) {
// color in percentage is in linear RGB color space, i.e. needs to be gamma corrected for AWT color
// see https://en.wikipedia.org/wiki/SRGB (The forward transformation)
if (linRGB <= 0.0031308d) {
return (float)(linRGB / 100000d * 12.92d);
} else {
return (float)(1.055d * Math.pow(linRGB / 100000d, 1.0d/2.4d) - 0.055d);
}
}
}

View File

@ -30,6 +30,7 @@ import org.apache.poi.util.POILogger;
import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.drawingml.x2006.main.CTColor;
import org.openxmlformats.schemas.drawingml.x2006.main.CTHslColor;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveFixedPercentage;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetColor;
import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;
import org.openxmlformats.schemas.drawingml.x2006.main.CTScRgbColor;
@ -122,9 +123,7 @@ public class XSLFColor {
int h = hsl.getHue2();
int s = hsl.getSat2();
int l = hsl.getLum2();
// This conversion is not correct and differs from PowerPoint.
// TODO: Revisit and improve.
color = Color.getHSBColor(h / 60000f, s / 100000f, l / 100000f);
color = DrawPaint.HSL2RGB(h / 60000d, s / 1000d, l / 1000d, 1d);
} else if (ch instanceof CTPresetColor) {
CTPresetColor prst = (CTPresetColor)ch;
String colorName = prst.getVal().toString();
@ -143,13 +142,11 @@ public class XSLFColor {
CTColor ctColor = theme.getCTColor(colorRef);
if(ctColor != null) color = toColor(ctColor, null);
} else if (ch instanceof CTScRgbColor) {
// same as CTSRgbColor but with values expressed in percents
// color in percentage is in linear RGB color space, i.e. needs to be gamma corrected for AWT color
CTScRgbColor scrgb = (CTScRgbColor)ch;
int r = scrgb.getR();
int g = scrgb.getG();
int b = scrgb.getB();
color = new Color(255 * r / 100000, 255 * g / 100000, 255 * b / 100000);
color = new Color(DrawPaint.lin2srgb(scrgb.getR()), DrawPaint.lin2srgb(scrgb.getG()), DrawPaint.lin2srgb(scrgb.getB()));
} else if (ch instanceof CTSRgbColor) {
// color in sRGB color space, i.e. same as AWT Color
CTSRgbColor srgb = (CTSRgbColor)ch;
byte[] val = srgb.getVal();
color = new Color(0xFF & val[0], 0xFF & val[1], 0xFF & val[2]);
@ -190,24 +187,11 @@ public class XSLFColor {
if (fill.isSetSrgbClr()) {
fill.unsetSrgbClr();
}
CTSRgbColor rgb = fill.addNewSrgbClr();
float[] rgbaf = color.getRGBComponents(null);
int r = color.getRed(), g = color.getGreen(), b = color.getBlue();
if (rgbaf[0]*255f == r && rgbaf[1]*255f == g && rgbaf[2]*255f == b) {
rgb.setVal(new byte[]{(byte)r, (byte)g, (byte)b });
} else {
rgb.addNewRed().setVal((int)(100000 * rgbaf[0]));
rgb.addNewGreen().setVal((int)(100000 * rgbaf[1]));
rgb.addNewBlue().setVal((int)(100000 * rgbaf[2]));
}
// alpha (%)
if (rgbaf.length == 4 && rgbaf[3] < 1f) {
rgb.addNewAlpha().setVal((int)(100000 * rgbaf[3]));
if (fill.isSetScrgbClr()) {
fill.unsetScrgbClr();
}
if (fill.isSetHslClr()) {
fill.unsetHslClr();
}
@ -220,13 +204,41 @@ public class XSLFColor {
fill.unsetSchemeClr();
}
if (fill.isSetScrgbClr()) {
fill.unsetScrgbClr();
}
if (fill.isSetSysClr()) {
fill.unsetSysClr();
}
float[] rgbaf = color.getRGBComponents(null);
boolean addAlpha = (rgbaf.length == 4 && rgbaf[3] < 1f);
CTPositiveFixedPercentage alphaPct;
// see office open xml part 4 - 5.1.2.2.30 and 5.1.2.2.32
if (isInt(rgbaf[0]) && isInt(rgbaf[1]) && isInt(rgbaf[2])) {
// sRGB has a gamma of 2.2
CTSRgbColor rgb = fill.addNewSrgbClr();
byte rgbBytes[] = { (byte)color.getRed(), (byte)color.getGreen(), (byte)color.getBlue() };
rgb.setVal(rgbBytes);
alphaPct = (addAlpha) ? rgb.addNewAlpha() : null;
} else {
CTScRgbColor rgb = fill.addNewScrgbClr();
rgb.setR(DrawPaint.srgb2lin(rgbaf[0]));
rgb.setG(DrawPaint.srgb2lin(rgbaf[1]));
rgb.setB(DrawPaint.srgb2lin(rgbaf[2]));
alphaPct = (addAlpha) ? rgb.addNewAlpha() : null;
}
// alpha (%)
if (alphaPct != null) {
alphaPct.setVal((int)(100000 * rgbaf[3]));
}
}
/**
* @return true, if this is an integer color value
*/
private static boolean isInt(float f) {
return Math.abs((f*255f) - Math.rint(f*255f)) < 0.00001f;
}
private int getRawValue(String elem) {

View 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);
}
}

View File

@ -104,7 +104,7 @@ public class TestXSLFColor {
c.setLum2(50000);
XSLFColor color = new XSLFColor(xml, null, null);
assertEquals(new Color(128, 00, 00), color.getColor());
assertEquals(Color.BLUE, color.getColor());
}
@Test