Plot pdf files from python with pre-defined colors

I just tested plotting pdf files in color using the SWIG API, I’ve never tried that before.

This code plots the layer in the user defined color:

plot_controller = pcbnew.PLOT_CONTROLLER(board)
plot_controller.SetColorMode(True)
plot_options = plot_controller.GetPlotOptions()
sm = pcbnew.GetSettingsManager()
cs = sm.GetColorSettings()
plot_options.SetColorSettings(cs)

Is there a way to define the colors that shall be used from python?

sm.GetColorSettings() returns a pointer, and plot_options.SetColorSettings() expects a pointer, so I don’t think that it’s possible for me to change the color in between these two?

The only way that I can think of is to add a new color template from a file using sm.AddNewColorSettings(filename) and then fetch its settings using sm.GetColorSettings(“filename”).

Is there a better way than to add a new template using AddNewColorSettings()?

Bonus question:
How do I list the available templates?
test_list = sm.GetColorSettingsList()
print(str(test_list))

Gives me this output, which I’m not sure what to do with:
<Swig Object of type 'std::vector< COLOR_SETTINGS *,std::allocator< COLOR_SETTINGS * > > *' at 0x00000220050FC450>

I did some tests. It seems like its not possible to specify a path in AddNewColorSettings(), just a filename. And it seems like I have to run sm.ReloadColorSettings() after this command.

It works if I place the template file in C:\Users\{username}\AppData\Roaming\kicad\8.0\colors, but it works just as well with only ReloadColorSettings(). Not sure if AddNewColorSettings() looks for the specified filename in any other places. If it only looks in this path and requires ReloadColorSettings() to be executed afterwards, then I don’t really see the point of running it at all. Probably something I’m missing.

Edit: I just realized that I probably misunderstood AddNewColorSettings(). It’s probably used to add a new empty color settings… :thinking:

Well, it works if I place file named “board2pdf.json” in the path returned by sm.GetColorSettingsPath() and then run these commands:

sm = pcbnew.GetSettingsManager()
sm.ReloadColorSettings()
cs = sm.GetColorSettings(“board2pdf”)
plot_options.SetColorSettings(cs)

And it works fine if I change the colors in the file and run the script again.

But if there’s a way to do this without creating a file I’d love to know about it! :slight_smile:

I did some more brain-thinking and I guess that since there is a SaveColorSettings() method, it should be possible to somehow change the settings from python? But I cannot find any functions to change the color settings, and I don’t understand how to work with these variable types.

def GetColorSettings (self, *args)
def GetColorSettingsList (self)
def SaveColorSettings (self, *args)
def AddNewColorSettings (self, aFilename)
def GetMigratedColorSettings (self)

cs = sm.GetColorSettings(“board2pdf”)
print(cs)
<Swig Object of type ‘COLOR_SETTINGS *’ at 0x00000140ADA2A310>

template_list = sm.GetColorSettingsList()
print(template_list)
<Swig Object of type ‘std::vector< COLOR_SETTINGS *,std::allocator< COLOR_SETTINGS * > > *’ at 0x00000140B4EAA670>

Sorry for rambling in three posts in a row, pushing this post to the top.

How do I work with the objects returned by these two commands?

Sadly, you can’t. When you see a pointer like that or vector<something> it means those classes (or vector template) are not mapped in swig interface and you can’t access any of the fields or methods from python.
You can request these to be added to swig on gitlab but unless they were previously accessible and aren’t anymore because of a regression, chances of them being added are slim because new API is on the way.

Thank you @qu1ck!

Since the SWIG API is depricated, I rather work around it’s flaws than to request things to be added.

No problem, I’ll solve this by generating a json file an placing it at sm.GetColorSettingsPath(). Feels a bit hacky, but if that’s the only way then I’ll go for that solution.

I’m looking forward to the new API! Will start looking at it in the beginning of next year, but I’ll probably need a few examples to build upon and I haven’t found any examples yet. Do you know if there are any?

There are no examples as the new api is not ready for use yet. But you can expect InteractiveHtmlBom to be migrated as soon as possible.

1 Like

Great! That will be a perfect example!

In my plugin, Board2Pdf, I’ve added the ability to use the KiCad API to color the pdf files. It works great when I run the plugin from KiCad, but when I run it from outside KiCad it doesn’t work.

First I’m fetching the path to where the color-template-json-file shall be stored using these commands:

sm = pcbnew.GetSettingsManager()
template_file_path = os.path.join(sm.GetColorSettingsPath(), “board2pdf.json”)

After generating a color-template-json-file and storing it, I’m running these commands to tell KiCad to use the newly created template:

plot_controller.SetColorMode(True)
sm.ReloadColorSettings()
cs = sm.GetColorSettings(“board2pdf”)
plot_options.SetColorSettings(cs)
plot_options.SetBlackAndWhite(False)

This works fine from within KiCad, But not if I run the CLI of Board2Pdf using this command:

"C:\Program Files\KiCad\8.0\bin\python.exe" "C:\Users\denne\Documents\KiCad\8.0\3rdparty\plugins\com_gitlab_dennevi_Board2Pdf\board2pdf-cli.py" LVDS-Gender-Bender-A.kicad_pcb

Then I get this error message:
image

The line that causes this error is

sm.ReloadColorSettings()

Does anyone know of a way to solve this?

I tried replacing sm.ReloadColorSettings() with these lines, but it didn’t reload the color settings. :pensive:

import importlib
importlib.reload(pcbnew)
importlib.reload(sys.modules[‘pcbnew’])
importlib.reload(sys.modules[‘_pcbnew’])
sm = pcbnew.GetSettingsManager()

Many features of KiCad are not designed to work in a standalone manner, and this is just one of them. I don’t think you’ll find a fix in Python. You’d need to open an issue requesting a change in the KiCad code to make it possible to change color settings like this from Python.

Thank you @craftyjon!

Since the new API is on its way, I much rather see you developers spending time on that. I can live with not having this ability in standalone mode.

I’ll stop wasting time on trying to get this to work. :slight_smile: