1
0
Fork 0
inkscape/share/extensions/hpgl_parser.py
Daniel Baumann 02d935e272
Adding upstream version 1.4.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 23:40:13 +02:00

231 lines
7.1 KiB
Python

#!/usr/bin/env python3
# coding=utf-8
#
# Copyright (C) 2022 Jonathan Neuhauser (jonathan.neuhauser@outlook.com)
#
# 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 2 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, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
"""Grammar for parsing HPGL input files"""
import pyparsing as pp
from hpgl_input_sm import HPGLStateMachine
pp.ParserElement.enablePackrat()
pp.enable_all_warnings()
integer = pp.pyparsing_common.integer
sinteger = pp.pyparsing_common.signed_integer
flt = pp.pyparsing_common.number
comma = pp.Optional(pp.Suppress(","))
cpair = flt("X*") + comma + flt("Y*")
def build_vector_parsers(stm: HPGLStateMachine):
"""Parsers of the vector group"""
# Lines
line_command = pp.Group(
(
(pp.Literal("PA") | "PR" | "PD" | "PU")("key")
+ pp.Opt(
cpair
+ pp.ZeroOrMore(comma + cpair)
+ pp.Opt(comma + sinteger("leftover*"))
)
).add_parse_action(stm.line_command)
)
# Circles and arcs
ci_command = pp.Group(
(
"CI" + sinteger("Radius") + pp.Opt(comma + flt("Chord_angle"))
).add_parse_action(stm.ci_command)
)
arc_command = pp.Group(
(
(pp.Literal("AA") | "AR")("key")
+ cpair
+ comma
+ sinteger("sweep")
+ pp.Opt(comma + flt("Chord_angle*"))
).add_parse_action(stm.arc_command)
)
at_command = pp.Group(
(
"AT" + cpair + comma + cpair + pp.Opt(comma + flt("Chord_angle*"))
).add_parse_action(stm.at_command)
)
# Beziers
bezier = cpair + comma + cpair + comma + cpair
bezier_command = pp.Group(
(
(pp.Literal("BR") | "BZ")("key")
+ bezier("B*")
+ pp.ZeroOrMore(comma + bezier("B*"))
).add_parse_action(stm.bezier_command)
)
# Polyline encoded
pe_command = pp.Group(
(
"PE" + pp.Regex("[^;]*").setWhitespaceChars("")("data") + pp.Suppress(";")
).add_parse_action(stm.polyline_encoded)
)
return (
line_command
| ci_command
| arc_command
| bezier_command
| at_command
| pe_command
)
def build_polygon_parsers(stm: HPGLStateMachine):
"""Build parser object from the polygon group"""
pm_command = pp.Group(
("PM" + pp.Opt(pp.Word("012", exact=1), default="0")("value")).add_parse_action(
stm.pm_command
)
)
rectangle_command = pp.Group(
((pp.Literal("EA") | "ER" | "RA" | "RR")("key") + cpair).add_parse_action(
stm.rectangle_command
)
)
polygon_command = pp.Group(
(
(
pp.Literal("FP")("key")
+ pp.Opt(pp.Word("01", exact=1), default="0")("fillmode")
)
| pp.Literal("EP")("key")
).add_parse_action(stm.edge_fill_polygon)
)
wedge_command = pp.Group(
(
(pp.Literal("EW") | "WG")("key")
+ sinteger("radius")
+ comma
+ flt("start_angle")
+ comma
+ flt("sweep")
+ pp.Opt(comma + flt("Chord_angle*"))
).add_parse_action(stm.wedge_command)
)
return pm_command | rectangle_command | polygon_command | wedge_command
def build_linefill_parsers(stm: HPGLStateMachine):
"""Build parsers from the Line and Fill Attributes Group"""
kind = pp.Word("123", exact=1)("kind*")
la_command = pp.Group(
"LA"
+ pp.Opt(kind + comma + integer("value*"))
+ (comma + kind + comma + integer("value*")) * (0, 2)
)
lt_command = pp.Group(
"LT"
+ pp.Opt(
integer("linetype")
+ pp.Opt(comma + flt("pattern_length") + pp.Opt(comma + flt("mode")))
)
)
pw_command = pp.Group("PW" + pp.Opt(flt("width") + pp.Opt(comma + integer("pen"))))
# maybe we can combine those two?
ft_command = pp.Group(
"FT"
+ pp.Opt(
(pp.Literal("1") | "2" | "3" | "4" | "10" | "11" | "21" | "22")("type")
+ pp.Opt(comma + flt("option1") + pp.Opt(comma + flt("option2")))
)
)
tr_command = pp.Group("TR" + pp.Opt(pp.Literal("0") | "1", "1")("transparency"))
ul_command = pp.Group(
"UL" + pp.Opt(integer("index") + (comma + flt("gap*")) * (0, 20))
)
wu_command = pp.Group("WU" + pp.Opt(pp.Word("01", exact=1)("units")))
sp_command = pp.Group("SP" + pp.Opt(integer("pen"), 0))
return (
sp_command
| la_command
| lt_command
| pw_command
| ft_command
| tr_command
| ul_command
| wu_command
).add_parse_action(stm.style_command)
def build_configuration_parser(stm: HPGLStateMachine):
"""Commands of the configurtion group"""
co_command = pp.Literal("CO") + pp.Suppress('"') + ... + pp.Suppress('"')
in_command = pp.Literal("IN").add_parse_action(stm.initialize)
ip_command = pp.Group(
(pp.Literal("IP") | "IR")("key") + pp.Opt(cpair + pp.Opt(comma + cpair))
)
ro_command = pp.Group(
"RO" + pp.Optional(pp.Literal("0") | "90" | "180" | "270", "0")("angle")
)
iw_command = pp.Group("IW" + pp.Opt(cpair + comma + cpair))
sc_command = pp.Group(
pp.Literal("SC")
+ (
pp.Optional(
flt("Xmin")
+ comma
+ flt("Xmax")
+ comma
+ flt("Ymin")
+ comma
+ flt("Ymax")
+ pp.Optional(
(comma + (pp.Literal("0") | "2")("type"))
| (
comma
+ pp.Literal("1")("type")
+ pp.Optional(comma + flt("left") + comma + flt("bottom"))
)
)
)
)
)
return (in_command | co_command) | (
ip_command | sc_command | ro_command | iw_command
).add_parse_action(stm.transform_command)
def build_parser(stm: HPGLStateMachine):
"""Assemble the command groups"""
command = (
build_configuration_parser(stm)
| build_vector_parsers(stm)
| build_polygon_parsers(stm)
| build_linefill_parsers(stm)
# Commands we don't understand
| pp.Group(pp.Word(pp.alphas, exact=2) + pp.Opt(pp.Word(pp.nums + ",. ")))("u*")
)
# The parse actions of the documents are final cleanup
document = pp.ZeroOrMore(command + pp.Opt(pp.Suppress(";"))).add_parse_action(
stm.finalize_path
)
pp.autoname_elements()
return document