KiCad9 -- "Plot References/Values" option

I could not load your jobset, it did open but the option to run it or something was not present, so I create a new one that would generate Gerber files with the settings that you had selected:


{
  "jobs": [
    {
      "description": "",
      "id": "306ca924-6704-4fcb-a1ec-a3333cadf0af",
      "settings": {
        "black_and_white": true,
        "create_gerber_job_file": false,
        "crossout_dnp_footprints_on_fab_layers": true,
        "description": "",
        "disable_aperture_macros": false,
        "drawing_sheet": "",
        "drill_shape": "full",
        "hide_dnp_footprints_on_fab_layers": false,
        "include_netlist_attributes": true,
        "layers": [
          "In30.Cu",
          "In29.Cu",
          "In28.Cu",
          "In27.Cu",
          "In26.Cu",
          "In25.Cu",
          "In24.Cu",
          "In23.Cu",
          "In22.Cu",
          "In21.Cu",
          "In20.Cu",
          "In19.Cu",
          "In18.Cu",
          "In17.Cu",
          "In16.Cu",
          "In15.Cu",
          "In14.Cu",
          "In13.Cu",
          "In12.Cu",
          "In11.Cu",
          "In10.Cu",
          "In9.Cu",
          "In8.Cu",
          "In7.Cu",
          "In6.Cu",
          "In5.Cu",
          "In4.Cu",
          "In3.Cu",
          "In2.Cu",
          "In1.Cu",
          "F.Fab",
          "Edge.Cuts"
        ],
        "layers_to_include_on_all_layers": [],
        "mirror": false,
        "negative": false,
        "output_filename": "",
        "plot_drawing_sheet": false,
        "plot_footprint_values": true,
        "plot_pad_numbers": false,
        "plot_ref_des": true,
        "precision": 5,
        "sketch_dnp_footprints_on_fab_layers": true,
        "sketch_pads_on_fab_layers": true,
        "subtract_solder_mask_from_silk": false,
        "use_drill_origin": false,
        "use_protel_file_extension": true,
        "use_x2_format": true
      },
      "type": "pcb_export_gerbers"
    }
  ],
  "meta": {
    "version": 1
  },
  "outputs": [
    {
      "description": "testFolder",
      "id": "96f755de-66a3-4a5c-8b00-1fa20d9b81de",
      "only": [],
      "settings": {
        "output_path": "test2_Tiles_Value"
      },
      "type": "folder"
    }
  ]
}

The content of the folder has only 2 files and the gerbers look ok.

However I am not in the release build of v9.0.1 but in a test build from some days ago.

In your test case, on which layer do you have your Values and RefDes’s ? Are they Enabled / Visible in your design view?

@der.ule I’ve just upgraded my KiCad to recent V9 testing build, and run your Jobset file. It still does not override “plot_footprint_values” and “plot_ref_des” settings of my design.
So I only get what is set in Footprint properties, and no overrides defined in the Jobset are working.

Well, there is something going on there but I could not find out what was it. What worked yesterday, was not working today anymore, didn’t matter what I changed, the result was as you said, both values being plotted in F.Fab, I try to revert my settings as I had them yesterday and created a new PDF jobset, the same result.

After a little why and trying many permutations of settings (no edge.cuts layer, with F.Cu, B.Cu, F.Fab and B.Fab, etc.) I restarted KiCAD, just closed everything and open the project again. This time it worked, as did the previous jobsets that where not working before. :person_shrugging:

As you can see I loaded the F.Fab with Values and DefRefs (different colors, two different jobsets), my fotprint looks like this, no field is invisible.

Gerbv outputs:

Footprint in editor

There seems to be a demand for this feature. I can add it to Board2Pdf v2.0.0.

v2.0.0 uses the new API, and since the new API requires a running instance of KiCad I cannot use the API to hide/show texts. Otherwise the function wouldn’t work with Board2Pdf CLI.

I wrote a script which can force hide/show footprint references and values, by parsing the board file. I’ll add it in Board2Pdf soon. It won’t make any changes to the actual board file, just to a temporary copy of it.

Here’s the script I wrote, if anyone is interested in parsing KiCad files using Python.

import sexpdata

