ADDED: Ability to set a PDF background color for PCB plots

Fixes https://gitlab.com/kicad/code/kicad/-/issues/20873
This commit is contained in:
Mark Roszko 2025-06-19 19:34:23 -04:00
parent e274307437
commit ce545f4d6c
13 changed files with 227 additions and 3 deletions

View File

@ -33,7 +33,10 @@ JOB_EXPORT_PCB_PDF::JOB_EXPORT_PCB_PDF() :
JOB_EXPORT_PCB_PLOT( JOB_EXPORT_PCB_PLOT::PLOT_FORMAT::PDF, "pdf", false ),
m_pdfFrontFPPropertyPopups( true ),
m_pdfBackFPPropertyPopups( true ),
m_pdfMetadata( true ), m_pdfSingle( false ), m_pdfGenMode( GEN_MODE::ALL_LAYERS_ONE_FILE )
m_pdfMetadata( true ),
m_pdfSingle( false ),
m_pdfGenMode( GEN_MODE::ALL_LAYERS_ONE_FILE ),
m_pdfBackgroundColor( "rgba(0,0,0,0)" ) // represents an unspecified color
{
m_plotDrawingSheet = false;
@ -51,6 +54,7 @@ JOB_EXPORT_PCB_PDF::JOB_EXPORT_PCB_PDF() :
&m_pdfBackFPPropertyPopups, m_pdfBackFPPropertyPopups ) );
m_params.emplace_back( new JOB_PARAM<GEN_MODE>( "pdf_gen_mode",
&m_pdfGenMode, m_pdfGenMode ) );
m_params.emplace_back( new JOB_PARAM<wxString>( "background_color", &m_pdfBackgroundColor, m_pdfBackgroundColor ) );
}

View File

@ -56,6 +56,9 @@ public:
///< uused by the cli, will be removed when the other behavior is deprecated
GEN_MODE m_pdfGenMode;
///< The background color specified in a hex string
wxString m_pdfBackgroundColor;
};
#endif

View File

