EMF+ tdf#31814 Add support of reading EmfPlusBoundaryPointData

The EmfPlusBoundaryPointData object specifies a closed cardinal spline boundary for a gradient brush.
This data is starting point for displaying correctly gradients.

Change-Id: I91b01417c6dc00a04dabfc5a035afe9085999240
Reviewed-on: https://gerrit.libreoffice.org/37519
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Bartosz Kosiorek <gang65@poczta.onet.pl>
This commit is contained in:
Bartosz Kosiorek 2017-05-11 22:58:06 +02:00
parent 016e4d0e26
commit 43f5268c6f
3 changed files with 89 additions and 70 deletions

View file

@ -43,16 +43,6 @@ namespace cppcanvas
{
namespace internal
{
enum EmfPlusBrushType
{
BrushTypeSolidColor = 0x00000000,
BrushTypeHatchFill = 0x00000001,
BrushTypeTextureFill = 0x00000002,
BrushTypePathGradient = 0x00000003,
BrushTypeLinearGradient = 0x00000004
};
EMFPBrush::EMFPBrush()
: type(0)
, additionalFlags(0)
@ -154,7 +144,7 @@ namespace cppcanvas
SAL_INFO("cppcanvas.emf", "EMF+\tcenter point: " << areaX << "," << areaY);
s.ReadInt32(surroundColorsNumber);
SAL_INFO("cppcanvas.emf", "EMF+\tsurround colors: " << surroundColorsNumber);
SAL_INFO("cppcanvas.emf", "EMF+\t number of surround colors: " << surroundColorsNumber);
if (surroundColorsNumber<0 || sal_uInt32(surroundColorsNumber)>SAL_MAX_INT32 / sizeof(::Color))
surroundColorsNumber = SAL_MAX_INT32 / sizeof(::Color);
@ -191,57 +181,73 @@ namespace cppcanvas
const ::basegfx::B2DRectangle aBounds(::basegfx::tools::getRange(path->GetPolygon(rR, false)));
areaWidth = aBounds.getWidth();
areaHeight = aBounds.getHeight();
SAL_INFO("cppcanvas.emf", "EMF+\t polygon bounding box: " << aBounds.getMinX() << "," << aBounds.getMinY() << " " << aBounds.getWidth() << "x" << aBounds.getHeight());
}
else
{
sal_Int32 boundaryPointCount;
s.ReadInt32(boundaryPointCount);
SAL_INFO("cppcanvas.emf", "EMF+\tpolygon bounding box: " << aBounds.getMinX() << "," << aBounds.getMinY() << " " << aBounds.getWidth() << "x" << aBounds.getHeight());
sal_uInt64 const pos = s.Tell();
SAL_INFO("cppcanvas.emf", "EMF+\t use boundary, points: " << boundaryPointCount);
path = new EMFPPath(boundaryPointCount);
path->Read(s, 0x0, rR);
s.Seek(pos + 8 * boundaryPointCount);
if (additionalFlags & 0x02) {
SAL_INFO("cppcanvas.emf", "EMF+\tuse transformation");
ReadXForm(s, brush_transformation);
hasTransformation = true;
SAL_INFO("cppcanvas.emf",
"EMF+\tm11: " << brush_transformation.eM11 << " m12: " << brush_transformation.eM12 <<
"\nEMF+\tm21: " << brush_transformation.eM21 << " m22: " << brush_transformation.eM22 <<
"\nEMF+\tdx: " << brush_transformation.eDx << " dy: " << brush_transformation.eDy);
const ::basegfx::B2DRectangle aBounds(::basegfx::tools::getRange(path->GetPolygon(rR, false)));
areaWidth = aBounds.getWidth();
areaHeight = aBounds.getHeight();
SAL_INFO("cppcanvas.emf", "EMF+\t polygon bounding box: " << aBounds.getMinX() << "," << aBounds.getMinY() << " " << aBounds.getWidth() << "x" << aBounds.getHeight());
}
if (additionalFlags & 0x02) {
SAL_INFO("cppcanvas.emf", "EMF+\tuse transformation");
ReadXForm(s, brush_transformation);
hasTransformation = true;
SAL_INFO("cppcanvas.emf",
"EMF+\tm11: " << brush_transformation.eM11 << " m12: " << brush_transformation.eM12 <<
"\nEMF+\tm21: " << brush_transformation.eM21 << " m22: " << brush_transformation.eM22 <<
"\nEMF+\tdx: " << brush_transformation.eDx << " dy: " << brush_transformation.eDy);
}
if (additionalFlags & 0x08) {
s.ReadInt32(blendPoints);
SAL_INFO("cppcanvas.emf", "EMF+\tuse blend, points: " << blendPoints);
if (blendPoints<0 || sal_uInt32(blendPoints)>SAL_MAX_INT32 / (2 * sizeof(float)))
blendPoints = SAL_MAX_INT32 / (2 * sizeof(float));
blendPositions = new float[2 * blendPoints];
blendFactors = blendPositions + blendPoints;
for (int i = 0; i < blendPoints; i++) {
s.ReadFloat(blendPositions[i]);
SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i << "]: " << blendPositions[i]);
}
if (additionalFlags & 0x08) {
s.ReadInt32(blendPoints);
SAL_INFO("cppcanvas.emf", "EMF+\tuse blend, points: " << blendPoints);
if (blendPoints<0 || sal_uInt32(blendPoints)>SAL_MAX_INT32 / (2 * sizeof(float)))
blendPoints = SAL_MAX_INT32 / (2 * sizeof(float));
blendPositions = new float[2 * blendPoints];
blendFactors = blendPositions + blendPoints;
for (int i = 0; i < blendPoints; i++) {
s.ReadFloat(blendPositions[i]);
SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i << "]: " << blendPositions[i]);
}
for (int i = 0; i < blendPoints; i++) {
s.ReadFloat(blendFactors[i]);
SAL_INFO("cppcanvas.emf", "EMF+\tfactor[" << i << "]: " << blendFactors[i]);
}
}
if (additionalFlags & 0x04) {
s.ReadInt32(colorblendPoints);
SAL_INFO("cppcanvas.emf", "EMF+\tuse color blend, points: " << colorblendPoints);
if (colorblendPoints<0 || sal_uInt32(colorblendPoints)>SAL_MAX_INT32 / sizeof(float))
colorblendPoints = SAL_MAX_INT32 / sizeof(float);
if (sal_uInt32(colorblendPoints)>SAL_MAX_INT32 / sizeof(::Color))
colorblendPoints = SAL_MAX_INT32 / sizeof(::Color);
colorblendPositions = new float[colorblendPoints];
colorblendColors = new ::Color[colorblendPoints];
for (int i = 0; i < colorblendPoints; i++) {
s.ReadFloat(colorblendPositions[i]);
SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i << "]: " << colorblendPositions[i]);
}
for (int i = 0; i < colorblendPoints; i++) {
s.ReadUInt32(color);
colorblendColors[i] = ::Color(0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
SAL_INFO("cppcanvas.emf", "EMF+\tcolor[" << i << "]: 0x" << std::hex << color << std::dec);
}
for (int i = 0; i < blendPoints; i++) {
s.ReadFloat(blendFactors[i]);
SAL_INFO("cppcanvas.emf", "EMF+\tfactor[" << i << "]: " << blendFactors[i]);
}
}
if (additionalFlags & 0x04) {
s.ReadInt32(colorblendPoints);
SAL_INFO("cppcanvas.emf", "EMF+\tuse color blend, points: " << colorblendPoints);
if (colorblendPoints<0 || sal_uInt32(colorblendPoints)>SAL_MAX_INT32 / sizeof(float))
colorblendPoints = SAL_MAX_INT32 / sizeof(float);
if (sal_uInt32(colorblendPoints)>SAL_MAX_INT32 / sizeof(::Color))
colorblendPoints = SAL_MAX_INT32 / sizeof(::Color);
colorblendPositions = new float[colorblendPoints];
colorblendColors = new ::Color[colorblendPoints];
for (int i = 0; i < colorblendPoints; i++) {
s.ReadFloat(colorblendPositions[i]);
SAL_INFO("cppcanvas.emf", "EMF+\tposition[" << i << "]: " << colorblendPositions[i]);
}
for (int i = 0; i < colorblendPoints; i++) {
s.ReadUInt32(color);
colorblendColors[i] = ::Color(0xff - (color >> 24), (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
SAL_INFO("cppcanvas.emf", "EMF+\tcolor[" << i << "]: 0x" << std::hex << color << std::dec);
}
}
break;
}
case BrushTypeLinearGradient:

View file

@ -81,6 +81,15 @@ namespace cppcanvas
HatchStyleSolidDiamond = 0x00000034
};
enum EmfPlusBrushType
{
BrushTypeSolidColor = 0x00000000,
BrushTypeHatchFill = 0x00000001,
BrushTypeTextureFill = 0x00000002,
BrushTypePathGradient = 0x00000003,
BrushTypeLinearGradient = 0x00000004
};
struct EMFPPath;
struct EMFPBrush : public EMFPObject

View file

@ -330,7 +330,7 @@ namespace cppcanvas
rState.isFillColorSet = false;
rState.isLineColorSet = false;
if (brush->type == 1)
if (brush->type == BrushTypeHatchFill)
{
// EMF+ like hatching is currently not supported. These are just color blends which serve as an approximation for some of them
// for the others the hatch "background" color (secondColor in brush) is used.
@ -371,11 +371,16 @@ namespace cppcanvas
rState.fillColor = vcl::unotools::colorToDoubleSequence(fillColor, rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace());
pPolyAction = ActionSharedPtr ( internal::PolyPolyActionFactory::createPolyPolyAction( localPolygon, rParms.mrCanvas, rState ) );
}
else if (brush->type == 3 || brush->type == 4)
else if (brush->type == BrushTypeTextureFill)
{
if (brush->type == 3 && !(brush->additionalFlags & 0x1))
return; // we are unable to parse these brushes yet
SAL_WARN("cppcanvas.emf", "EMF+\tTODO: implement BrushTypeTextureFill brush");
}
else if (brush->type == BrushTypePathGradient || brush->type == BrushTypeLinearGradient)
{
if (brush->type == BrushTypePathGradient && !(brush->additionalFlags & 0x1))
{
SAL_WARN("cppcanvas.emf", "EMF+\t TODO Verify proper displaying of BrushTypePathGradient with flags: " << std::hex << brush->additionalFlags << std::dec);
}
::basegfx::B2DHomMatrix aTextureTransformation;
::basegfx::B2DHomMatrix aWorldTransformation;
::basegfx::B2DHomMatrix aBaseTransformation;
@ -395,14 +400,13 @@ namespace cppcanvas
aBaseTransformation.set (1, 1, aBaseTransform.eM22);
aBaseTransformation.set (1, 2, aBaseTransform.eDy);
if (brush->type == 4) {
aTextureTransformation.scale (brush->areaWidth, brush->areaHeight);
aTextureTransformation.translate (brush->areaX, brush->areaY);
} else {
// TODO Verify on example image, why there is shift (-0.5, -0.5)
if (brush->type == BrushTypePathGradient && (brush->additionalFlags & 0x1))
{
aTextureTransformation.translate (-0.5, -0.5);
aTextureTransformation.scale (brush->areaWidth, brush->areaHeight);
aTextureTransformation.translate (brush->areaX,brush->areaY);
}
aTextureTransformation.scale (brush->areaWidth, brush->areaHeight);
aTextureTransformation.translate (brush->areaX, brush->areaY);
if (brush->hasTransformation) {
::basegfx::B2DHomMatrix aTransformation;
@ -452,7 +456,7 @@ namespace cppcanvas
aStops[i] = brush->blendPositions [i];
for (int j = 0; j < length; j++) {
if (brush->type == 4) {
if (brush->type == BrushTypeLinearGradient) {
aColor [j] = aStartColor [j]*(1 - brush->blendFactors[i]) + aEndColor [j]*brush->blendFactors[i];
} else
aColor [j] = aStartColor [j]*brush->blendFactors[i] + aEndColor [j]*(1 - brush->blendFactors[i]);
@ -467,14 +471,14 @@ namespace cppcanvas
for (int i = 0; i < brush->colorblendPoints; i++) {
aStops[i] = brush->colorblendPositions [i];
aColors[(brush->type == 4) ? i : brush->colorblendPoints - 1 - i] = vcl::unotools::colorToDoubleSequence( brush->colorblendColors [i],
aColors[(brush->type == BrushTypeLinearGradient) ? i : brush->colorblendPoints - 1 - i] = vcl::unotools::colorToDoubleSequence( brush->colorblendColors [i],
rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() );
}
} else {
aStops[0] = 0.0;
aStops[1] = 1.0;
if (brush->type == 4) {
if (brush->type == BrushTypeLinearGradient) {
aColors[0] = aStartColor;
aColors[1] = aEndColor;
} else {
@ -485,7 +489,7 @@ namespace cppcanvas
SAL_INFO("cppcanvas.emf", "EMF+\t\tset gradient");
basegfx::B2DRange aBoundsRectangle (0, 0, 1, 1);
if (brush->type == 4) {
if (brush->type == BrushTypeLinearGradient) {
aGradientService = "LinearGradient";
aGradInfo = basegfx::tools::createLinearODFGradientInfo(
aBoundsRectangle,