From 079d4a603af92c007a2d3f9f00c558877919438e Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Fri, 8 Apr 2022 11:35:52 +0100 Subject: [PATCH] Improve transparency handling while plotting. Only SVG can actually handle transparency, but we should at least mimic the color value of other transparent fills by blending with a (presumed) white paper. Fixes https://gitlab.com/kicad/code/kicad/issues/11304 --- common/plotters/PDF_plotter.cpp | 12 +++++++++++- common/plotters/PS_plotter.cpp | 21 ++++++++++++++++----- common/plotters/SVG_plotter.cpp | 16 +++++++++++----- include/plotters/plotters_pslike.h | 9 +++++---- 4 files changed, 43 insertions(+), 15 deletions(-) diff --git a/common/plotters/PDF_plotter.cpp b/common/plotters/PDF_plotter.cpp index fb19c53368..37092b59f0 100644 --- a/common/plotters/PDF_plotter.cpp +++ b/common/plotters/PDF_plotter.cpp @@ -159,9 +159,19 @@ void PDF_PLOTTER::SetCurrentLineWidth( int aWidth, void* aData ) } -void PDF_PLOTTER::emitSetRGBColor( double r, double g, double b ) +void PDF_PLOTTER::emitSetRGBColor( double r, double g, double b, double a ) { wxASSERT( workFile ); + + // PDF treats all colors as opaque, so the best we can do with alpha is generate an + // appropriate blended color assuming white paper. + if( a < 1.0 ) + { + r = ( r * a ) + ( 1 - a ); + g = ( g * a ) + ( 1 - a ); + b = ( b * a ) + ( 1 - a ); + } + fprintf( workFile, "%g %g %g rg %g %g %g RG\n", r, g, b, r, g, b ); } diff --git a/common/plotters/PS_plotter.cpp b/common/plotters/PS_plotter.cpp index 8b0d18a908..d210123a3c 100644 --- a/common/plotters/PS_plotter.cpp +++ b/common/plotters/PS_plotter.cpp @@ -64,9 +64,9 @@ void PSLIKE_PLOTTER::SetColor( const COLOR4D& color ) if( m_colorMode ) { if( m_negativeMode ) - emitSetRGBColor( 1 - color.r, 1 - color.g, 1 - color.b ); + emitSetRGBColor( 1 - color.r, 1 - color.g, 1 - color.b, color.a ); else - emitSetRGBColor( color.r, color.g, color.b ); + emitSetRGBColor( color.r, color.g, color.b, color.a ); } else { @@ -80,9 +80,9 @@ void PSLIKE_PLOTTER::SetColor( const COLOR4D& color ) k = 0; if( m_negativeMode ) - emitSetRGBColor( 1 - k, 1 - k, 1 - k ); + emitSetRGBColor( 1 - k, 1 - k, 1 - k, 1.0 ); else - emitSetRGBColor( k, k, k ); + emitSetRGBColor( k, k, k, 1.0 ); } } @@ -527,10 +527,21 @@ void PS_PLOTTER::SetCurrentLineWidth( int aWidth, void* aData ) } -void PS_PLOTTER::emitSetRGBColor( double r, double g, double b ) +void PS_PLOTTER::emitSetRGBColor( double r, double g, double b, double a ) { wxASSERT( m_outputFile ); + // Postscript treats all colors as opaque, so the best we can do with alpha is generate + // an appropriate blended color assuming white paper. (It's possible that a halftone would + // work better on *some* drivers, but most drivers are known to still treat halftones as + // opaque and remove any colors underneath them.) + if( a < 1.0 ) + { + r = ( r * a ) + ( 1 - a ); + g = ( g * a ) + ( 1 - a ); + b = ( b * a ) + ( 1 - a ); + } + // XXX why %.3g ? shouldn't %g suffice? who cares... fprintf( m_outputFile, "%.3g %.3g %.3g setrgbcolor\n", r, g, b ); } diff --git a/common/plotters/SVG_plotter.cpp b/common/plotters/SVG_plotter.cpp index 791ba98447..c5cb4dbb21 100644 --- a/common/plotters/SVG_plotter.cpp +++ b/common/plotters/SVG_plotter.cpp @@ -168,6 +168,7 @@ SVG_PLOTTER::SVG_PLOTTER() m_fillMode = FILL_T::NO_FILL; // or FILLED_SHAPE or FILLED_WITH_BG_BODYCOLOR m_pen_rgb_color = 0; // current color value (black) m_brush_rgb_color = 0; // current color value (black) + m_brush_alpha = 1.0; m_dashed = PLOT_DASH_TYPE::SOLID; m_useInch = false; // millimeters are always the svg unit m_precision = 4; // default: 4 digits in mantissa. @@ -233,10 +234,14 @@ void SVG_PLOTTER::setSVGPlotStyle( bool aIsGroup, const std::string& aExtraStyle switch( m_fillMode ) { - case FILL_T::NO_FILL: fputs( "fill-opacity:0.0; ", m_outputFile ); break; - case FILL_T::FILLED_SHAPE: fputs( "fill-opacity:1.0; ", m_outputFile ); break; + case FILL_T::NO_FILL: + fputs( "fill-opacity:0.0; ", m_outputFile ); + break; + case FILL_T::FILLED_SHAPE: case FILL_T::FILLED_WITH_BG_BODYCOLOR: - case FILL_T::FILLED_WITH_COLOR: fputs( "fill-opacity:0.6; ", m_outputFile ); break; + case FILL_T::FILLED_WITH_COLOR: + fprintf( m_outputFile, "fill-opacity:%.*f; ", m_precision, m_brush_alpha ); + break; } double pen_w = userToDeviceSize( GetCurrentLineWidth() ); @@ -342,7 +347,7 @@ void SVG_PLOTTER::EndBlock( void* aData ) } -void SVG_PLOTTER::emitSetRGBColor( double r, double g, double b ) +void SVG_PLOTTER::emitSetRGBColor( double r, double g, double b, double a ) { int red = (int) ( 255.0 * r ); int green = (int) ( 255.0 * g ); @@ -356,6 +361,7 @@ void SVG_PLOTTER::emitSetRGBColor( double r, double g, double b ) // Currently, use the same color for brush and pen (i.e. to draw and fill a contour). m_brush_rgb_color = rgb_color; + m_brush_alpha = a; } } @@ -746,7 +752,7 @@ bool SVG_PLOTTER::StartPlot() double opacity = 1.0; // 0.0 (transparent to 1.0 (solid) fprintf( m_outputFile, "