@ -68,6 +68,9 @@ namespace CLI
#define ARG_SCALE "--scale"
#define ARG_SCALE_DESC "Scale for the PCB, not for the border and title. Use 0 for autoscale"
#define ARG_BACKGROUND_COLOR "--bg-color"
#define ARG_BACKGROUND_COLOR_DESC "Background color, can be in hex #rrggbb, #rrggbbaa; or css rgb(r,g,b), rgba(r,g,b,a) format"
struct PCB_EXPORT_BASE_COMMAND : public COMMAND
{
PCB_EXPORT_BASE_COMMAND( const std::string& aName, bool aInputCanBeDir = false,

View File

@ -119,6 +119,11 @@ CLI::PCB_EXPORT_PDF_COMMAND::PCB_EXPORT_PDF_COMMAND() :
.scan<'g', double>()
.default_value( 1.0 )
.metavar( "SCALE" );
m_argParser.add_argument( ARG_BACKGROUND_COLOR )
.default_value( std::string() )
.help( UTF8STDSTR( _( ARG_BACKGROUND_COLOR_DESC ) ) )
.metavar( "COLOR" );
}
@ -157,6 +162,10 @@ int CLI::PCB_EXPORT_PDF_COMMAND::doPerform( KIWAY& aKiway )
pdfJob->m_sketchDNPFPsOnFabLayers = m_argParser.get<bool>( ARG_SKETCH_DNP_FPS_ON_FAB_LAYERS );
pdfJob->m_crossoutDNPFPsOnFabLayers = m_argParser.get<bool>( ARG_CROSSOUT_DNP_FPS_ON_FAB_LAYERS );
wxString bgColor = From_UTF8( m_argParser.get<std::string>( ARG_BACKGROUND_COLOR ).c_str() );
if( bgColor != wxEmptyString )
pdfJob->m_pdfBackgroundColor = bgColor;
int drillShape = m_argParser.get<int>( ARG_DRILL_SHAPE_OPTION );
pdfJob->m_drillShapeOption = static_cast<DRILL_MARKS>( drillShape );

View File

@ -41,6 +41,7 @@
#include <dialog_gendrill.h>
#include <widgets/wx_html_report_panel.h>
#include <widgets/std_bitmap_button.h>
#include <widgets/color_swatch.h>
#include <tool/tool_manager.h>
#include <tools/zone_filler_tool.h>
#include <tools/drc_tool.h>
@ -118,6 +119,8 @@ DIALOG_PLOT::DIALOG_PLOT( PCB_EDIT_FRAME* aEditFrame, wxWindow* aParent,
{
BOARD* board = m_editFrame->GetBoard();
m_pdfBackgroundColorSwatch->SetDefaultColor( COLOR4D::UNSPECIFIED );
SetName( DLG_WINDOW_NAME );
m_DRCWarningTemplate = m_DRCExclusionsWarning->GetLabel();
@ -433,6 +436,8 @@ void DIALOG_PLOT::init_Dialog()
m_backFPPropertyPopups->SetValue( m_plotOpts.m_PDFBackFPPropertyPopups );
m_pdfMetadata->SetValue( m_plotOpts.m_PDFMetadata );
m_pdfSingle->SetValue( m_plotOpts.m_PDFSingle );
m_pdfBackgroundColorSwatch->SetSwatchColor( m_plotOpts.m_PDFBackgroundColor, false );
updatePdfColorOptions();
// Initialize a few other parameters, which can also be modified
// from the drill dialog
@ -500,6 +505,7 @@ void DIALOG_PLOT::transferPlotParamsToJob()
pdfJob->m_pdfBackFPPropertyPopups = m_plotOpts.m_PDFBackFPPropertyPopups;
pdfJob->m_pdfMetadata = m_plotOpts.m_PDFMetadata;
pdfJob->m_pdfSingle = m_plotOpts.m_PDFSingle;
pdfJob->m_pdfBackgroundColor = m_plotOpts.m_PDFBackgroundColor.ToCSSString();
// we need to embed this for the cli deprecation fix
if( pdfJob->m_pdfSingle )
@ -1044,6 +1050,7 @@ void DIALOG_PLOT::applyPlotSettings()
tempOptions.m_PDFBackFPPropertyPopups = m_backFPPropertyPopups->GetValue();
tempOptions.m_PDFMetadata = m_pdfMetadata->GetValue();
tempOptions.m_PDFSingle = m_pdfSingle->GetValue();
tempOptions.m_PDFBackgroundColor = m_pdfBackgroundColorSwatch->GetSwatchColor();
}
else
{
@ -1401,3 +1408,24 @@ void DIALOG_PLOT::onSketchPads( wxCommandEvent& aEvent )
{
m_plotPadNumbers->Enable( aEvent.IsChecked() );
}
void DIALOG_PLOT::updatePdfColorOptions()
{
if( m_PDFColorChoice->GetSelection() == 1 )
{
m_pdfBackgroundColorSwatch->Disable();
m_pdfBackgroundColorText->Disable();
}
else
{
m_pdfBackgroundColorSwatch->Enable();
m_pdfBackgroundColorText->Enable();
}
}
void DIALOG_PLOT::onPDFColorChoice( wxCommandEvent& aEvent )
{
updatePdfColorOptions();
}

View File

@ -66,6 +66,7 @@ private:
void onDNPCheckbox( wxCommandEvent& event ) override;
void onSketchPads( wxCommandEvent& event ) override;
void onPDFColorChoice( wxCommandEvent& event ) override;
// other functions
void init_Dialog(); // main initialization
@ -76,6 +77,7 @@ private:
void arrangeAllLayersList( const LSEQ& aSeq );
void loadPlotParamsFromJob();
void transferPlotParamsToJob();
void updatePdfColorOptions();
private:
PCB_EDIT_FRAME* m_editFrame;

View File

@ -5,6 +5,7 @@
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "widgets/color_swatch.h"
#include "widgets/std_bitmap_button.h"
#include "widgets/wx_html_report_panel.h"
@ -392,7 +393,14 @@ DIALOG_PLOT_BASE::DIALOG_PLOT_BASE( wxWindow* parent, wxWindowID id, const wxStr
gbSizer4->Add( m_pdfMetadata, wxGBPosition( 3, 0 ), wxGBSpan( 1, 2 ), wxLEFT|wxRIGHT, 5 );
m_pdfSingle = new wxCheckBox( m_PDFOptionsSizer->GetStaticBox(), wxID_ANY, _("Single document"), wxDefaultPosition, wxDefaultSize, 0 );
gbSizer4->Add( m_pdfSingle, wxGBPosition( 4, 0 ), wxGBSpan( 1, 2 ), wxBOTTOM|wxLEFT|wxRIGHT, 5 );
gbSizer4->Add( m_pdfSingle, wxGBPosition( 4, 0 ), wxGBSpan( 1, 2 ), wxLEFT|wxRIGHT, 5 );
m_pdfBackgroundColorText = new wxStaticText( m_PDFOptionsSizer->GetStaticBox(), wxID_ANY, _("Background Color"), wxDefaultPosition, wxDefaultSize, 0 );
m_pdfBackgroundColorText->Wrap( -1 );
gbSizer4->Add( m_pdfBackgroundColorText, wxGBPosition( 5, 0 ), wxGBSpan( 1, 1 ), wxALL, 5 );
m_pdfBackgroundColorSwatch = new COLOR_SWATCH( m_PDFOptionsSizer->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
gbSizer4->Add( m_pdfBackgroundColorSwatch, wxGBPosition( 5, 1 ), wxGBSpan( 1, 1 ), wxALL, 5 );
m_PDFOptionsSizer->Add( gbSizer4, 1, wxEXPAND|wxBOTTOM, 5 );
@ -457,6 +465,7 @@ DIALOG_PLOT_BASE::DIALOG_PLOT_BASE( wxWindow* parent, wxWindowID id, const wxStr
m_boardSetup->Connect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( DIALOG_PLOT_BASE::onBoardSetup ), NULL, this );
m_useGerberX2Format->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_PLOT_BASE::OnGerberX2Checked ), NULL, this );
m_DXF_plotModeOpt->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_PLOT_BASE::OnChangeDXFPlotMode ), NULL, this );
m_PDFColorChoice->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_PLOT_BASE::onPDFColorChoice ), NULL, this );
m_buttonDRC->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PLOT_BASE::onRunDRC ), NULL, this );
m_sdbSizer1Apply->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PLOT_BASE::CreateDrillFile ), NULL, this );
m_sdbSizer1OK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PLOT_BASE::Plot ), NULL, this );
@ -474,6 +483,7 @@ DIALOG_PLOT_BASE::~DIALOG_PLOT_BASE()
m_boardSetup->Disconnect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( DIALOG_PLOT_BASE::onBoardSetup ), NULL, this );
m_useGerberX2Format->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_PLOT_BASE::OnGerberX2Checked ), NULL, this );
m_DXF_plotModeOpt->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_PLOT_BASE::OnChangeDXFPlotMode ), NULL, this );
m_PDFColorChoice->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_PLOT_BASE::onPDFColorChoice ), NULL, this );
m_buttonDRC->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PLOT_BASE::onRunDRC ), NULL, this );
m_sdbSizer1Apply->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PLOT_BASE::CreateDrillFile ), NULL, this );
m_sdbSizer1OK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_PLOT_BASE::Plot ), NULL, this );

