filter/CppunitTest_filter_pdf.mk |    1 
 filter/qa/pdf.cxx                |   53 +++++++++++++++++++++++++++++++++++++++
 filter/source/pdf/pdfexport.cxx  |   38 +++++++++++++++++++++++++++
 filter/source/pdf/pdfexport.hxx  |    1 
 4 files changed, 93 insertions(+)

New commits:
commit 574db5efa9a2ab6d70faedf538be77a1eb8c597b
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Thu Nov 24 14:30:22 2022 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Thu Nov 24 16:30:31 2022 +0100

    Related: tdf#54053 PDF export: add UNO API to customize the watermark 
rotation
    
    The watermark direction is currently either 0 degrees for landscape
    pages or 270 degrees for portrait pages.
    
    The problem is many people expect 45 degrees rotation angle or some
    custom angle in general, and we provide no way to control it.
    
    Fix the problem by adding a new "WatermarkRotateAngle" PDF export filter
    option to specify the rotation angle explicitly. Note that the watermark
    text is still centered, and the text size is decreased to still fit the page
    boundaries. To keep things simple, do this shrinking by going with a
    size that matches the shorter dimension of the page, instead of some
    more complex iterative approach.
    
    Example cmdline usage:
    
    soffice --convert-to 
pdf:writer_pdf_Export:'{"Watermark":{"type":"string","value":"draft"}, 
"WatermarkRotateAngle":{"type":"long","value":"450"}}' test.odt
    
    Change-Id: I1fee14c333e68c92cf4c65ec100e04dcf024f907
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143229
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/filter/CppunitTest_filter_pdf.mk b/filter/CppunitTest_filter_pdf.mk
index e551ae6b9d07..912b84e0edb4 100644
--- a/filter/CppunitTest_filter_pdf.mk
+++ b/filter/CppunitTest_filter_pdf.mk
@@ -20,6 +20,7 @@ $(eval $(call 
gb_CppunitTest_add_exception_objects,filter_pdf, \
 ))
 
 $(eval $(call gb_CppunitTest_use_libraries,filter_pdf, \
+    basegfx \
     comphelper \
     cppu \
     cppuhelper \
diff --git a/filter/qa/pdf.cxx b/filter/qa/pdf.cxx
index 24014571b331..b631a3f8a4a8 100644
--- a/filter/qa/pdf.cxx
+++ b/filter/qa/pdf.cxx
@@ -20,6 +20,7 @@
 #include <tools/stream.hxx>
 #include <unotools/streamwrap.hxx>
 #include <vcl/filter/PDFiumLibrary.hxx>
+#include <tools/helpers.hxx>
 
 using namespace ::com::sun::star;
 
@@ -276,6 +277,58 @@ CPPUNIT_TEST_FIXTURE(Test, testWatermarkFontName)
     // i.e. the font name was sans, could not specify an explicit name.
     CPPUNIT_ASSERT_EQUAL(aExpectedFontName, aFontName);
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testWatermarkRotateAngle)
+{
+    // Given an empty Writer document:
+    std::shared_ptr<vcl::pdf::PDFium> pPDFium = vcl::pdf::PDFiumLibrary::get();
+    if (!pPDFium)
+        return;
+    mxComponent.set(loadFromDesktop("private:factory/swriter", 
"com.sun.star.text.TextDocument"));
+
+    // When exporting that as PDF with a rotated watermark:
+    uno::Reference<css::lang::XMultiServiceFactory> xFactory = 
getMultiServiceFactory();
+    uno::Reference<document::XFilter> xFilter(
+        xFactory->createInstance("com.sun.star.document.PDFFilter"), 
uno::UNO_QUERY);
+    uno::Reference<document::XExporter> xExporter(xFilter, uno::UNO_QUERY);
+    xExporter->setSourceDocument(mxComponent);
+    SvMemoryStream aStream;
+    uno::Reference<io::XOutputStream> xOutputStream(new 
utl::OStreamWrapper(aStream));
+    // 45.0 degrees, counter-clockwise.
+    sal_Int32 nExpectedRotateAngle = 45;
+    uno::Sequence<beans::PropertyValue> aFilterData{
+        comphelper::makePropertyValue("Watermark", OUString("X")),
+        comphelper::makePropertyValue("WatermarkRotateAngle", 
nExpectedRotateAngle * 10),
+    };
+    uno::Sequence<beans::PropertyValue> aDescriptor{
+        comphelper::makePropertyValue("FilterName", 
OUString("writer_pdf_Export")),
+        comphelper::makePropertyValue("FilterData", aFilterData),
+        comphelper::makePropertyValue("OutputStream", xOutputStream),
+    };
+    xFilter->filter(aDescriptor);
+
+    // Then make sure that the watermark rotation angle is correct:
+    std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument
+        = pPDFium->openDocument(aStream.GetData(), aStream.GetSize(), 
OString());
+    CPPUNIT_ASSERT(pPdfDocument);
+    std::unique_ptr<vcl::pdf::PDFiumPage> pPage = pPdfDocument->openPage(0);
+    CPPUNIT_ASSERT_EQUAL(1, pPage->getObjectCount());
+    std::unique_ptr<vcl::pdf::PDFiumPageObject> pPageObject = 
pPage->getObject(0);
+    CPPUNIT_ASSERT_EQUAL(1, pPageObject->getFormObjectCount());
+    std::unique_ptr<vcl::pdf::PDFiumPageObject> pFormObject = 
pPageObject->getFormObject(0);
+    basegfx::B2DHomMatrix aMatrix = pFormObject->getMatrix();
+    basegfx::B2DTuple aScale;
+    basegfx::B2DTuple aTranslate;
+    double fRotate{};
+    double fShearX{};
+    aMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
+    sal_Int32 nActualRotateAngle = NormAngle360(basegfx::rad2deg<1>(fRotate));
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 45
+    // - Actual  : 270
+    // i.e. the rotation angle was 270 for an A4 page, not the requested 45 
degrees.
+    CPPUNIT_ASSERT_EQUAL(nExpectedRotateAngle, nActualRotateAngle);
+}
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/filter/source/pdf/pdfexport.cxx b/filter/source/pdf/pdfexport.cxx
index 5bb6f0baa2fe..8204d6da86b3 100644
--- a/filter/source/pdf/pdfexport.cxx
+++ b/filter/source/pdf/pdfexport.cxx
@@ -577,6 +577,14 @@ bool PDFExport::Export( const OUString& rFile, const 
Sequence< PropertyValue >&
                         moWatermarkFontHeight = nFontHeight;
                     }
                 }
