Add cli export of symbols from kicad libraries

This commit is contained in:
Marek Roszko 2022-12-12 22:42:22 -05:00
parent 59a6d14242
commit f1f5fff072
14 changed files with 395 additions and 11 deletions

View File

@ -0,0 +1,49 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 Mark Roszko <mark.roszko@gmail.com>
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef JOB_SYM_EXPORT_SVG_H
#define JOB_SYM_EXPORT_SVG_H
#include <wx/string.h>
#include "job.h"
class JOB_SYM_EXPORT_SVG : public JOB
{
public:
JOB_SYM_EXPORT_SVG( bool aIsCli ) :
JOB( "symsvg", aIsCli ),
m_libraryPath(),
m_symbol(),
m_outputDirectory(),
m_blackAndWhite( false )
{
}
wxString m_libraryPath;
wxString m_symbol;
wxString m_outputDirectory;
wxString m_colorTheme;
bool m_blackAndWhite;
};
#endif

View File

@ -742,11 +742,11 @@ bool SVG_PLOTTER::StartPlot( const wxString& aPageNumber )
strftime( date_buf, 250, "%Y/%m/%d %H:%M:%S", localtime( &ltime ) ); strftime( date_buf, 250, "%Y/%m/%d %H:%M:%S", localtime( &ltime ) );
fprintf( m_outputFile, fprintf( m_outputFile,
"<title>SVG Picture created as %s date %s </title>\n", "<title>SVG Image created as %s date %s </title>\n",
TO_UTF8( XmlEsc( wxFileName( m_filename ).GetFullName() ) ), date_buf ); TO_UTF8( XmlEsc( wxFileName( m_filename ).GetFullName() ) ), date_buf );
// End of header // End of header
fprintf( m_outputFile, " <desc>Picture generated by %s </desc>\n", fprintf( m_outputFile, " <desc>Image generated by %s </desc>\n",
TO_UTF8( XmlEsc( m_creator ) ) ); TO_UTF8( XmlEsc( m_creator ) ) );
// output the pen and brush color (RVB values in hex) and opacity // output the pen and brush color (RVB values in hex) and opacity

View File

@ -183,6 +183,7 @@ const std::string JpegFileExtension( "jpg" );
const std::string TextFileExtension( "txt" ); const std::string TextFileExtension( "txt" );
const std::string MarkdownFileExtension( "md" ); const std::string MarkdownFileExtension( "md" );
const std::string CsvFileExtension( "csv" ); const std::string CsvFileExtension( "csv" );
const std::string XmlFileExtension( "xml" );
const wxString GerberFileExtensionsRegex( "(gbr|gko|pho|(g[tb][alops])|(gm?\\d\\d*)|(gp[tb]))" ); const wxString GerberFileExtensionsRegex( "(gbr|gko|pho|(g[tb][alops])|(gm?\\d\\d*)|(gp[tb]))" );

View File

