Skip to content

Commit 6063d50

Browse files
Funkenjaegerqu1ck
authored andcommitted
Handle font_data in genericjson parser
1 parent 6567e9a commit 6063d50

File tree

6 files changed

+110
-13
lines changed

6 files changed

+110
-13
lines changed

InteractiveHtmlBom/core/config.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ class Config:
3737
html_config_fields = [
3838
'dark_mode', 'show_pads', 'show_fabrication', 'show_silkscreen',
3939
'highlight_pin1', 'redraw_on_drag', 'board_rotation', 'checkboxes',
40-
'bom_view', 'layer_view', 'offset_back_rotation'
40+
'bom_view', 'layer_view', 'offset_back_rotation',
41+
'kicad_text_formatting'
4142
]
4243
default_show_group_fields = ["Value", "Footprint"]
4344

@@ -67,6 +68,7 @@ class Config:
6768
blacklist_empty_val = False
6869
include_tracks = False
6970
include_nets = False
71+
kicad_text_formatting = True
7072

7173
# Extra fields section
7274
extra_data_file = None

InteractiveHtmlBom/ecad/common.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,29 @@ def add_polygon():
111111
for point in polygon:
112112
bbox.add_point(point[0], point[1])
113113

114+
def add_arc():
115+
if 'svgpath' in drawing:
116+
add_svgpath()
117+
else:
118+
width = drawing.get('width', 0)
119+
xc, yc = drawing['start'][:2]
120+
a1 = drawing['startangle']
121+
a2 = drawing['endangle']
122+
r = drawing['radius']
123+
x1 = xc + math.cos(math.radians(a1))
124+
y1 = xc + math.sin(math.radians(a1))
125+
x2 = xc + math.cos(math.radians(a2))
126+
y2 = xc + math.sin(math.radians(a2))
127+
da = a2 - a1 if a2 > a1 else a2 + 360 - a1
128+
la = 1 if da > 180 else 0
129+
svgpath = f'M {x1} {y1} A {r} {r} 0 {la} 1 {x2} {y2}'
130+
bbox.add_svgpath(svgpath, width, self.logger)
131+
114132
{
115133
'segment': add_segment,
116134
'rect': add_segment, # bbox of a rect and segment are the same
117135
'circle': add_circle,
118-
'arc': add_svgpath,
136+
'arc': add_arc,
119137
'polygon': add_polygon,
120138
'text': lambda: None, # text is not really needed for bounding box
121139
}.get(drawing['type'])()

InteractiveHtmlBom/ecad/genericjson.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
from jsonschema import validate, ValidationError
55

66
from .common import EcadParser, Component, BoundingBox
7+
from ..core.fontparser import FontParser
8+
from ..errors import ParsingException
79

810

911
class GenericJsonParser(EcadParser):
@@ -65,6 +67,45 @@ def _verify(self, pcb):
6567

6668
return True
6769

70+
@staticmethod
71+
def _texts(pcbdata):
72+
for layer in pcbdata['drawings'].values():
73+
for side in layer.values():
74+
for dwg in side:
75+
if 'text' in dwg:
76+
yield dwg
77+
78+
@staticmethod
79+
def _remove_control_codes(s):
80+
import unicodedata
81+
return ''.join(c for c in s if unicodedata.category(c)[0] != "C")
82+
83+
def _parse_font_data(self, pcbdata):
84+
font_parser = FontParser()
85+
for dwg in self._texts(pcbdata):
86+
if 'svgpath' not in dwg:
87+
dwg['text'] = self._remove_control_codes(dwg['text'])
88+
font_parser.parse_font_for_string(dwg['text'])
89+
90+
if font_parser.get_parsed_font():
91+
pcbdata['font_data'] = font_parser.get_parsed_font()
92+
93+
def _check_font_data(self, pcbdata):
94+
mc = set()
95+
for dwg in self._texts(pcbdata):
96+
dwg['text'] = self._remove_control_codes(dwg['text'])
97+
mc.update({c for c in dwg['text'] if 'svgpath' not in dwg and
98+
c not in pcbdata['font_data']})
99+
100+
if mc:
101+
s = ''.join(mc)
102+
self.logger.error('Provided font_data is missing character(s)'
103+
f' "{s}" that are present in text drawing'
104+
' objects')
105+
return False
106+
else:
107+
return True
108+
68109
def _parse(self):
69110
try:
70111
pcb = self.get_generic_json_pcb()
@@ -82,6 +123,15 @@ def _parse(self):
82123
pcbdata = pcb['pcbdata']
83124
components = [Component(**c) for c in pcb['components']]
84125

126+
if 'font_data' in pcbdata:
127+
if not self._check_font_data(pcbdata):
128+
raise ParsingException(f'Failed parsing {self.file_name}')
129+
else:
130+
self._parse_font_data(pcbdata)
131+
if 'font_data' in pcbdata:
132+
self.logger.info('No font_data provided in JSON, using '
133+
'newstroke font')
134+
85135
self.logger.info('Successfully parsed {}'.format(self.file_name))
86136

87137
return pcbdata, components
@@ -108,4 +158,6 @@ def parse(self):
108158
c.extra_fields = {
109159
f: c.extra_fields.get(f, "") for f in extra_fields}
110160

161+
self.config.kicad_text_formatting = False
162+
111163
return pcbdata, components

InteractiveHtmlBom/ecad/schema/genericjsonpcbdata_v1.schema

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@
8888
"nets": {
8989
"type": "array",
9090
"items": { "type": "string" }
91+
},
92+
"font_data": {
93+
"$ref": "#/definitions/FontData"
9194
}
9295
},
9396
"required": [
@@ -592,6 +595,9 @@
592595
}
593596
}
594597
},
598+
"PolyLineArray": {
599+
"$ref": "#/definitions/Polygons"
600+
},
595601
"ReferenceSet": {
596602
"type": "array",
597603
"items": {
@@ -609,6 +615,23 @@
609615
"properties": {
610616
},
611617
"title": "ExtraData"
618+
},
619+
"FontData": {
620+
"type": "object",
621+
"patternProperties": {
622+
"^.$" : {
623+
"type": "object",
624+
"properties": {
625+
"w": { "type": "number" },
626+
"l": { "$ref": "#/definitions/PolyLineArray" }
627+
},
628+
"additionalProperties" : false,
629+
"required": [
630+
"w",
631+
"l"
632+
]
633+
}
634+
}
612635
}
613636
}
614637
}

InteractiveHtmlBom/web/render.js

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,16 +71,18 @@ function drawText(ctx, text, color) {
7171
var offsetx = -lineWidth * (text.justify[0] + 1) / 2;
7272
var inOverbar = false;
7373
for (var j = 0; j < txt[i].length; j++) {
74-
if (txt[i][j] == '\t') {
75-
var fourSpaces = 4 * pcbdata.font_data[' '].w * text.width;
76-
offsetx += fourSpaces - offsetx % fourSpaces;
77-
continue;
78-
} else if (txt[i][j] == '~') {
79-
j++;
80-
if (j == txt[i].length)
81-
break;
82-
if (txt[i][j] != '~') {
83-
inOverbar = !inOverbar;
74+
if (config.kicad_text_formatting) {
75+
if (txt[i][j] == '\t') {
76+
var fourSpaces = 4 * pcbdata.font_data[' '].w * text.width;
77+
offsetx += fourSpaces - offsetx % fourSpaces;
78+
continue;
79+
} else if (txt[i][j] == '~') {
80+
j++;
81+
if (j == txt[i].length)
82+
break;
83+
if (txt[i][j] != '~') {
84+
inOverbar = !inOverbar;
85+
}
8486
}
8587
}
8688
var glyph = pcbdata.font_data[txt[i][j]];

InteractiveHtmlBom/web/util.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ var settings = {
488488
renderTracks: true,
489489
renderZones: true,
490490
columnOrder: [],
491-
hiddenColumns: [],
491+
hiddenColumns: []
492492
}
493493

494494
function initDefaults() {

0 commit comments

Comments
 (0)