+                else if (rProp.Name == "WatermarkRotateAngle")
+                {
+                    sal_Int32 nRotateAngle{};
+                    if (rProp.Value >>= nRotateAngle)
+                    {
+                        moWatermarkRotateAngle = Degree10(nRotateAngle);
+                    }
+                }
                 else if (rProp.Name == "WatermarkFontName")
                 {
                     OUString aFontName{};
@@ -1189,6 +1197,17 @@ void PDFExport::ImplWriteWatermark( vcl::PDFWriter& 
rWriter, const Size& rPageSi
         aFont.SetOrientation( 2700_deg10 );
     }
 
+    if (moWatermarkRotateAngle)
+    {
+        aFont.SetOrientation(*moWatermarkRotateAngle);
+        if (rPageSize.Width() < rPageSize.Height())
+        {
+            // Set text width based on the shorter side, so rotation can't 
push text outside the
+            // page boundaries.
+            nTextWidth = rPageSize.Width();
+        }
+    }
+
     // adjust font height for text to fit
     OutputDevice* pDev = rWriter.GetReferenceDevice();
     pDev->Push();
@@ -1242,6 +1261,25 @@ void PDFExport::ImplWriteWatermark( vcl::PDFWriter& 
rWriter, const Size& rPageSi
                             (rPageSize.Height()-w)/2 );
         aTextRect = tools::Rectangle( aTextPoint, Size( nTextHeight, w ) );
     }
+
+    if (moWatermarkRotateAngle)
+    {
+        // First set the text's starting point to the center of the page.
+        tools::Rectangle aPageRectangle(Point(0, 0), rPageSize);
+        aTextPoint = aPageRectangle.Center();
+        // Then adjust it so that the text remains centered, based on the 
rotation angle.
+        basegfx::B2DPolygon aTextPolygon
+            = basegfx::utils::createPolygonFromRect(basegfx::B2DRectangle(0, 
-nTextHeight, w, 0));
+        basegfx::B2DHomMatrix aMatrix;
+        aMatrix.rotate(-1 * toRadians(*moWatermarkRotateAngle));
+        aTextPolygon.transform(aMatrix);
+        basegfx::B2DPoint aPolygonCenter = 
aTextPolygon.getB2DRange().getCenter();
+        aTextPoint.AdjustX(-aPolygonCenter.getX());
+        aTextPoint.AdjustY(-aPolygonCenter.getY());
+
+        aTextRect = aPageRectangle;
+    }
+
     rWriter.SetClipRegion();
     rWriter.BeginTransparencyGroup();
     rWriter.DrawText( aTextPoint, msWatermark );
diff --git a/filter/source/pdf/pdfexport.hxx b/filter/source/pdf/pdfexport.hxx
index 40ac7d3e2f9a..dfd371c3177b 100644
--- a/filter/source/pdf/pdfexport.hxx
+++ b/filter/source/pdf/pdfexport.hxx
@@ -76,6 +76,7 @@ private:
     Color               maWatermarkColor;
     std::optional<sal_Int32> moWatermarkFontHeight;
     OUString            maWatermarkFontName;
+    std::optional<Degree10> moWatermarkRotateAngle;
     OUString            msTiledWatermark;
 
     // these variable are here only to have a location in filter/pdf to set 
the default

Reply via email to