Introduction
Generating an OMR form in Aspose.OMR FOSS for Python means building a tree of element configs rooted at TemplateConfig, then handing that tree to OmrEngine.Generate(). The engine renders a page image plus a .omr descriptor that a later recognition pass reads back. This post walks through the element configs that make up that tree, and the alternative text-markup DSL that builds the same tree without constructing Python objects directly.
The library imports as import omr, is MIT licensed, and depends only on numpy, opencv-python, and Pillow.
What’s Included
The Template Tree
TemplateConfig is the document root; it contains one or more PageConfig objects, one per physical page. Every element below a page is a subclass of BaseConfig, carrying at minimum a Name and a Type discriminator (ConfigType).
from omr.generation.config import TemplateConfig
from omr.generation.config.elements.parents import PageConfig
tpl = TemplateConfig()
tpl.Name = "quiz"
page = PageConfig()
page.Children = []
tpl.Children = [page]
Question Elements
ChoiceBoxConfig defines a single question with a fixed set of option bubbles (each a ChoiceBoxAnswerConfig) and supports multi-select; FormValidationLogic, set once per TemplateProcessor, can raise if a question with Multiselect disabled receives more than one mark. AnswerSheetConfig lays out a numbered matrix of answer bubbles for exam-style sheets, with a configurable BubbleType and BubbleSize. CheckBoxConfig is a labeled group of blank boxes accepting any mark, with a tunable fill threshold.
from omr.generation.config.elements import AnswerSheetConfig
sheet = AnswerSheetConfig()
sheet.Name = "answers"
sheet.AnswersCount = 4 # bubbles per question (e.g. A-D)
sheet.ElementsCount = 20 # number of questions
Grids and Composite Grids
GridConfig renders a digit matrix — a fixed number of sections, each with 0–9 option bubbles — merged into a single value, commonly used for ID numbers. CompositeGridConfig is the more flexible variant: a custom symbol set per column, with marks across columns merging into one value.
Layout Containers
BlockConfig is a bordered, padded box; ContainerConfig arranges child blocks into columns or a page footer; PositionedBlockConfig places children at absolute XPosition/YPosition coordinates instead of flowing them. BlockConfig and GlobalPageSettings also carry an Overflow property (OverflowAction subclasses Clip/NoClip/Wrap) and LongWordHandling, but these enums parse and validate correctly without yet being honored by this release’s render engine — overflow behavior is not yet configurable, and is tracked on the upstream roadmap.
The Markup DSL
The same tree can be written as plain text instead of Python objects. ?choicebox=... opens a choice-box question, the following lines list its options, and &choicebox closes it.
import json
from omr.api import OmrEngine
markup = [
"?choicebox=Rate it",
"(1) Poor (2) Fair (3) Good",
"&choicebox",
]
engine = OmrEngine()
result = engine.Generate(markup)
desc = json.loads(result.Template)
Quick Start
git clone https://github.com/aspose-omr-foss/Aspose.OMR-FOSS-for-Python.git
cd Aspose.OMR-FOSS-for-Python
pip install -e .from omr.api import OmrEngine, FormValidationLogic
engine = OmrEngine()
gen = engine.Generate("final-exam.txt") # or a code-first TemplateConfig
gen.Save("out", "final-exam") # -> out/final-exam.png + out/final-exam.omr
processor = engine.GetTemplateProcessor("out/final-exam.omr", FormValidationLogic.Ignore)
result = processor.Recognize("scan.png") # -100 = auto-calibrated threshold
print(result.GetCsv()) # also GetJson() / GetXml()
Open Source & Licensing
Aspose.OMR FOSS for Python is MIT licensed and hosted on GitHub. Commercial use is permitted under the same terms as any MIT-licensed project. For enterprise features and production support, see Aspose.OMR — Enterprise Product Family.