View File

@ -3812,6 +3812,7 @@
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChoice">onPDFColorChoice</event>
</object>
</object>
<object class="gbsizeritem" expanded="true">
@ -4022,7 +4023,7 @@
<property name="border">5</property>
<property name="colspan">2</property>
<property name="column">0</property>
<property name="flag">wxBOTTOM|wxLEFT|wxRIGHT</property>
<property name="flag">wxLEFT|wxRIGHT</property>
<property name="row">4</property>
<property name="rowspan">1</property>
<object class="wxCheckBox" expanded="true">
@ -4086,6 +4087,137 @@
<property name="window_style"></property>
</object>
</object>
<object class="gbsizeritem" expanded="true">
<property name="border">5</property>
<property name="colspan">1</property>
<property name="column">0</property>
<property name="flag">wxALL</property>
<property name="row">5</property>
<property name="rowspan">1</property>
<object class="wxStaticText" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Background Color</property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_pdfBackgroundColorText</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
</object>
</object>
<object class="gbsizeritem" expanded="true">
<property name="border">5</property>
<property name="colspan">1</property>
<property name="column">1</property>
<property name="flag">wxALL</property>
<property name="row">5</property>
<property name="rowspan">1</property>
<object class="CustomControl" expanded="true">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer">0</property>
<property name="aui_name"></property>
<property name="aui_position">0</property>
<property name="aui_row">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="class">COLOR_SWATCH</property>
<property name="close_button">1</property>
<property name="construction"></property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="declaration"></property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="include"></property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_pdfBackgroundColorSwatch</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="settings"></property>
<property name="show">1</property>
<property name="size"></property>
<property name="subclass">COLOR_SWATCH; widgets/color_swatch.h; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
</object>
</object>
</object>

View File

@ -10,6 +10,7 @@
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
class COLOR_SWATCH;
class STD_BITMAP_BUTTON;
class WX_HTML_REPORT_PANEL;
@ -118,6 +119,8 @@ class DIALOG_PLOT_BASE : public DIALOG_SHIM
wxCheckBox* m_backFPPropertyPopups;
wxCheckBox* m_pdfMetadata;
wxCheckBox* m_pdfSingle;
wxStaticText* m_pdfBackgroundColorText;
COLOR_SWATCH* m_pdfBackgroundColorSwatch;
WX_HTML_REPORT_PANEL* m_messagesPanel;
wxBoxSizer* m_sizerButtons;
wxButton* m_buttonDRC;
@ -137,6 +140,7 @@ class DIALOG_PLOT_BASE : public DIALOG_SHIM
virtual void onBoardSetup( wxHyperlinkEvent& event ) { event.Skip(); }
virtual void OnGerberX2Checked( wxCommandEvent& event ) { event.Skip(); }
virtual void OnChangeDXFPlotMode( wxCommandEvent& event ) { event.Skip(); }
virtual void onPDFColorChoice( wxCommandEvent& event ) { event.Skip(); }
virtual void onRunDRC( wxCommandEvent& event ) { event.Skip(); }
virtual void CreateDrillFile( wxCommandEvent& event ) { event.Skip(); }
virtual void Plot( wxCommandEvent& event ) { event.Skip(); }

