tdf166084 tdf138087 tdf59814 EMF+ Fix scale and trans DrawImagePoints Metafile
This commit fixes the incorrect positioning and scaling of Metafiles
rendered via EMF+ DrawImagePoints.
Key changes:
- Implemented a normalization matrix for Metafiles to properly map
source coordinates (SrcRect) to the destination.
- Updated EMFPImage to parse and store bounds from nested EMF headers,
ensuring correct dimensions (x, y, width, height) are available.
Change-Id: I07b4d99c334611a10e7faff42b76699f04fa1520
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/201084
Tested-by: Jenkins
Reviewed-by: Bartosz Kosiorek <gang65@poczta.onet.pl>
(cherry picked from commit 4dccec254c)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/201163
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
This commit is contained in:
committed by
Tomaž Vajngerl
parent
292c654185
commit
0afed6774e
@@ -30,19 +30,20 @@
|
||||
#include <wmfemfhelper.hxx>
|
||||
#include <drawinglayer/attribute/fillgraphicattribute.hxx>
|
||||
#include <drawinglayer/attribute/fontattribute.hxx>
|
||||
#include <drawinglayer/primitive2d/PolygonStrokeArrowPrimitive2D.hxx>
|
||||
#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
|
||||
#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
|
||||
#include <drawinglayer/primitive2d/PolyPolygonGraphicPrimitive2D.hxx>
|
||||
#include <drawinglayer/primitive2d/PolyPolygonRGBAPrimitive2D.hxx>
|
||||
#include <drawinglayer/primitive2d/PolyPolygonStrokePrimitive2D.hxx>
|
||||
#include <drawinglayer/primitive2d/PolygonStrokeArrowPrimitive2D.hxx>
|
||||
#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
|
||||
#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
|
||||
#include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
|
||||
#include <drawinglayer/primitive2d/svggradientprimitive2d.hxx>
|
||||
#include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
|
||||
#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
|
||||
#include <drawinglayer/primitive2d/textprimitive2d.hxx>
|
||||
#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
|
||||
#include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
|
||||
#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
|
||||
#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
|
||||
#include <basegfx/color/bcolor.hxx>
|
||||
#include <basegfx/color/bcolormodifier.hxx>
|
||||
#include <basegfx/matrix/b2dhommatrixtools.hxx>
|
||||
@@ -1542,11 +1543,8 @@ namespace emfplushelper
|
||||
ReadPoint(rMS, x2, y2, flags); // upper-right
|
||||
ReadPoint(rMS, x3, y3, flags); // lower-left
|
||||
|
||||
SAL_INFO("drawinglayer.emf", "EMF+\t destination points: "
|
||||
<< x1 << "," << y1 << " " << x2 << ","
|
||||
<< y2 << " " << x3 << "," << y3);
|
||||
dx = x1;
|
||||
dy = y2;
|
||||
dy = y1;
|
||||
dw = x2 - x1;
|
||||
dh = y3 - y1;
|
||||
fShearX = x3 - x1;
|
||||
@@ -1556,7 +1554,7 @@ namespace emfplushelper
|
||||
ReadRectangle(rMS, dx, dy, dw, dh, bool(flags & 0x4000));
|
||||
|
||||
SAL_INFO("drawinglayer.emf",
|
||||
"EMF+\t Rectangle: " << dx << "," << dy << " " << dw << "x" << dh);
|
||||
"EMF+\t Destination rectangle: " << dx << "," << dy << " " << dw << "x" << dh);
|
||||
Size aSize;
|
||||
if (image->type == ImageDataTypeBitmap)
|
||||
{
|
||||
@@ -1588,22 +1586,15 @@ namespace emfplushelper
|
||||
else if (sy + sh > aSize.Height())
|
||||
dh = ((aSize.Height() - sy) / sh) * dh;
|
||||
}
|
||||
else
|
||||
SAL_INFO(
|
||||
"drawinglayer.emf",
|
||||
"EMF+\t TODO: Add support for SrcRect to ImageDataTypeMetafile");
|
||||
const ::basegfx::B2DPoint aDstPoint(dx, dy);
|
||||
const ::basegfx::B2DSize aDstSize(dw, dh);
|
||||
|
||||
const basegfx::B2DHomMatrix aTransformMatrix
|
||||
= maMapTransform
|
||||
* basegfx::B2DHomMatrix(
|
||||
/* Row 0, Column 0 */ aDstSize.getWidth(),
|
||||
const basegfx::B2DHomMatrix aDestMatrix =
|
||||
maMapTransform * basegfx::B2DHomMatrix(
|
||||
/* Row 0, Column 0 */ dw,
|
||||
/* Row 0, Column 1 */ fShearX,
|
||||
/* Row 0, Column 2 */ aDstPoint.getX(),
|
||||
/* Row 0, Column 2 */ dx,
|
||||
/* Row 1, Column 0 */ fShearY,
|
||||
/* Row 1, Column 1 */ aDstSize.getHeight(),
|
||||
/* Row 1, Column 2 */ aDstPoint.getY());
|
||||
/* Row 1, Column 1 */ dh,
|
||||
/* Row 1, Column 2 */ dy);
|
||||
|
||||
if (image->type == ImageDataTypeBitmap)
|
||||
{
|
||||
@@ -1614,18 +1605,46 @@ namespace emfplushelper
|
||||
{
|
||||
mrTargetHolders.Current().append(
|
||||
new drawinglayer::primitive2d::BitmapPrimitive2D(
|
||||
aBmp, aTransformMatrix));
|
||||
aBmp, aDestMatrix));
|
||||
}
|
||||
else
|
||||
SAL_WARN("drawinglayer.emf", "EMF+\t warning: empty bitmap");
|
||||
}
|
||||
else if (image->type == ImageDataTypeMetafile)
|
||||
{
|
||||
GDIMetaFile aGDI(image->graphic.GetGDIMetaFile());
|
||||
aGDI.Clip(aSource);
|
||||
SAL_INFO("drawinglayer.emf",
|
||||
"\t\t Metafile Dimensions: " << image->x << "," << image->y
|
||||
<< " [" << image->width << "x"
|
||||
<< image->height);
|
||||
|
||||
const GDIMetaFile aGDI(image->graphic.GetGDIMetaFile());
|
||||
basegfx::B2DHomMatrix aFinalMatrix = aDestMatrix;
|
||||
if (image->width > 0 && image->height > 0 && sw > 0. && sh > 0.)
|
||||
{
|
||||
const double fRelSrcX = sx - static_cast<double>(image->x);
|
||||
const double fRelSrcY = sy - static_cast<double>(image->y);
|
||||
const basegfx::B2DHomMatrix aNormalizeMatrix(
|
||||
/* Row 0, Column 0 */ static_cast<double>(image->width) / sw,
|
||||
/* Row 0, Column 1 */ 0.0,
|
||||
/* Row 0, Column 2 */ -fRelSrcX / sw,
|
||||
/* Row 1, Column 0 */ 0.0,
|
||||
/* Row 1, Column 1 */ static_cast<double>(image->height) / sh,
|
||||
/* Row 1, Column 2 */ -fRelSrcY / sh);
|
||||
|
||||
aFinalMatrix = aDestMatrix * aNormalizeMatrix;
|
||||
}
|
||||
|
||||
basegfx::B2DPolygon aClipPoly = basegfx::utils::createUnitPolygon();
|
||||
aClipPoly.transform(aDestMatrix);
|
||||
|
||||
mrTargetHolders.Current().append(
|
||||
new drawinglayer::primitive2d::MetafilePrimitive2D(aTransformMatrix,
|
||||
aGDI));
|
||||
new drawinglayer::primitive2d::MaskPrimitive2D(
|
||||
basegfx::B2DPolyPolygon(aClipPoly),
|
||||
drawinglayer::primitive2d::Primitive2DContainer {
|
||||
new drawinglayer::primitive2d::MetafilePrimitive2D(aFinalMatrix, aGDI)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -60,6 +60,40 @@ namespace emfplushelper
|
||||
SvMemoryStream mfStream(const_cast<char *>(static_cast<char const *>(s.GetData()) + s.Tell()), dataSize, StreamMode::READ);
|
||||
filter.ImportGraphic(graphic, u"", mfStream);
|
||||
|
||||
mfStream.Seek(0);
|
||||
// 1 = Wmf, 2 = WmfPlaceable, 3 = Emf, 4 = EmfPlusOnly, 5 = EmfPlusDual
|
||||
if (mfType == 3 || mfType == 4 || mfType == 5)
|
||||
{
|
||||
sal_uInt32 dwRecordType, dwRecordSize, dSignature, nVersion;
|
||||
sal_Int32 rclBoundsLeft, rclBoundsTop, rclBoundsRight, rclBoundsBottom;
|
||||
|
||||
mfStream.ReadUInt32(dwRecordType);
|
||||
mfStream.ReadUInt32(dwRecordSize);
|
||||
mfStream.ReadInt32(rclBoundsLeft);
|
||||
mfStream.ReadInt32(rclBoundsTop);
|
||||
mfStream.ReadInt32(rclBoundsRight);
|
||||
mfStream.ReadInt32(rclBoundsBottom);
|
||||
|
||||
mfStream.SeekRel(16);
|
||||
|
||||
mfStream.ReadUInt32(dSignature);
|
||||
mfStream.ReadUInt32(nVersion);
|
||||
|
||||
if (dwRecordType == 1 && dSignature == 0x464D4520)
|
||||
{
|
||||
x = rclBoundsLeft;
|
||||
y = rclBoundsTop;
|
||||
width = rclBoundsRight - rclBoundsLeft;
|
||||
height = rclBoundsBottom - rclBoundsTop;
|
||||
SAL_INFO("drawinglayer.emf", "EMF+\tNested EMF Header detected.");
|
||||
SAL_INFO("drawinglayer.emf",
|
||||
"EMF+\tBounds: [" << rclBoundsLeft << "," << rclBoundsTop << ", "
|
||||
<< rclBoundsRight << ", " << rclBoundsBottom << "]");
|
||||
SAL_INFO("drawinglayer.emf",
|
||||
"EMF+\tVersion: 0x" << std::hex << nVersion << std::dec);
|
||||
}
|
||||
}
|
||||
|
||||
// debug code - write the stream to debug file /tmp/emf-stream.emf
|
||||
#if OSL_DEBUG_LEVEL > 1
|
||||
mfStream.Seek(0);
|
||||
|
||||
@@ -35,12 +35,24 @@ namespace emfplushelper
|
||||
struct EMFPImage : public EMFPObject
|
||||
{
|
||||
sal_uInt32 type;
|
||||
sal_Int32 x;
|
||||
sal_Int32 y;
|
||||
sal_Int32 width;
|
||||
sal_Int32 height;
|
||||
sal_Int32 stride;
|
||||
sal_uInt32 pixelFormat;
|
||||
Graphic graphic;
|
||||
|
||||
EMFPImage():
|
||||
type(ImageDataTypeUnknown),
|
||||
x(0),
|
||||
y(0),
|
||||
width(0),
|
||||
height(0),
|
||||
stride(0),
|
||||
pixelFormat(0)
|
||||
{}
|
||||
|
||||
void Read(SvMemoryStream &s, sal_uInt32 dataSize, bool bUseWholeStream);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -118,12 +118,12 @@ void writePolyPolygon(::tools::XmlWriter& rWriter, const basegfx::B2DPolyPolygon
|
||||
{
|
||||
rWriter.startElement("polypolygon");
|
||||
const basegfx::B2DRange aB2DRange(rB2DPolyPolygon.getB2DRange());
|
||||
rWriter.attributeDouble("height", aB2DRange.getHeight());
|
||||
rWriter.attributeDouble("width", aB2DRange.getWidth());
|
||||
rWriter.attributeDouble("minx", aB2DRange.getMinX());
|
||||
rWriter.attributeDouble("miny", aB2DRange.getMinY());
|
||||
rWriter.attributeDouble("maxx", aB2DRange.getMaxX());
|
||||
rWriter.attributeDouble("maxy", aB2DRange.getMaxY());
|
||||
rWriter.attribute("height", aB2DRange.getHeight());
|
||||
rWriter.attribute("width", aB2DRange.getWidth());
|
||||
rWriter.attribute("minx", aB2DRange.getMinX());
|
||||
rWriter.attribute("miny", aB2DRange.getMinY());
|
||||
rWriter.attribute("maxx", aB2DRange.getMaxX());
|
||||
rWriter.attribute("maxy", aB2DRange.getMaxY());
|
||||
rWriter.attribute("path", basegfx::utils::exportToSvgD(rB2DPolyPolygon, true, true, false));
|
||||
|
||||
for (basegfx::B2DPolygon const& rPolygon : rB2DPolyPolygon)
|
||||
|
||||
@@ -146,6 +146,59 @@ CPPUNIT_TEST_FIXTURE(Test, testDrawImagePointsTypeBitmap)
|
||||
"b63539,b53335,ba3236,a2393e,1c0000");
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(Test, testDrawImagePointsWithMetafile)
|
||||
{
|
||||
// tdf166084 tdf138087 tdf59814 EMF+ file with ObjectTypeImage, DrawImagePoints
|
||||
// The test is checking the position and scale of embedded metafile drawed by DrawImagePoints
|
||||
|
||||
Primitive2DSequence aSequence
|
||||
= parseEmf(u"/emfio/qa/cppunit/emf/data/TestEmfPlusDrawImagePointsWithMetafile.emf");
|
||||
CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));
|
||||
drawinglayer::Primitive2dXmlDump dumper;
|
||||
xmlDocUniquePtr pDocument = dumper.dumpAndParse(Primitive2DContainer(aSequence));
|
||||
CPPUNIT_ASSERT(pDocument);
|
||||
|
||||
assertXPath(pDocument, aXPathPrefix + "mask/polypolygon", 1);
|
||||
assertXPath(pDocument, aXPathPrefix + "mask/polypolygon", "minx", u"0");
|
||||
assertXPath(pDocument, aXPathPrefix + "mask/polypolygon", "miny", u"0");
|
||||
assertXPath(pDocument, aXPathPrefix + "mask/polypolygon", "maxx", u"6921");
|
||||
assertXPath(pDocument, aXPathPrefix + "mask/polypolygon", "maxy", u"20306");
|
||||
assertXPath(pDocument, aXPathPrefix + "mask/mask/metafile/transform", "xy11", u"1");
|
||||
assertXPath(pDocument, aXPathPrefix + "mask/mask/metafile/transform", "xy12", u"0");
|
||||
assertXPath(pDocument, aXPathPrefix + "mask/mask/metafile/transform", "xy13", u"-3279");
|
||||
assertXPath(pDocument, aXPathPrefix + "mask/mask/metafile/transform", "xy21", u"0");
|
||||
assertXPath(pDocument, aXPathPrefix + "mask/mask/metafile/transform", "xy22", u"1");
|
||||
assertXPath(pDocument, aXPathPrefix + "mask/mask/metafile/transform", "xy23", u"-176");
|
||||
|
||||
assertXPath(pDocument, aXPathPrefix + "mask/mask/metafile/transform/mask/polypolygon", "height",
|
||||
u"15747");
|
||||
assertXPath(pDocument, aXPathPrefix + "mask/mask/metafile/transform/mask/polypolygon", "width",
|
||||
u"10088");
|
||||
|
||||
assertXPath(
|
||||
pDocument,
|
||||
aXPathPrefix + "mask/mask/metafile/transform/mask/mask/metafile/transform/mask/group", 17);
|
||||
|
||||
assertXPath(pDocument,
|
||||
aXPathPrefix + "mask/mask/metafile/transform/mask/mask/metafile/transform", "xy11",
|
||||
u"1");
|
||||
assertXPath(pDocument,
|
||||
aXPathPrefix + "mask/mask/metafile/transform/mask/mask/metafile/transform", "xy12",
|
||||
u"0");
|
||||
assertXPath(pDocument,
|
||||
aXPathPrefix + "mask/mask/metafile/transform/mask/mask/metafile/transform", "xy13",
|
||||
u"3");
|
||||
assertXPath(pDocument,
|
||||
aXPathPrefix + "mask/mask/metafile/transform/mask/mask/metafile/transform", "xy21",
|
||||
u"0");
|
||||
assertXPath(pDocument,
|
||||
aXPathPrefix + "mask/mask/metafile/transform/mask/mask/metafile/transform", "xy22",
|
||||
u"1");
|
||||
assertXPath(pDocument,
|
||||
aXPathPrefix + "mask/mask/metafile/transform/mask/mask/metafile/transform", "xy23",
|
||||
u"-140");
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(Test, testFillRectsWithTextureBrush)
|
||||
{
|
||||
// tdf#129342 tdf#170985 EMF+ file with ObjectTypeBrush, ObjectTypepen, FillRects
|
||||
|
||||
Binary file not shown.
@@ -1424,8 +1424,8 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf158445)
|
||||
xmlDocUniquePtr pDocument = dumpAndParseSvg(u"/svgio/qa/cppunit/data/tdf158445.svg");
|
||||
|
||||
assertXPath(pDocument, "/primitive2D/transform/mask/transform/transform/transform/polypolygoncolor", "color", u"#000000");
|
||||
assertXPath(pDocument, "/primitive2D/transform/mask/transform/transform/transform/polypolygoncolor/polypolygon", "height", u"8.052");
|
||||
assertXPath(pDocument, "/primitive2D/transform/mask/transform/transform/transform/polypolygoncolor/polypolygon", "width", u"5.328");
|
||||
assertXPath(pDocument, "/primitive2D/transform/mask/transform/transform/transform/polypolygoncolor/polypolygon", "height", u"8");
|
||||
assertXPath(pDocument, "/primitive2D/transform/mask/transform/transform/transform/polypolygoncolor/polypolygon", "width", u"5");
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(Test, testTdf159594)
|
||||
@@ -1433,8 +1433,8 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf159594)
|
||||
xmlDocUniquePtr pDocument = dumpAndParseSvg(u"/svgio/qa/cppunit/data/tdf159594.svg");
|
||||
|
||||
assertXPath(pDocument, "/primitive2D/transform/transform/polypolygoncolor", "color", u"#000000");
|
||||
assertXPath(pDocument, "/primitive2D/transform/transform/polypolygoncolor/polypolygon", "height", u"11.671875");
|
||||
assertXPath(pDocument, "/primitive2D/transform/transform/polypolygoncolor/polypolygon", "width", u"7.5");
|
||||
assertXPath(pDocument, "/primitive2D/transform/transform/polypolygoncolor/polypolygon", "height", u"12");
|
||||
assertXPath(pDocument, "/primitive2D/transform/transform/polypolygoncolor/polypolygon", "width", u"8");
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(Test, testTdf97663)
|
||||
|
||||
Reference in New Issue
Block a user