@ -24,17 +24,22 @@
#include <jobs/job_export_sch_netlist.h> #include <jobs/job_export_sch_netlist.h>
#include <jobs/job_export_sch_pdf.h> #include <jobs/job_export_sch_pdf.h>
#include <jobs/job_export_sch_svg.h> #include <jobs/job_export_sch_svg.h>
#include <jobs/job_sym_export_svg.h>
#include <jobs/job_sym_upgrade.h> #include <jobs/job_sym_upgrade.h>
#include <pgm_base.h> #include <pgm_base.h>
#include <sch_plotter.h> #include <sch_plotter.h>
#include <schematic.h> #include <schematic.h>
#include <wx/crt.h> #include <wx/crt.h>
#include <wx/dir.h>
#include <wx/file.h>
#include <memory> #include <memory>
#include <connection_graph.h> #include <connection_graph.h>
#include "eeschema_helpers.h" #include "eeschema_helpers.h"
#include <sch_painter.h> #include <sch_painter.h>
#include <locale_io.h>
#include <erc.h> #include <erc.h>
#include <wildcards_and_files_ext.h> #include <wildcards_and_files_ext.h>
#include <plotters/plotters_pslike.h>
#include <settings/settings_manager.h> #include <settings/settings_manager.h>
@ -62,7 +67,9 @@ EESCHEMA_JOBS_HANDLER::EESCHEMA_JOBS_HANDLER()
Register( "svg", Register( "svg",
std::bind( &EESCHEMA_JOBS_HANDLER::JobExportSvg, this, std::placeholders::_1 ) ); std::bind( &EESCHEMA_JOBS_HANDLER::JobExportSvg, this, std::placeholders::_1 ) );
Register( "symupgrade", Register( "symupgrade",
std::bind( &EESCHEMA_JOBS_HANDLER::JobExportSymLibUpgrade, this, std::placeholders::_1 ) ); std::bind( &EESCHEMA_JOBS_HANDLER::JobSymUpgrade, this, std::placeholders::_1 ) );
Register( "symsvg",
std::bind( &EESCHEMA_JOBS_HANDLER::JobSymExportSvg, this, std::placeholders::_1 ) );
} }
@ -302,13 +309,11 @@ int EESCHEMA_JOBS_HANDLER::JobExportPythonBom( JOB* aJob )
std::unique_ptr<NETLIST_EXPORTER_XML> xmlNetlist = std::unique_ptr<NETLIST_EXPORTER_XML> xmlNetlist =
std::make_unique<NETLIST_EXPORTER_XML>( sch ); std::make_unique<NETLIST_EXPORTER_XML>( sch );
wxString fileExt = wxS( "xml" );
if( aNetJob->m_outputFile.IsEmpty() ) if( aNetJob->m_outputFile.IsEmpty() )
{ {
wxFileName fn = sch->GetFileName(); wxFileName fn = sch->GetFileName();
fn.SetName( fn.GetName() + "-bom" ); fn.SetName( fn.GetName() + "-bom" );
fn.SetExt( fileExt ); fn.SetExt( XmlFileExtension );
aNetJob->m_outputFile = fn.GetFullName(); aNetJob->m_outputFile = fn.GetFullName();
} }
@ -324,7 +329,158 @@ int EESCHEMA_JOBS_HANDLER::JobExportPythonBom( JOB* aJob )
} }
int EESCHEMA_JOBS_HANDLER::JobExportSymLibUpgrade( JOB* aJob ) int EESCHEMA_JOBS_HANDLER::doSymExportSvg( JOB_SYM_EXPORT_SVG* aSvgJob,
KIGFX::SCH_RENDER_SETTINGS* aRenderSettings,
LIB_SYMBOL* symbol )
{
wxASSERT( symbol != nullptr );
if( symbol == nullptr )
return CLI::EXIT_CODES::ERR_UNKNOWN;
// iterate from unit 1, unit 0 would be "all units" which we don't want
for( int unit = 1; unit < symbol->GetUnitCount() + 1; unit++ )
{
int convert = 0;
wxFileName fn;
fn.SetPath( aSvgJob->m_outputDirectory );
fn.SetExt( SVGFileExtension );
//simplify the name if its single unit
if( symbol->IsMulti() )
{
fn.SetName( wxString::Format( "%s_%d", symbol->GetName().Lower(), unit ) );
wxPrintf( _( "Plotting symbol '%s' unit %d to '%s'\n" ), symbol->GetName(), unit,
fn.GetFullPath() );
}
else
{
fn.SetName( symbol->GetName().Lower() );
wxPrintf( _( "Plotting symbol '%s' to '%s'\n" ), symbol->GetName(), fn.GetFullPath() );
}
// Get the symbol bounding box to fit the plot page to it
BOX2I symbolBB = symbol->Flatten()->GetUnitBoundingBox( unit, convert );
PAGE_INFO pageInfo( PAGE_INFO::Custom );
pageInfo.SetHeightMils( schIUScale.IUToMils( symbolBB.GetHeight() * 1.2 ) );
pageInfo.SetWidthMils( schIUScale.IUToMils( symbolBB.GetWidth() * 1.2 ) );
SVG_PLOTTER* plotter = new SVG_PLOTTER();
plotter->SetRenderSettings( aRenderSettings );
plotter->SetPageSettings( pageInfo );
plotter->SetColorMode( !aSvgJob->m_blackAndWhite );
wxPoint plot_offset;
const double scale = 1.0;
// Currently, plot units are in decimil
plotter->SetViewport( plot_offset, schIUScale.IU_PER_MILS / 10, scale, false );
plotter->SetCreator( wxT( "Eeschema-SVG" ) );
if( !plotter->OpenFile( fn.GetFullPath() ) )
{
wxFprintf( stderr, _( "Unable to open destination '%s'" ), fn.GetFullPath() );
delete plotter;
return CLI::EXIT_CODES::ERR_INVALID_INPUT_FILE;
}
LOCALE_IO toggle;
plotter->StartPlot( wxT( "1" ) );
if( symbol )
{
constexpr bool background = true;
TRANSFORM temp; // Uses default transform
VECTOR2I plotPos;
plotPos.x = pageInfo.GetWidthIU( schIUScale.IU_PER_MILS ) / 2;
plotPos.y = pageInfo.GetHeightIU( schIUScale.IU_PER_MILS ) / 2;
symbol->Plot( plotter, unit, convert, background, plotPos, temp, false );
// Plot lib fields, not plotted by m_symbol->Plot():
symbol->PlotLibFields( plotter, unit, convert, background, plotPos, temp, false );
symbol->Plot( plotter, unit, convert, !background, plotPos, temp, false );
// Plot lib fields, not plotted by m_symbol->Plot():
symbol->PlotLibFields( plotter, unit, convert, !background, plotPos, temp, false );
}
plotter->EndPlot();
delete plotter;
}
return CLI::EXIT_CODES::OK;
}
int EESCHEMA_JOBS_HANDLER::JobSymExportSvg( JOB* aJob )
{
JOB_SYM_EXPORT_SVG* svgJob = dynamic_cast<JOB_SYM_EXPORT_SVG*>( aJob );
SCH_SEXPR_PLUGIN_CACHE schLibrary( svgJob->m_libraryPath );
try
{
schLibrary.Load();
}
catch( ... )
{
wxFprintf( stderr, _( "Unable to load library\n" ) );
return CLI::EXIT_CODES::ERR_UNKNOWN;
}
LIB_SYMBOL* symbol = nullptr;
if( !svgJob->m_symbol.IsEmpty() )
{
// See if the selected symbol exists
symbol = schLibrary.GetSymbol( svgJob->m_symbol );
if( !symbol )
{
wxFprintf( stderr, _( "There is no symbol selected to save." ) );
return CLI::EXIT_CODES::ERR_ARGS;
}
}
if( !svgJob->m_outputDirectory.IsEmpty() && !wxDir::Exists( svgJob->m_outputDirectory ) )
{
wxFileName::Mkdir( svgJob->m_outputDirectory );
}
KIGFX::SCH_RENDER_SETTINGS renderSettings;
COLOR_SETTINGS* cs = Pgm().GetSettingsManager().GetColorSettings( svgJob->m_colorTheme );
renderSettings.LoadColors( cs );
renderSettings.SetDefaultPenWidth( DEFAULT_LINE_WIDTH_MILS * schIUScale.IU_PER_MILS );
int exitCode = CLI::EXIT_CODES::OK;
if( symbol )
{
exitCode = doSymExportSvg( svgJob, &renderSettings, symbol );
}
else
{
// Just plot all the symbols we can
const LIB_SYMBOL_MAP& libSymMap = schLibrary.GetSymbolMap();
for( const std::pair<const wxString, LIB_SYMBOL*>& entry : libSymMap )
{
exitCode = doSymExportSvg( svgJob, &renderSettings, entry.second );
if( exitCode != CLI::EXIT_CODES::OK )
break;
}
}
return exitCode;
}
int EESCHEMA_JOBS_HANDLER::JobSymUpgrade( JOB* aJob )
{ {
JOB_SYM_UPGRADE* upgradeJob = dynamic_cast<JOB_SYM_UPGRADE*>( aJob ); JOB_SYM_UPGRADE* upgradeJob = dynamic_cast<JOB_SYM_UPGRADE*>( aJob );

View File

@ -31,6 +31,8 @@ class SCH_RENDER_SETTINGS;
}; };
class SCHEMATIC; class SCHEMATIC;
class JOB_SYM_EXPORT_SVG;
class LIB_SYMBOL;
/** /**
* Handles eeschema job dispatches * Handles eeschema job dispatches
@ -43,7 +45,10 @@ public:
int JobExportNetlist( JOB* aJob ); int JobExportNetlist( JOB* aJob );
int JobExportPdf( JOB* aJob ); int JobExportPdf( JOB* aJob );
int JobExportSvg( JOB* aJob ); int JobExportSvg( JOB* aJob );
int JobExportSymLibUpgrade( JOB* aJob ); int JobSymUpgrade( JOB* aJob );
int JobSymExportSvg( JOB* aJob );
int doSymExportSvg( JOB_SYM_EXPORT_SVG* aSvgJob, KIGFX::SCH_RENDER_SETTINGS* aRenderSettings, LIB_SYMBOL* symbol );
/** /**
* Configures the SCH_RENDER_SETTINGS object with the correct data to be used with plotting * Configures the SCH_RENDER_SETTINGS object with the correct data to be used with plotting

View File

@ -173,3 +173,16 @@ void SCH_LIB_PLUGIN_CACHE::AddSymbol( const LIB_SYMBOL* aSymbol )
m_isModified = true; m_isModified = true;
IncrementModifyHash(); IncrementModifyHash();
} }
LIB_SYMBOL* SCH_LIB_PLUGIN_CACHE::GetSymbol( const wxString& aName )
{
LIB_SYMBOL_MAP::iterator it = m_symbols.find( aName );
if( it != m_symbols.end() )
{
return it->second;
}
return nullptr;
}

View File

@ -68,6 +68,8 @@ public:
virtual void DeleteSymbol( const wxString& aName ) = 0; virtual void DeleteSymbol( const wxString& aName ) = 0;
virtual LIB_SYMBOL* GetSymbol( const wxString& aName );
// If m_libFileName is a symlink follow it to the real source file // If m_libFileName is a symlink follow it to the real source file
wxFileName GetRealFile() const; wxFileName GetRealFile() const;
@ -85,6 +87,8 @@ public:
wxString GetFileName() const { return m_libFileName.GetFullPath(); } wxString GetFileName() const { return m_libFileName.GetFullPath(); }
const LIB_SYMBOL_MAP& GetSymbolMap() const { return m_symbols; }
protected: protected:
LIB_SYMBOL* removeSymbol( LIB_SYMBOL* aAlias ); LIB_SYMBOL* removeSymbol( LIB_SYMBOL* aAlias );

View File

@ -40,7 +40,7 @@ void SYMBOL_EDIT_FRAME::SVGPlotSymbol( const wxString& aFullFileName )
plotter->SetPageSettings( pageInfo ); plotter->SetPageSettings( pageInfo );
plotter->SetColorMode( true ); plotter->SetColorMode( true );
wxPoint plot_offset; VECTOR2I plot_offset;
const double scale = 1.0; const double scale = 1.0;
// Currently, plot units are in decimil // Currently, plot units are in decimil

View File

@ -169,6 +169,7 @@ extern const std::string JpegFileExtension;
extern const std::string TextFileExtension; extern const std::string TextFileExtension;
extern const std::string MarkdownFileExtension; extern const std::string MarkdownFileExtension;
extern const std::string CsvFileExtension; extern const std::string CsvFileExtension;
extern const std::string XmlFileExtension;
extern const wxString GerberFileExtensionsRegex; extern const wxString GerberFileExtensionsRegex;

View File

@ -31,6 +31,7 @@ set( KICAD_SRCS
cli/command_export_sch_netlist.cpp cli/command_export_sch_netlist.cpp
cli/command_export_sch_pdf.cpp cli/command_export_sch_pdf.cpp
cli/command_export_sch_svg.cpp cli/command_export_sch_svg.cpp
cli/command_sym_export_svg.cpp
cli/command_sym_upgrade.cpp cli/command_sym_upgrade.cpp
dialogs/dialog_template_selector_base.cpp dialogs/dialog_template_selector_base.cpp
dialogs/dialog_template_selector.cpp dialogs/dialog_template_selector.cpp

View File

@ -0,0 +1,34 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 Mark Roszko <mark.roszko@gmail.com>
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef COMMAND_SYM_EXPORT_H
#define COMMAND_SYM_EXPORT_H
#include "command.h"
namespace CLI
{
struct SYM_EXPORT_COMMAND : public COMMAND
{
SYM_EXPORT_COMMAND() : COMMAND( "export" ) {}
};
}
#endif

View File

@ -0,0 +1,71 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 Mark Roszko <mark.roszko@gmail.com>
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "command_sym_export_svg.h"
#include <cli/exit_codes.h>
#include "jobs/job_sym_export_svg.h"
#include <kiface_base.h>
#include <layer_ids.h>
#include <wx/crt.h>
#include <macros.h>
#include <wx/tokenzr.h>
#define ARG_NO_BACKGROUND_COLOR "--no-background-color"
#define ARG_SYMBOL "--symbol"
CLI::SYM_EXPORT_SVG_COMMAND::SYM_EXPORT_SVG_COMMAND() : EXPORT_PCB_BASE_COMMAND( "svg" )
{
m_argParser.add_argument( "-t", ARG_THEME )
.default_value( std::string() )
.help( UTF8STDSTR( _( "Color theme to use (will default to pcbnew settings)" ) ) );
m_argParser.add_argument( "-s", ARG_SYMBOL )
.default_value( std::string() )
.help( UTF8STDSTR( _( "Specific symbol to export within the library" ) ) );
m_argParser.add_argument( ARG_BLACKANDWHITE )
.help( UTF8STDSTR( _( "Black and white only" ) ) )
.implicit_value( true )
.default_value( false );
}
int CLI::SYM_EXPORT_SVG_COMMAND::Perform( KIWAY& aKiway )
{
std::unique_ptr<JOB_SYM_EXPORT_SVG> svgJob = std::make_unique<JOB_SYM_EXPORT_SVG>( true );
svgJob->m_libraryPath = FROM_UTF8( m_argParser.get<std::string>( ARG_INPUT ).c_str() );
svgJob->m_outputDirectory = FROM_UTF8( m_argParser.get<std::string>( ARG_OUTPUT ).c_str() );
svgJob->m_blackAndWhite = m_argParser.get<bool>( ARG_BLACKANDWHITE );
svgJob->m_symbol = FROM_UTF8( m_argParser.get<std::string>( ARG_SYMBOL ).c_str() );
if( !wxFile::Exists( svgJob->m_libraryPath ) )
{
wxFprintf( stderr, _( "Symbol file does not exist or is not accessible\n" ) );
return EXIT_CODES::ERR_INVALID_INPUT_FILE;
}
svgJob->m_colorTheme = FROM_UTF8( m_argParser.get<std::string>( ARG_THEME ).c_str() );
int exitCode = aKiway.ProcessJob( KIWAY::FACE_SCH, svgJob.get() );
return exitCode;
}

View File

@ -0,0 +1,37 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 Mark Roszko <mark.roszko@gmail.com>
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef COMMAND_SYM_EXPORT_SVG_H
#define COMMAND_SYM_EXPORT_SVG_H
#include "command_export_pcb_base.h"
namespace CLI
{
class SYM_EXPORT_SVG_COMMAND : public EXPORT_PCB_BASE_COMMAND
{
public:
SYM_EXPORT_SVG_COMMAND();
int Perform( KIWAY& aKiway ) override;
};
} // namespace CLI
#endif

View File

@ -66,6 +66,8 @@
#include "cli/command_sch.h" #include "cli/command_sch.h"
#include "cli/command_sch_export.h" #include "cli/command_sch_export.h"
#include "cli/command_sym.h" #include "cli/command_sym.h"
#include "cli/command_sym_export.h"
#include "cli/command_sym_export_svg.h"
#include "cli/command_sym_upgrade.h" #include "cli/command_sym_upgrade.h"
#include "cli/exit_codes.h" #include "cli/exit_codes.h"
#include "cli/cli_names.h" #include "cli/cli_names.h"
@ -134,6 +136,8 @@ static CLI::EXPORT_SCH_SVG_COMMAND exportSchSvgCmd{};
static CLI::FP_COMMAND fpCmd{}; static CLI::FP_COMMAND fpCmd{};
static CLI::FP_UPGRADE_COMMAND fpUpgradeCmd{}; static CLI::FP_UPGRADE_COMMAND fpUpgradeCmd{};
static CLI::SYM_COMMAND symCmd{}; static CLI::SYM_COMMAND symCmd{};
static CLI::SYM_EXPORT_COMMAND symExportCmd{};
static CLI::SYM_EXPORT_SVG_COMMAND symExportSvgCmd{};
static CLI::SYM_UPGRADE_COMMAND symUpgradeCmd{}; static CLI::SYM_UPGRADE_COMMAND symUpgradeCmd{};
static std::vector<COMMAND_ENTRY> commandStack = { static std::vector<COMMAND_ENTRY> commandStack = {
@ -148,7 +152,8 @@ static std::vector<COMMAND_ENTRY> commandStack = {
{ {
&pcbCmd, &pcbCmd,
{ {
{ &exportPcbCmd, {
&exportPcbCmd,
{ {
&exportPcbDrillCmd, &exportPcbDrillCmd,
&exportPcbDxfCmd, &exportPcbDxfCmd,
@ -165,7 +170,8 @@ static std::vector<COMMAND_ENTRY> commandStack = {
{ {
&schCmd, &schCmd,
{ {
{ &exportSchCmd, {
&exportSchCmd,
{ {
&exportSchNetlistCmd, &exportSchNetlistCmd,
&exportSchPdfCmd, &exportSchPdfCmd,
@ -178,6 +184,12 @@ static std::vector<COMMAND_ENTRY> commandStack = {
{ {
&symCmd, &symCmd,
{ {
{
&symExportCmd,
{
&symExportSvgCmd
}
},
{ {
&symUpgradeCmd &symUpgradeCmd
} }