diff options
author | Pierre-Eric Pelloux-Prayer <pierre-eric@lanedo.com> | 2013-09-03 13:31:51 +0200 |
---|---|---|
committer | Michael Meeks <michael.meeks@collabora.com> | 2013-09-09 19:28:01 +0000 |
commit | 0f5368434ef506aadfbd44613b7b98270e6a00c7 (patch) | |
tree | 6dfb034c60ab9f84bffaf0e61615e92c272b0309 | |
parent | 7323bc340501c2600944193df54295c28de5482c (diff) |
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@collabora.com>
Tested-by: Michael Meeks <michael.meeks@collabora.com>
-rw-r--r-- | vcl/source/gdi/pdfwriter.cxx | 13 | ||||
-rw-r--r-- | vcl/source/gdi/pdfwriter_impl.cxx | 153 | ||||
-rw-r--r-- | vcl/source/gdi/pdfwriter_impl2.cxx | 62 |
3 files changed, 186 insertions, 42 deletions
diff --git a/vcl/source/gdi/pdfwriter.cxx b/vcl/source/gdi/pdfwriter.cxx index 137319ae80b0..fba8f18779cc 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 9b720c2c4de3..e3d9ecfd06fa 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 2c3df1504887..0fd93adcb00c 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: */ |