View File

@ -104,6 +104,7 @@ PCB_PLOT_PARAMS::PCB_PLOT_PARAMS()
m_PDFBackFPPropertyPopups = true;
m_PDFMetadata = true;
m_PDFSingle = false;
m_PDFBackgroundColor = COLOR4D::UNSPECIFIED;
// This parameter controls if the NPTH pads will be plotted or not
// it is a "local" parameter

View File

@ -184,11 +184,15 @@ public:
void SetDashedLineGapRatio( double aVal ) { m_dashedLineGapRatio = aVal; }
double GetDashedLineGapRatio() const { return m_dashedLineGapRatio; }
void SetPDFBackgroundColor( const COLOR4D& aColor ) { m_PDFBackgroundColor = aColor; }
COLOR4D GetPDFBackgroundColor() const { return m_PDFBackgroundColor; }
public:
bool m_PDFFrontFPPropertyPopups; ///< Generate PDF property popup menus for footprints
bool m_PDFBackFPPropertyPopups; ///< on front and/or back of board
bool m_PDFMetadata; ///< Generate PDF metadata for SUBJECT and AUTHOR
bool m_PDFSingle; ///< Generate a single PDF file for all layers
COLOR4D m_PDFBackgroundColor; ///< Background color to use if m_PDFUseBackgroundColor is true
private:
friend class PCB_PLOT_PARAMS_PARSER;

View File

@ -424,6 +424,7 @@ void PCB_PLOTTER::PlotJobToPlotOpts( PCB_PLOT_PARAMS& aOpts, JOB_EXPORT_PCB_PLOT
aOpts.m_PDFBackFPPropertyPopups = pdfJob->m_pdfBackFPPropertyPopups;
aOpts.m_PDFMetadata = pdfJob->m_pdfMetadata;
aOpts.m_PDFSingle = pdfJob->m_pdfSingle;
aOpts.m_PDFBackgroundColor = COLOR4D( pdfJob->m_pdfBackgroundColor );
}
if( aJob->m_plotFormat == JOB_EXPORT_PCB_PLOT::PLOT_FORMAT::POST )

View File

@ -1187,6 +1187,24 @@ static void FillNegativeKnockout( PLOTTER *aPlotter, const BOX2I &aBbbox )
}
static void plotPdfBackground( BOARD* aBoard, const PCB_PLOT_PARAMS* aPlotOpts, PLOTTER* aPlotter )
{
if( aPlotter->GetColorMode()
&& aPlotOpts->GetPDFBackgroundColor() != COLOR4D::UNSPECIFIED )
{
aPlotter->SetColor( aPlotOpts->GetPDFBackgroundColor() );
// Use page size selected in pcb to know the schematic bg area
const PAGE_INFO& actualPage = aBoard->GetPageSettings();
VECTOR2I end( actualPage.GetWidthIU( pcbIUScale.IU_PER_MILS ),
actualPage.GetHeightIU( pcbIUScale.IU_PER_MILS ) );
aPlotter->Rect( VECTOR2I( 0, 0 ), end, FILL_T::FILLED_SHAPE, 1.0 );
}
}
/**
* Open a new plotfile using the options (and especially the format) specified in the options
* and prepare the page for plotting.
@ -1309,6 +1327,9 @@ PLOTTER* StartPlotBoard( BOARD *aBoard, const PCB_PLOT_PARAMS *aPlotOpts, int aL
if( startPlotSuccess )
{
if( aPlotOpts->GetFormat() == PLOT_FORMAT::PDF )
plotPdfBackground( aBoard, aPlotOpts, plotter );
// Plot the frame reference if requested
if( aPlotOpts->GetPlotFrameRef() )
{
@ -1345,6 +1366,8 @@ void setupPlotterNewPDFPage( PLOTTER* aPlotter, BOARD* aBoard, PCB_PLOT_PARAMS*
const wxString& aSheetPath, const wxString& aPageNumber,
int aPageCount )
{
plotPdfBackground( aBoard, aPlotOpts, aPlotter );
// Plot the frame reference if requested
if( aPlotOpts->GetPlotFrameRef() )
{