[Libreoffice-commits] core.git: vcl/source

Pierre-Eric Pelloux-Prayer pierre-eric at lanedo.com
Mon Sep 9 12:28:21 PDT 2013


 vcl/source/gdi/pdfwriter.cxx       |   13 +++
 vcl/source/gdi/pdfwriter_impl.cxx  |  153 +++++++++++++++++++++++++++++++------
 vcl/source/gdi/pdfwriter_impl2.cxx |   62 ++++++++++----
 3 files changed, 186 insertions(+), 42 deletions(-)

New commits:
commit 0f5368434ef506aadfbd44613b7b98270e6a00c7
Author: Pierre-Eric Pelloux-Prayer <pierre-eric at lanedo.com>
Date:   Tue Sep 3 13:31:51 2013 +0200

    vcl/pdfwriter: export linear/axial gradients as PDF gradients
    
    Using PDF's Axial shading leads to better visual result than Sampled
    function shading.
    Only GradientStyle_LINEAR and GradientStyle_AXIAL are affected by
    this change, all other gradient styles are exported as before.
    
    Change-Id: Ib4d549987e34b7ba5d1c5adaf30908f2e306d07e
    Reviewed-on: https://gerrit.libreoffice.org/5799
    Reviewed-by: Michael Meeks <michael.meeks at collabora.com>
    Tested-by: Michael Meeks <michael.meeks at collabora.com>

diff --git a/vcl/source/gdi/pdfwriter.cxx b/vcl/source/gdi/pdfwriter.cxx
index 137319a..fba8f18 100644
--- a/vcl/source/gdi/pdfwriter.cxx
+++ b/vcl/source/gdi/pdfwriter.cxx
@@ -192,6 +192,19 @@ void PDFWriter::DrawHatch( const PolyPolygon& rPolyPoly, const Hatch& rHatch )
     pImplementation->drawHatch( rPolyPoly, rHatch );
 }
 