def process_footprint(footprint: list, force_fp_value: str, force_fp_reference: str) -> list:
    """
    Processes a single footprint s-expression to change the 'hide' property of 'Value' to 'no'.

    Args:
        footprint: A list representing the s-expression of a footprint.
        force_fp_value: Set to 'no', 'hide' or 'show' to specify if footprint values should be forced hidden or forced shown
        force_fp_reference: Set to 'no', 'hide' or 'show' to specify if footprint references should be forced hidden or forced shown

    Returns:
        The modified footprint s-expression.
    """
    for i in range(1, len(footprint)):
        """ Process footprint Value to set it to hidden or shown """
        if force_fp_value != 'no':
            if isinstance(footprint[i], list) and footprint[i][0] == sexpdata.Symbol('property') and footprint[i][1] == 'Value':
                found_value = False
                for j in range(len(footprint[i])):
                    if isinstance(footprint[i][j], list) and footprint[i][j][0] == sexpdata.Symbol('hide'):
                        found_value = True
                        if force_fp_value == 'show':
                            footprint[i][j][1] = sexpdata.Symbol('no')
                        else:
                            footprint[i][j][1] = sexpdata.Symbol('yes')
                        break  # Found and modified 'hide', move to the next node
                if not found_value:
                    if force_fp_value == 'show':
                        footprint[i].append([sexpdata.Symbol('hide'), sexpdata.Symbol('no')])
                    else:
                        footprint[i].append([sexpdata.Symbol('hide'), sexpdata.Symbol('yes')])

        """ Process footprint Reference to set it to hidden or shown """
        if force_fp_reference != 'no':
            if isinstance(footprint[i], list) and footprint[i][0] == sexpdata.Symbol('property') and footprint[i][1] == 'Reference':
                found_value = False
                for j in range(len(footprint[i])):
                    if isinstance(footprint[i][j], list) and footprint[i][j][0] == sexpdata.Symbol('hide'):
                        found_value = True
                        if force_fp_reference == 'show':
                            footprint[i][j][1] = sexpdata.Symbol('no')
                        else:
                            footprint[i][j][1] = sexpdata.Symbol('yes')
                        break  # Found and modified 'hide', move to the next node
                if not found_value:
                    if force_fp_reference == 'show':
                        footprint[i].append([sexpdata.Symbol('hide'), sexpdata.Symbol('no')])
                    else:
                        footprint[i].append([sexpdata.Symbol('hide'), sexpdata.Symbol('yes')])
    return footprint

def process_kicad_pcb(data: list, force_fp_value: str='no', force_fp_reference: str='no') -> list:
    """
    Processes the entire KiCad PCB s-expression to modify all footprint objects.

    Args:
        data: A list representing the entire KiCad PCB s-expression.
        force_fp_value: Set to 'no', 'hide' or 'show' to specify if footprint values should be forced hidden or forced shown
        force_fp_reference: Set to 'no', 'hide' or 'show' to specify if footprint references should be forced hidden or forced shown

    Returns:
        The modified KiCad PCB s-expression.
    """
    for i in range(len(data)):
        if isinstance(data[i], list) and data[i][0] == sexpdata.Symbol('footprint'):
            data[i] = process_footprint(data[i], force_fp_value, force_fp_reference)
    return data

def main():
    input_filename = 'input.kicad_pcb'
    output_filename = 'output.kicad_pcb'

    force_fp_value = 'show'
    force_fp_reference = 'hide'

    try:
        with open(input_filename, 'r') as infile:
            s_expression_string = infile.read()
            data = sexpdata.loads(s_expression_string)
    except FileNotFoundError:
        print(f"Error: Input file '{input_filename}' not found.")
        return
    except sexpdata.ParseError as e:
        print(f"Error parsing '{input_filename}': {e}")
        return

    modified_data = process_kicad_pcb(data, force_fp_value, force_fp_reference)

    try:
        with open(output_filename, 'w') as outfile:
            sexpdata.dump(modified_data, outfile, pretty_print=True, indent=2)
        print(f"Successfully processed '{input_filename}' and wrote to '{output_filename}'.")
    except IOError:
        print(f"Error: Could not write to output file '{output_filename}'.")

if __name__ == "__main__":
    main()

This still works, but my guess is that part of the problem people are having is that the “Force plotting of invisible values / refs” is gone.

As long as all values and references are visible, the settings in the jobset file still works.

Plot window from 8.0.9:

Plot window in latest 9.0.1 nightly:

Using Values and Reference Designators on different (logical-) layers is “normal”.
One layer may be attached to (fabricate) silkscreen and the other not. Sometimes boards are so compact with closely spaced SMT parts there is no room for any silkscreen, or it may be too small to be printable or legible. In that case Reference designators may be on a document layer for PDF output.
I normally do not include Values on silkscreen, these only go to the pick-and-place X-Y file and BOM.

Moreover, a value should also have different (logical-) layers that could be exported to BOM, like basic specifications for Spec Control drawings, or Source Control, with specific vendor, partnumber and hyperlink. Spec Control could be voltage rating, power rating, automotive rating, % tolerance, dielectric material, temp rating etc needed to select a suitable part without a specific partnumber.
Creating a BOM for a board with 200 different parts will take serious time, so this “automation” would help.