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
This commit is contained in:
Jeff Young 2022-04-08 11:35:52 +01:00
parent 702623ef87
commit 079d4a603a
4 changed files with 43 additions and 15 deletions

View File

@ -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 );
}

View File

@ -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 );
}

View File

@ -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,
"<g style=\"fill:#%6.6lX; fill-opacity:%.*f;stroke:#%6.6lX; stroke-opacity:%.*f;\n",
m_brush_rgb_color, m_precision, opacity, m_pen_rgb_color, m_precision, opacity );
m_brush_rgb_color, m_precision, m_brush_alpha, m_pen_rgb_color, m_precision, opacity );
// output the pen cap and line joint
fputs( "stroke-linecap:round; stroke-linejoin:round;\"\n", m_outputFile );

View File

@ -131,7 +131,7 @@ protected:
virtual std::string encodeStringForPlotter( const wxString& aUnicode );
/// Virtual primitive for emitting the setrgbcolor operator
virtual void emitSetRGBColor( double r, double g, double b ) = 0;
virtual void emitSetRGBColor( double r, double g, double b, double a ) = 0;
/// Height of the postscript font (from the AFM)
static const double postscriptTextAscent; // = 0.718;
@ -232,7 +232,7 @@ public:
void* aData = nullptr ) override;
protected:
virtual void emitSetRGBColor( double r, double g, double b ) override;
virtual void emitSetRGBColor( double r, double g, double b, double a ) override;
};
@ -373,7 +373,7 @@ protected:
* engines. Also arcs are filled as pies but only the arc is stroked so
* it would be difficult to handle anyway.
*/
virtual void emitSetRGBColor( double r, double g, double b ) override;
virtual void emitSetRGBColor( double r, double g, double b, double a ) override;
/**
* Allocate a new handle in the table of the PDF object. The
@ -521,7 +521,7 @@ protected:
* Initialize m_pen_rgb_color from reduced values r, g ,b
* ( reduced values are 0.0 to 1.0 )
*/
virtual void emitSetRGBColor( double r, double g, double b ) override;
virtual void emitSetRGBColor( double r, double g, double b, double a ) override;
/**
* Output the string which define pen and brush color, shape, transparency
@ -544,6 +544,7 @@ protected:
// (written in hex to svg files)
long m_brush_rgb_color; // same as m_pen_rgb_color, used to fill
// some contours.
double m_brush_alpha;
bool m_graphics_changed; // true if a pen/brush parameter is modified
// color, pen size, fill mode ...
// the new SVG stype must be output on file