+void PDFWriter::DrawGradient( const Rectangle& rRect, const Gradient& rGradient )
+{
+    pImplementation->drawGradient( rRect, rGradient );
+}
+
+void PDFWriter::DrawGradient( const PolyPolygon& rPolyPoly, const Gradient& rGradient )
+{
+    pImplementation->push(PUSH_CLIPREGION);
+    pImplementation->setClipRegion( rPolyPoly.getB2DPolyPolygon() );
+    pImplementation->drawGradient( rPolyPoly.GetBoundRect(), rGradient );
+    pImplementation->pop();
+}
+
 void PDFWriter::DrawWallpaper( const Rectangle& rRect, const Wallpaper& rWallpaper )
 {
     pImplementation->drawWallpaper( rRect, rWallpaper );
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 9b720c2..e3d9ecf 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -9455,6 +9455,12 @@ bool PDFWriterImpl::writeTransparentObject( TransparencyEmit& rObject )
 
 bool PDFWriterImpl::writeGradientFunction( GradientEmit& rObject )
 {
+    // LO internal gradient -> PDF shading type:
+    //  * GradientStyle_LINEAR: axial shading, using sampled-function with 2 samples
+    //                          [t=0:colorStart, t=1:colorEnd]
+    //  * GradientStyle_AXIAL: axial shading, using sampled-function with 3 samples
+    //                          [t=0:colorEnd, t=0.5:colorStart, t=1:colorEnd]
+    //  * other styles: function shading with aSize.Width() * aSize.Height() samples
     sal_Int32 nFunctionObject = createObject();
     CHECK_RETURN( updateObject( nFunctionObject ) );
 
@@ -9480,12 +9486,30 @@ bool PDFWriterImpl::writeGradientFunction( GradientEmit& rObject )
     OStringBuffer aLine( 120 );
     aLine.append( nFunctionObject );
     aLine.append( " 0 obj\n"
-                  "<</FunctionType 0\n"
-                  "/Domain[ 0 1 0 1 ]\n"
-                  "/Size[ " );
-    aLine.append( (sal_Int32)aSize.Width() );
-    aLine.append( ' ' );
-    aLine.append( (sal_Int32)aSize.Height() );
+                  "<</FunctionType 0\n");
+    switch (rObject.m_aGradient.GetStyle())
+    {
+        case GradientStyle::GradientStyle_LINEAR:
+        case GradientStyle::GradientStyle_AXIAL:
+            aLine.append("/Domain[ 0 1]\n");
+            break;
+        default:
+            aLine.append("/Domain[ 0 1 0 1]\n");
+    }
+    aLine.append("/Size[ " );
+    switch (rObject.m_aGradient.GetStyle())
+    {
+        case GradientStyle::GradientStyle_LINEAR:
+            aLine.append('2');
+            break;
+        case GradientStyle::GradientStyle_AXIAL:
+            aLine.append('3');
+            break;
+        default:
+            aLine.append( (sal_Int32)aSize.Width() );
+            aLine.append( ' ' );
+            aLine.append( (sal_Int32)aSize.Height() );
+    }
     aLine.append( " ]\n"
                   "/BitsPerSample 8\n"
                   "/Range[ 0 1 0 1 0 1 ]\n"
@@ -9505,17 +9529,39 @@ bool PDFWriterImpl::writeGradientFunction( GradientEmit& rObject )
 
     checkAndEnableStreamEncryption( nFunctionObject );
     beginCompression();
-    for( int y = aSize.Height()-1; y >= 0; y-- )
+    sal_uInt8 aCol[3];
+    switch (rObject.m_aGradient.GetStyle())
     {
-        for( int x = 0; x < aSize.Width(); x++ )
+        case GradientStyle::GradientStyle_AXIAL:
+            aCol[0] = rObject.m_aGradient.GetEndColor().GetRed();
+            aCol[1] = rObject.m_aGradient.GetEndColor().GetGreen();
+            aCol[2] = rObject.m_aGradient.GetEndColor().GetBlue();
+            CHECK_RETURN( writeBuffer( aCol, 3 ) );
+        case GradientStyle::GradientStyle_LINEAR:
         {
-            sal_uInt8 aCol[3];
-            BitmapColor aColor = pAccess->GetColor( y, x );
-            aCol[0] = aColor.GetRed();
-            aCol[1] = aColor.GetGreen();
-            aCol[2] = aColor.GetBlue();
+            aCol[0] = rObject.m_aGradient.GetStartColor().GetRed();
+            aCol[1] = rObject.m_aGradient.GetStartColor().GetGreen();
+            aCol[2] = rObject.m_aGradient.GetStartColor().GetBlue();
             CHECK_RETURN( writeBuffer( aCol, 3 ) );
+
+            aCol[0] = rObject.m_aGradient.GetEndColor().GetRed();
+            aCol[1] = rObject.m_aGradient.GetEndColor().GetGreen();
+            aCol[2] = rObject.m_aGradient.GetEndColor().GetBlue();
+            CHECK_RETURN( writeBuffer( aCol, 3 ) );
+            break;
         }
+        default:
+            for( int y = aSize.Height()-1; y >= 0; y-- )
+            {
+                for( int x = 0; x < aSize.Width(); x++ )
+                {
+                    BitmapColor aColor = pAccess->GetColor( y, x );
+                    aCol[0] = aColor.GetRed();
+                    aCol[1] = aColor.GetGreen();
+                    aCol[2] = aColor.GetBlue();
+                    CHECK_RETURN( writeBuffer( aCol, 3 ) );
+                }
+            }
     }
     endCompression();
     disableStreamEncryption();
@@ -9539,17 +9585,76 @@ bool PDFWriterImpl::writeGradientFunction( GradientEmit& rObject )
     CHECK_RETURN( updateObject( rObject.m_nObject ) );
     aLine.setLength( 0 );
     aLine.append( rObject.m_nObject );
-    aLine.append( " 0 obj\n"
-                  "<</ShadingType 1\n"
-                  "/ColorSpace/DeviceRGB\n"
-                  "/AntiAlias true\n"
-                  "/Domain[ 0 1 0 1 ]\n"
-                  "/Matrix[ " );
-    aLine.append( (sal_Int32)aSize.Width() );
-    aLine.append( " 0 0 " );
-    aLine.append( (sal_Int32)aSize.Height() );
-    aLine.append( " 0 0 ]\n"
-                  "/Function " );
+    aLine.append( " 0 obj\n");
+    switch (rObject.m_aGradient.GetStyle())
+    {
+        case GradientStyle::GradientStyle_LINEAR:
+        case GradientStyle::GradientStyle_AXIAL:
+            aLine.append("<</ShadingType 2\n");
+            break;
+        default:
+            aLine.append("<</ShadingType 1\n");
+    }
+    aLine.append("/ColorSpace/DeviceRGB\n"
+                  "/AntiAlias true\n");
+
+    // Determination of shading axis
+    // See: OutputDevice::ImplDrawLinearGradient for reference
+    Rectangle aRect;
+    aRect.Left() = aRect.Top() = 0;
+    aRect.Right() = aSize.Width();
+    aRect.Bottom() = aSize.Height();
+
+    Rectangle aBoundRect;
+    Point     aCenter;
+    sal_uInt16    nAngle = rObject.m_aGradient.GetAngle() % 3600;
+    rObject.m_aGradient.GetBoundRect( aRect, aBoundRect, aCenter );
+
+    const bool bLinear = (rObject.m_aGradient.GetStyle() == GradientStyle_LINEAR);
+    double fBorder = aBoundRect.GetHeight() * rObject.m_aGradient.GetBorder() / 100.0;
+    if ( !bLinear )
+    {
+        fBorder /= 2.0;
+    }
+
+    aBoundRect.Bottom() -= fBorder;
+    if (!bLinear)
+    {
+        aBoundRect.Top() += fBorder;
+    }
+
+    switch (rObject.m_aGradient.GetStyle())
+    {
+        case GradientStyle::GradientStyle_LINEAR:
+        case GradientStyle::GradientStyle_AXIAL:
+        {
+            aLine.append("/Domain[ 0 1 ]\n"
+                    "/Coords[ " );
+            Polygon     aPoly( 2 );
+            aPoly[0] = aBoundRect.BottomCenter();
+            aPoly[1] = aBoundRect.TopCenter();
+            aPoly.Rotate( aCenter, 3600 - nAngle );
+
+            aLine.append( (sal_Int32) aPoly[0].X() );
+            aLine.append( " " );
+            aLine.append( (sal_Int32) aPoly[0].Y() );
+            aLine.append( " " );
+            aLine.append( (sal_Int32) aPoly[1].X());
+            aLine.append( " ");
+            aLine.append( (sal_Int32) aPoly[1].Y());
+            aLine.append( " ]\n");
+            aLine.append("/Extend [true true]\n");
+            break;
+        }
+        default:
+            aLine.append("/Domain[ 0 1 0 1 ]\n"
+                    "/Matrix[ " );
+            aLine.append( (sal_Int32)aSize.Width() );
+            aLine.append( " 0 0 " );
+            aLine.append( (sal_Int32)aSize.Height() );
+            aLine.append( " 0 0 ]\n");
+    }
+    aLine.append("/Function " );
     aLine.append( nFunctionObject );
     aLine.append( " 0 R\n"
                   ">>\n"
diff --git a/vcl/source/gdi/pdfwriter_impl2.cxx b/vcl/source/gdi/pdfwriter_impl2.cxx
index 2c3df15..0fd93ad 100644
--- a/vcl/source/gdi/pdfwriter_impl2.cxx
+++ b/vcl/source/gdi/pdfwriter_impl2.cxx
@@ -41,14 +41,14 @@
 
 #include <rtl/digest.h>
 
-#undef USE_PDFGRADIENTS
-
 using namespace vcl;
 using namespace rtl;
 using namespace com::sun::star;
 using namespace com::sun::star::uno;
 using namespace com::sun::star::beans;
 
+static bool lcl_canUsePDFAxialShading(const Gradient& rGradient);
+
 // -----------------------------------------------------------------------------
 
 void PDFWriterImpl::implWriteGradient( const PolyPolygon& i_rPolyPoly, const Gradient& i_rGradient,
@@ -360,23 +360,28 @@ void PDFWriterImpl::playMetafile( const GDIMetaFile& i_rMtf, vcl::PDFExtOutDevDa
                 case( META_GRADIENT_ACTION ):
                 {
                     const MetaGradientAction* pA = (const MetaGradientAction*) pAction;
-                    #ifdef USE_PDFGRADIENTS
-                    m_rOuterFace.DrawGradient( pA->GetRect(), pA->GetGradient() );
-                    #else
-                    const PolyPolygon         aPolyPoly( pA->GetRect() );
-                    implWriteGradient( aPolyPoly, pA->GetGradient(), pDummyVDev, i_rContext );
-                    #endif
+                    const Gradient& rGradient = pA->GetGradient();
+                    if (lcl_canUsePDFAxialShading(rGradient))
+                    {
+                        m_rOuterFace.DrawGradient( pA->GetRect(), rGradient );
+                    }
+                    else
+                    {
+                        const PolyPolygon aPolyPoly( pA->GetRect() );
+                        implWriteGradient( aPolyPoly, rGradient, pDummyVDev, i_rContext );
+                    }
                 }
                 break;
 
                 case( META_GRADIENTEX_ACTION ):
                 {
                     const MetaGradientExAction* pA = (const MetaGradientExAction*) pAction;
-                    #ifdef USE_PDFGRADIENTS
-                    m_rOuterFace.DrawGradient( pA->GetPolyPolygon(), pA->GetGradient() );
-                    #else
-                    implWriteGradient( pA->GetPolyPolygon(), pA->GetGradient(), pDummyVDev, i_rContext );
-                    #endif
+                    const Gradient& rGradient = pA->GetGradient();
+
+                    if (lcl_canUsePDFAxialShading(rGradient))
+                        m_rOuterFace.DrawGradient( pA->GetPolyPolygon(), rGradient );
+                    else
+                        implWriteGradient( pA->GetPolyPolygon(), rGradient, pDummyVDev, i_rContext );
                 }
                 break;
 
@@ -535,11 +540,14 @@ void PDFWriterImpl::playMetafile( const GDIMetaFile& i_rMtf, vcl::PDFExtOutDevDa
 
                         if( pGradAction )
                         {
-                            #ifdef USE_PDFGRADIENTS
-                            m_rOuterFace.DrawGradient( pGradAction->GetPolyPolygon(), pGradAction->GetGradient() );
-                            #else
-                            implWriteGradient( pGradAction->GetPolyPolygon(), pGradAction->GetGradient(), pDummyVDev, i_rContext );
-                            #endif
+                            if (lcl_canUsePDFAxialShading(pGradAction->GetGradient()))
+                            {
+                                m_rOuterFace.DrawGradient( pGradAction->GetPolyPolygon(), pGradAction->GetGradient() );
+                            }
+                            else
+                            {
+                                implWriteGradient( pGradAction->GetPolyPolygon(), pGradAction->GetGradient(), pDummyVDev, i_rContext );
+                            }
                         }
                     }
                     else
@@ -2038,4 +2046,22 @@ void PDFWriterImpl::writeG4Stream( BitmapReadAccess* i_pBitmap )
     rtl_freeMemory( pFirstRefLine );
 }
 
+static bool lcl_canUsePDFAxialShading(const Gradient& rGradient) {
+    switch (rGradient.GetStyle())
+    {
+        case GradientStyle::GradientStyle_LINEAR:
+        case GradientStyle::GradientStyle_AXIAL:
+            break;
+        default:
+            return false;
+    }
+
+    // TODO: handle step count
+    if (rGradient.GetSteps() > 0)
+        return false;
+
+    return true;
+}
+
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list