Skip to content
Talk to our solutions team

Document model API

This is the symbol reference for the spatial document model: the types a document is made of, their exact fields, and every exported function and method you can call on them. Look a name up here; read The document model for how the model is built and Extracting fields for how it is used.

Three packages are covered — document (the analysed document and its result types), reading (reading-order analysis) and field (form-field detection and field packs). Names are given unqualified when they belong to document, and package-qualified otherwise.

Every symbol here is reachable from both documented surfaces: the kis CLI and the deployed rules.svc. A rule obtains the document with bbox.Get("<name>") and calls these methods on it; the mapping from rule text to method is in The rules bridge.

ConventionRule
ReceiverMethods are on *Document unless the table header says otherwise
NumbersMethod parameters and returns use int64 and float64 only — never int, int32 or float32
Struct fieldsExported fields still use plain int; the numeric contract covers signatures, not fields
Pages1-indexed. 0 means “every page” on HeaderText, FooterText and Headings
Missing resultsQueries return the zero value (empty slice, "", 0, nil) — they do not error
Safe*Returns a non-nil empty result where the plain variant returns nil
type BoundingBox struct {
X0, Y0 float64 // Top-left corner
X1, Y1 float64 // Bottom-right corner
}

Top-left origin, Y increasing downward, in raw OCR units. Nothing is normalised to 0..1.

MethodReturns
Width() float64X1 - X0
Height() float64Y1 - Y0
Area() float64Width() * Height()
CenterX() float64(X0 + X1) / 2
CenterY() float64(Y0 + Y1) / 2
Left() float64X0
Right() float64X1
Top() float64Y0
Bottom() float64Y1
IsZero() boolTrue when all four coordinates are within 1e-9 of zero
Contains(x, y float64) boolTrue when the point is inside, edges included
type Point struct {
X, Y float64
}
type Direction int
const (
DirRight Direction = iota // 0
DirLeft // 1
DirAbove // 2
DirBelow // 3
)
Method or functionReturns
(Direction) String() string"right", "left", "above", "below", else "unknown"
DirectionFromString(s string) DirectionParses right, left, above/up, below/down
type Confidence struct {
Value float64 // Score from 0.0 to 1.0
Level string // "VeryLow", "Low", "Medium", "High", "VeryHigh"
}
MethodReturns
IsHigh() boolValue >= 0.8
IsMedium() boolValue >= 0.5 && Value < 0.8
IsLow() boolValue < 0.5
Percent() float64Value * 100
TypeFields
TextBlockText string, Box BoundingBox, Confidence float64, Page int
TextLineText string, Box BoundingBox, Confidence float64, Page int, IsWrapped bool
DocumentStatsMedianCharWidth, MedianLineHeight, MedianWordGap, MedianLineGap, PageWidth, PageHeight — all float64
PageLayoutResultPage int, Width float64, Height float64, ColumnCount int, HasHeader bool, HasFooter bool, Margins MarginsResult
MarginsResultTop, Bottom, Left, Right — all float64
RegionResultType string (Header, Footer, MainContent, LeftMargin, RightMargin), Box BoundingBox, Page int, Text string, Confidence float64
DocumentSummaryPageCount, BlockCount, LineCount, TableCount, FieldCount, CheckboxCount, CheckboxGroups — all int — plus Stats text.DocStats

TextBlock is lossy against the analysis-layer block: it drops the source words, the line id and the merge score, so it cannot answer “was this block merged, and from what”. Use the internal-typed accessors when you need that provenance.

type Document struct {
Pages []ocr.Page
Stats text.DocStats
Blocks []text.Block
Lines []text.Line
Tables []table.Table
Fields []field.Field
Checkboxes []checkbox.Checkbox
CheckboxGroups []checkbox.CheckboxGroup
PageLayouts []*region.PageLayout
SpecialRegions []special.Region
Signatures []special.Region
Handwriting []special.Region
Barcodes []special.Region
FontAnalysis *font.FontAnalysis
}

Pages is the input; everything else is filled by Analyze. Signatures, Handwriting and Barcodes are projections of SpecialRegions, not separate detections.

Method or functionReturns
New(ocrDoc *ocr.Document) *DocumentWraps an OCR document with DefaultConfig(). Does not analyse
NewWithConfig(ocrDoc *ocr.Document, cfg Config) *DocumentSame, with explicit settings
DefaultConfig() ConfigEvery detector on, DPI 300
Analyze() errorRuns the full pipeline. Always returns nil today
AnalyzeParallel(workers int64) errorPer-page parallel analysis; results match the serial path
AnalyzeParallelContext(ctx context.Context, workers int64) errorCancellable parallel analysis
SetDPI(dpi float64)Overrides the scan resolution used for point-size conversion
Debug(value bool)Sets debug logging
Toggledebug()Flips debug logging
SetSchemas(schemas map[string]*jsonschema.Schema)Installs named extraction schemas
Schema(name string) *jsonschema.SchemaReturns an installed schema, nil when absent
Summary() DocumentSummaryCounts and statistics for the analysed document
InvalidateReadingCache()Drops the cached reading-order result
type Config struct {
MergeWords bool
DetectTables bool
DetectFields bool
DetectCheckboxes bool
DetectRegions bool
DetectSpecialRegions bool
AnalyzeFonts bool
SpellCheck bool
ExtractPatterns bool
BuildSpatialIndex bool
DPI float64
MergeConfig text.MergeConfig
}
FieldDefaultEffect
MergeWordstrueGlue adjacent OCR words into blocks. Off means one block per word
DetectTablestruePopulates Tables
DetectFieldstruePopulates Fields
DetectCheckboxestruePopulates Checkboxes and CheckboxGroups
DetectRegionstruePopulates PageLayouts
DetectSpecialRegionstruePopulates SpecialRegions and its three projections
AnalyzeFontstruePopulates FontAnalysis
SpellCheckfalseDeclared but never read by the pipeline
ExtractPatternstrueDeclared but never read — pattern extraction is lazy, built on first Find/Has/Count
BuildSpatialIndextrueBuilds the R-tree. Without it the k-nearest, directional and radius queries return nil
DPI300.0Point-size conversion basis. <= 0 falls back to 300
MergeConfigWord-merge thresholds
ConstantValue
DefaultDPI300.0
DefaultBaselineTolerance0.3
DefaultAlignTolerance0.3
DefaultMaxWordGapMultiplier5.0
DefaultCapHeightRatio0.72
DefaultXHeightRatio0.50
DefaultAscenderRatio0.85
DefaultMaxLabelLength50
DefaultFontSizeRoundingPrecision10.0
DefaultFuzzyDistance2
DefaultMaxGap5
UnlimitedDistance-1 (float64)

These return the flat wrapper types above.

MethodReturns
GetBlocks() []TextBlockEvery block in the document
GetLines() []TextLineEvery reconstructed line
GetPageBlocks(pageNum int64) []TextBlockBlocks on one page
GetPageTextLines(pageNum int64) []TextLineLines on one page
FindTextBlocks(search string) []TextBlockBlocks containing the text
FindAnchorBlocks(anchorText string) []TextBlockBlocks matching an anchor
FindFuzzyBlocks(search string, maxDist int64) []TextBlockBlocks within an edit distance
GetHeadingTextBlocks() []TextBlockBlocks classified as headings
GetBlocksByFontSizeRange(minPt, maxPt float64) []TextBlockBlocks inside a point-size band
GetDocumentStats() DocumentStatsThe six document medians and page dimensions

These return the analysis types instead of the wrappers, keeping provenance.

MethodReturns
GetPage(pageNum int64) []text.BlockMerged blocks on one page
GetPageLines(pageNum int64) []text.LineReconstructed lines on one page
GetField(label string) *field.FieldA detected field by label
GetTable(containing string) *table.TableThe first table containing the text
GetPageLayout(pageNum int64) *region.PageLayoutFull layout record for a page
GetHeader(pageNum int64) *region.RegionHeader region
GetFooter(pageNum int64) *region.RegionFooter region
GetMainContent(pageNum int64) *region.RegionMain-content region
GetCheckboxByLabel(label string) *checkbox.CheckboxA detected checkbox
GetCheckboxGroup(name string) *checkbox.CheckboxGroupA detected checkbox group
GetCheckedValue(groupName string) []stringSelected labels in a group
ExtractByDefinition(def field.FieldDef) *field.FieldExtract one field from an explicit definition
ExtractRegisteredFields() map[string]*field.FieldExtract every field definition registered by a pack
MethodReturns
GetLayout(pageNum int64) *PageLayoutResultPage dimensions, column count, header/footer flags, margins
GetHeaderRegion(pageNum int64) *RegionResultHeader region with its text
GetFooterRegion(pageNum int64) *RegionResultFooter region with its text
GetMainContentRegion(pageNum int64) *RegionResultMain-content region with its text
MethodReturns
AllLines() []stringEvery line’s text
LineCount() int64Number of lines
BlockCount() int64Number of blocks
LineAt(index int64) stringLine by 0-based index
FirstLine() string / LastLine() stringFirst and last line
TopLines(n int64) []string / BottomLines(n int64) []stringFirst and last n lines
LineContaining(text string) stringFirst line containing the text
FullLineContaining(text string) stringThe whole line containing the text, untrimmed
LineNumberOf(text string) int64Index of the first line containing the text
LineNumbersOf(text string) []int64Indexes of every matching line
LinesContaining(text string) []stringEvery line containing the text
LinesMatching(pattern string) []stringEvery line matching a regular expression
LineRange(start, end int64) []stringLines in an index range
LinesAfter(anchorText string, n int64) []stringn lines after an anchor
LinesBefore(anchorText string, n int64) []stringn lines before an anchor
LinesBetween(startText, endText string) []stringLines between two anchors
MethodReturns
PageCount() int64Highest page number across blocks
FieldCount() int64Detected fields
TableCount() int64Detected tables
CheckboxCount() int64Detected checkboxes
SignatureCount() int64Detected signatures
BarcodeCount() int64Detected barcodes
ColumnCount() int64Detected columns
CountOccurrences(text string) int64Occurrences of a string

Wrapper-typed, using BoundingBox and Point:

MethodReturns
BlocksInBox(box BoundingBox) []TextBlockBlocks fully inside the box
BlocksIntersectingBox(box BoundingBox) []TextBlockBlocks overlapping the box
NearestBlocks(point Point, k int64) []TextBlockThe k nearest blocks
NearestBlockIn(from BoundingBox, dir Direction, maxDist, margin float64) *TextBlockNearest block in a direction
BlocksNearPoint(center Point, radius float64) []TextBlockBlocks within a radius

Geometry-typed equivalents, returning text.Block:

MethodReturns
BlocksInRegion(region geometry.Box) []text.BlockBlocks fully inside the region
BlocksIntersecting(region geometry.Box) []text.BlockBlocks overlapping the region
KNearestBlocks(point geometry.Point, k int64) []text.BlockThe k nearest blocks
NearestBlockInDirection(from geometry.Box, dir geometry.Direction, maxDist, margin float64) *text.BlockNearest block in a direction
BlocksWithinRadius(center geometry.Point, radius float64) []text.BlockBlocks within a radius

KNearestBlocks, NearestBlockInDirection and BlocksWithinRadius all read the R-tree — they return nil when Config.BuildSpatialIndex was off.

Each returns a chainable query.QueryResult.

MethodAnchor semantics
After(anchorText string) query.QueryResultRight-of first, then below
Below(anchorText string) query.QueryResultDirectly below
Above(anchorText string) query.QueryResultDirectly above
RightOf(anchorText string) query.QueryResultDirectly right
LeftOf(anchorText string) query.QueryResultDirectly left
Near(anchorText string) query.QueryResultAny direction, nearest first
QueryBetween(startText, endText string) query.QueryResultBetween two anchors
InRegion(x0, y0, x1, y1 float64) query.QueryResultAbsolute coordinates
InRegionPct(x0Pct, y0Pct, x1Pct, y1Pct float64) query.QueryResultPercentages of the page

QueryResult carries Blocks []text.Block, Box geometry.Box, Found bool, Page int64 and these accessors:

MethodReturns
Text(), Lines(), Count(), IsEmpty()Text, line list, block count, emptiness
FirstText(), FirstNumber(), FirstCurrency(), FirstDate(), FirstValue()First match, typed
Containing(substr), MatchingPattern(pattern), Filter(predicate)Narrowing
ContainingPhraseFuzzy, ContainingIPhraseFuzzy, ContainingAnyPhraseFuzzy, ContainingAnyIPhraseFuzzyFuzzy narrowing, each (phrase string, maxDistPerWord, maxTotalDist int64)
MethodReturns
ReadAll() stringWhole document in reading order
ReadPage(page int64) stringOne page in reading order
MainContent() stringMain-content region text
BodyText() stringBody text, headers and footers excluded
HeaderText(page int64) string / FooterText(page int64) stringRegion text; 0 means all pages
InHeader(text string) bool / InFooter(text string) boolRegion containment
Contains(text string) boolReading-order text contains the string
ContainsAll(texts ...string) bool / ContainsAny(texts ...string) boolAll / any
Title() stringDetected title, "" when none
HasTitle(text string) bool / TitleContains(text string) boolExact / substring
TitleMatches(pattern string) boolRegular expression against the title
Outline() []reading.OutlineEntryNested heading structure
Headings(level int64) []stringHeadings at a level; 0 returns every level
AllHeadings() []stringEvery heading
Sections() []reading.SectionLogical sections
Section(heading string) *reading.SectionOne section; falls back to a case-insensitive substring match and recurses into subsections
TextUnder(heading string) stringText under a heading
TextBetween(startHeading, endHeading string) stringText between two headings
Columns() []reading.Column / Column(index int64) *reading.ColumnDetected columns
IsMultiColumn() bool / IsMultiPage() boolShape predicates

The reading result is computed once and cached. InvalidateReadingCache() drops it.

type AnalyzerConfig struct {
DetectColumns bool // default true
DetectHeadings bool // default true
RespectRegions bool // default true; declared but never read
MaxColumns int // default 4; 0 means auto
}
Method or functionReturns
DefaultAnalyzerConfig() AnalyzerConfigThe defaults above
NewAnalyzer() *AnalyzerAnalyzer with defaults
NewAnalyzerWithConfig(config AnalyzerConfig) *AnalyzerAnalyzer with explicit settings
(*Analyzer) Analyze(blocks []text.Block, docStats text.DocStats) *ReadingResultFull analysis using document medians
(*Analyzer) AnalyzeWithMedian(blocks []text.Block, medianHeight, medianCharWidth float64) *ReadingResultAnalysis with explicit medians
(*Analyzer) QuickAnalyze(blocks []text.Block) *ReadingResultAnalysis with medians derived from the blocks
TypeFields
ReadingResultBlocks []ReadingBlock, Outline []OutlineEntry, Sections []Section, Columns []Column, Title string, PageCount int
ReadingBlockembeds text.Block; ContentType ContentType, ReadingOrder int, Level int, Column int, RegionType RegionType
OutlineEntryText string, Level int, Box geometry.Box, Page int, Children []OutlineEntry, ContentStart int, ContentEnd int
SectionHeading string, Level int, Blocks []ReadingBlock, Subsections []Section, Box geometry.Box, Page int
ColumnIndex int, Box geometry.Box, Blocks []ReadingBlock, Page int
MethodReturns
(*ReadingResult) Text() stringEvery block’s text, newline-joined
(*ReadingResult) TextByPage(page int) stringOne page, newline-joined
(*ReadingResult) Headings(level int) []stringHeadings at a level; 0 returns all
(*Section) Text() stringHeading plus content plus subsections
(*Section) TextWithOptions(includeHeading bool, lineSeparator string) stringSame, configurable
(*Column) Text() string / (*Column) Lines() []stringColumn text as one string or per block

Classification enums:

TypeValues
ContentTypeContentUnknown, ContentTitle, ContentHeading, ContentSubheading, ContentBody, ContentCaption, ContentFootnote, ContentPageNumber, ContentListItem, ContentTableCell
RegionTypeRegionUnknown, RegionHeader, RegionBody, RegionFooter, RegionLeftMargin, RegionRightMargin

Both have String() string returning the name without the prefix ("Heading", "Footer").

Reading-order constants: HeaderRegionRatio 0.12, FooterRegionRatio 0.10, TitleSearchRegionRatio 0.35, TitleFontSizeMultiplier 1.5, HeadingFontSizeMultiplier 1.2, ColumnGapMinMultiplier 3.0, SameLineTolerance 0.3.

MethodReturns
ContainsText(text string) boolSubstring anywhere
ContainsAnyText(texts ...string) bool / ContainsAllText(texts ...string) boolAny / all
MethodReturns
HasPhrase(phrase string) boolMulti-word phrase present
HasPhraseOnPage(phrase string, page int64) boolScoped to a page
HasPhraseInBox(phrase string, box geometry.Box) boolScoped to a box
HasAnyPhrase(phrases ...string) bool / HasAllPhrases(phrases ...string) boolAny / all
HasAnyPhraseOnPage(page int64, phrases ...string) boolAny, page-scoped
HasAnyPhraseInBox(box geometry.Box, phrases ...string) boolAny, box-scoped
CountPhrase(phrase string) int64Occurrences
CountPhraseOnPage(phrase string, page int64) int64Occurrences on a page
PhraseNear(a, b string, maxPixels float64) boolTwo phrases within a pixel distance
PhraseBetween(startAnchor, endAnchor string) stringText between two phrases
FindPhrase(phrase string, linesBefore, linesAfter int64) []PhraseMatchMatches with line context
FindIPhrase(phrase string, linesBefore, linesAfter int64) []PhraseMatchSame, case-insensitive
MethodReturns
HasPhraseFuzzy(phrase string, maxDistancePerWord int64) boolPresent within an edit distance
HasPhraseOnPageFuzzy(phrase string, page int64, maxDistancePerWord int64) boolPage-scoped
HasPhraseInBoxFuzzy(phrase string, box geometry.Box, maxDistancePerWord int64) boolBox-scoped
HasAnyPhraseFuzzy(maxDistancePerWord int64, phrases ...string) boolAny
HasAllPhrasesFuzzy(maxDistancePerWord int64, phrases ...string) boolAll
CountPhraseFuzzy(phrase string, maxDistancePerWord int64) int64Occurrences
FindPhraseFuzzy(phrase string, maxDistancePerWord, maxTotalDistance, linesBefore, linesAfter int64) []FuzzyPhraseMatchMatches with distances
FindIPhraseFuzzy(phrase string, maxDistancePerWord, maxTotalDistance, linesBefore, linesAfter int64) []FuzzyPhraseMatchSame, case-insensitive
type PhraseMatch struct {
Phrase string // The matched phrase text
Page int // Page number where found
Box geometry.Box // Bounding box of the phrase
LineIndex int // Index of the line containing the phrase
MatchedLine string // Full text of the line containing the match
LinesBefore []string // Lines before the match (context)
LinesAfter []string // Lines after the match (context)
Blocks []text.Block // The blocks that form this phrase
}
type FuzzyPhraseMatch struct {
PhraseMatch
TotalDistance int // Total edit distance across all words
MatchedWords []string // The actual words that matched
}
MethodReturns
FindText(search string) []text.BlockBlocks containing the text
FindAnchor(anchorText string) []text.BlockBlocks matching an anchor
FindFuzzy(search string, maxDist int64) []text.BlockBlocks within an edit distance
FindNgram(tokens ...string) []anchor.NgramMatchUnordered n-gram matches
FindNextFuzzy(search string, fuzzymaxDist int64, from geometry.Box, dir geometry.Direction, maxDistance float64) *text.BlockNext fuzzy match in a direction
FindNextFuzzyWithNgram(search string, fuzzymaxDist int64, from geometry.Box, dir geometry.Direction, maxDistance float64) *anchor.NgramMatchSame, returning the n-gram match
ExtractAfter(label string, dir anchor.RelativeDir) []text.BlockBlocks after a label in a relative direction
MethodReturns
ExtractSnippet(startPhrase, endPhrase string, caseInsensitive, includeEnd bool) *SnippetText between two phrases, across pages. nil when the start phrase is absent
ExtractSnippetFuzzy(startPhrase, endPhrase string, caseInsensitive, includeEnd bool, maxDist int64) *SnippetSame, fuzzy
type Snippet struct {
StartPhrase string // The starting phrase that was matched
EndPhrase string // The ending phrase that was matched
StartPage int // Page where the start phrase was found
EndPage int // Page where the end phrase was found
Lines []string // The extracted lines of text
}

The start phrase is included; the end phrase is excluded unless includeEnd is true.

MethodReturns
GetOCRText(expr string, opts OCRTextOptions) stringText found by walking an anchor expression
GetOCRTextWithContext(ctx context.Context, expr string, opts OCRTextOptions) stringCancellable variant
GetOCRTextSimple(expr string, direction string, ngramMaxDistance float64, maxDistance float64, margin float64) stringSame, with the options flattened to primitives
FindMatchingBlock(expr string, ngramMaxDistance float64) *text.BlockThe block an expression resolves to
FindMatchingBlockWithContext(ctx context.Context, expr string, ngramMaxDistance float64) *text.BlockCancellable variant
type OCRTextOptions struct {
Direction geometry.Direction // search direction from the matched anchor
NgramMaxDistance float64 // 0 = unlimited
MaxDistance float64 // -1 = unlimited
Margin float64 // padding added to the search area
}

DefaultOCRTextOptions() OCRTextOptions returns DirBelow, 0, UnlimitedDistance, 0.

MethodReturns
Find(patternName string) []PatternMatchEvery match of a named pattern
FindFirst(patternName string) stringFirst match, "" when none
Has(patternName string) boolAny match
Count(patternName string) int64Match count
FindPattern(pattern string) []PatternMatchMatches of an explicit pattern
FindPatternFirst(pattern string) stringFirst explicit-pattern match
HasPattern(pattern string) bool / PatternCount(pattern string) int64Presence and count
ExtractPatterns() []pattern.MatchEvery pattern match in the document
ExtractDates() []pattern.Match / ExtractCurrency() []pattern.MatchTyped extraction
type PatternMatch struct {
Value string // The matched text
Box geometry.Box // Bounding box of the matched text
Page int // Page number where the match was found
BlockIndex int // Index of the block containing the match
}

A value split across blocks by OCR is only found by the spanning family.

MethodReturns
FindSpanning(patternName string) []pattern.BlockMatchMatches spanning blocks
FindSpanningAll() []pattern.BlockMatchEvery spanning match
HasSpanning(patternName string) bool / CountSpanning(patternName string) int64Presence and count

Fifteen types have a dedicated four-method set. Every method takes no arguments; the four signatures are the same for every type:

func (d *Document) Find<T>() []PatternMatch
func (d *Document) Find<T>First() string
func (d *Document) Has<T>() bool
func (d *Document) <T>Count() int64
TypeAll matchesFirst matchPresenceCount
SSNFindSSN()FindSSNFirst()HasSSN()SSNCount()
PhoneFindPhone()FindPhoneFirst()HasPhone()PhoneCount()
EmailFindEmail()FindEmailFirst()HasEmail()EmailCount()
DateFindDate()FindDateFirst()HasDate()DateCount()
CurrencyFindCurrency()FindCurrencyFirst()HasCurrency()CurrencyCount()
PercentageFindPercentage()FindPercentageFirst()HasPercentage()PercentageCount()
Account numberFindAccountNumber()FindAccountNumberFirst()HasAccountNumber()AccountNumberCount()
Routing numberFindRoutingNumber()FindRoutingNumberFirst()HasRoutingNumber()RoutingNumberCount()
ZIP codeFindZipCode()FindZipCodeFirst()HasZipCode()ZipCodeCount()
EINFindEIN()FindEINFirst()HasEIN()EINCount()
Street addressFindStreetAddress()FindStreetAddressFirst()HasStreetAddress()StreetAddressCount()
StateFindState()FindStateFirst()HasState()StateCount()
ITINFindITIN()FindITINFirst()HasITIN()ITINCount()
VINFindVIN()FindVINFirst()HasVIN()VINCount()
Policy numberFindPolicyNumber()FindPolicyNumberFirst()HasPolicyNumber()PolicyNumberCount()
MethodReturns
Field(label string) query.FieldResultA detected field by label
FieldByPattern(labelPattern string) query.FieldResultBy regular expression over labels
AllFields() []field.FieldEvery detected field
FieldExists(label string) boolPresence
FieldValue(label string) stringValue as text
FieldEquals(label, expected string) bool / FieldContains(label, substr string) boolComparison
FieldNumber(label string) float64 / FieldCurrency(label string) float64Numeric parse
ExtractFields(fieldLabels ...string) *FormDataSeveral fields plus every table
type FormData struct {
Fields map[string]query.FieldResult
Tables []*TableResult
}
MethodReturns
(*FormData) Get(label string) query.FieldResultOne field
(*FormData) Table(index int) *TableResultOne table
(*FormData) HasField(label string) boolField was found
(*FormData) MissingFields() []stringLabels with no value
(*FormData) IsComplete() boolNothing missing
(*FormData) ToMap() map[string]stringFlat label-to-value map
MethodReturns
TextRightOf(anchorText string) stringText to the right of an anchor
TextBelow(anchorText string) stringText below an anchor
TextAbove(anchorText string) stringText above an anchor
TextLeftOf(anchorText string) stringText to the left of an anchor
NumberRightOf(anchorText string) float64Numeric parse of TextRightOf
NumberBelow(anchorText string) float64Numeric parse of TextBelow
CurrencyRightOf(anchorText string) float64Currency parse of TextRightOf
CurrencyBelow(anchorText string) float64Currency parse of TextBelow
FuzzyTextNear(label string, dir Direction, maxDistPerWord, maxTotalDist int64, expand float64) stringFuzzy label, text in a direction
FuzzyTextNearCapped(label string, dir Direction, maxDistPerWord, maxTotalDist int64, expand, maxExtent float64) stringSame, with a hard extent cap
FuzzyTextNearChain(chain string, valueDir Direction, maxDistPerWord, maxTotalDist int64, expand float64) stringMulti-hop anchor chain
FuzzyTextNearChainCapped(chain string, valueDir Direction, maxDistPerWord, maxTotalDist int64, expand, maxExtent float64) stringChain with an extent cap
FuzzyTextNearChainScaled(chain string, valueDir Direction, maxDistPerWord, maxTotalDist int64, expand, multiplier float64) stringChain with a scaled search region
FuzzyTextAtIntersection(rowLabel, colLabel string, maxDistPerWord, maxTotalDist int64, expand float64) stringValue at a row/column crossing
HasFuzzyChain(chain string, maxDistPerWord, maxTotalDist int64, searchMultiplier, maxSearchPx, sideExtMultiplier float64) boolChain resolves
HasIFuzzyChain(chain string, maxDistPerWord, maxTotalDist int64, searchMultiplier, maxSearchPx, sideExtMultiplier float64) boolSame, case-insensitive

A chain is |-delimited, every segment but the last carrying a direction in angle brackets — "Loan Information<below>|Loan Term".

MethodReturns
FieldNear(label string, dir Direction, maxDistPerWord, maxTotalDist int64, expand float64) query.FieldResultScored spatial extraction
FieldNearCapped(label string, dir Direction, maxDistPerWord, maxTotalDist int64, expand, maxExtent float64) query.FieldResultScored, extent-capped
FieldNearChain(chain string, valueDir Direction, maxDistPerWord, maxTotalDist int64, expand float64) query.FieldResultScored chain
FieldNearChainCapped(chain string, valueDir Direction, maxDistPerWord, maxTotalDist int64, expand, maxExtent float64) query.FieldResultScored chain, extent-capped
ScoredField(label string) query.FieldResultRight-of and below, higher score wins
ScoredFieldOnPage(label string, page int64) query.FieldResultSame, page-scoped
ExtractFieldsScored(labels []string) map[string]query.FieldResultSeveral fields, scored
ExtractFieldsScoredOnPage(labels []string, page int64) map[string]query.FieldResultSame, page-scoped
ExtractFieldsJSON(labels []string) stringJSON object of ScoredValue
ExtractFieldsJSONOnPage(labels []string, page int64) stringSame, page-scoped
type ScoredValue struct {
Value string `json:"value"`
Confidence float64 `json:"confidence"` // 0..1
Found bool `json:"found"`
Page int64 `json:"page,omitempty"`
Method string `json:"method,omitempty"` // e.g. "field.right_of", "field.below"
}

query.FieldResult carries Value, Label, Box, LabelBox, Conf, Prov, Found and Page. Read it with AsText, AsNumber, AsCurrency, AsPercent, AsPercentRaw, AsInt, AsBool, AsDate; test it with IsEmpty, Equals, Contains, Matches, OneOf, GreaterThan, LessThan, Between, Before, After; and inspect the score with Confidence, ConfidencePct, ConfidenceScore, IsConfident, NeedsReview, Explain, Provenance. Required, Optional, Or, OrDefault, WithConfidence and WithProvenance return a modified copy.

MethodReturns
ExtractRepeatingFields(labels ...string) []field.RecordOne record per repeat of the label set
RepeatingExtractingFields(repextractFields string, extractMaxLines, extractMaxWords int64, extractEnd, extractFieldWords, extractVerticalFields string) []map[string]anySame, driven entirely by strings
Method or functionReturns
(*Document) ExtractColumnAlignedSection(sectionStart, sectionEnd, columnHeaders string) []map[string]anyRows read from a columnar section
PostprocessRows(rows []map[string]any, key string, fn string) []map[string]anyPackage function; applies a named transform to one key in every row

fn accepts trim, upper, lower, normalize_spaces, trim_currency, and the dynamic form ExtractRegex("pattern", "defaultVal"). An unknown fn returns the rows untouched. Call it again to chain a second transform on the same key.

type Field struct {
Label string
Value string
LabelBox geometry.Box
ValueBox geometry.Box
Relation RelationType
Confidence float64 // overall confidence
LabelConfidence confidence.Score
ValueConfidence confidence.Score
OverallScore confidence.Score
PatternType pattern.PatternType
Normalized any
}
type FieldDef struct {
Name string
LabelPatterns []string // regular expressions for the label
LabelAnchors []*anchor.Ngram // n-gram anchors for the label
ValueType pattern.PatternType
LocationHint RelationType
Required bool
Validator func(string) bool
}
TypeFields
FieldGroupName string, Fields []Field, Box geometry.Box
PackName string, Fields []FieldDef
RecordFields map[string]string, Line text.Line
DetectorNo exported fields
RelationTypeRelInline, RelRightOf, RelBelow, RelTableCell
Method or functionReturns
NewDetector() *DetectorA detector with default pattern, anchor and fuzzy settings
(*Detector) DetectFields(blocks []text.Block, lines []text.Line) []FieldInline, right-of and below detection, deduplicated
(*Detector) ExtractByDefinition(def FieldDef, blocks []text.Block, lines []text.Line) *FieldOne field from an explicit definition
GroupFields(fields []Field, maxGap float64) []FieldGroupClusters fields by vertical proximity
(*Field) ComputeOverallConfidence()Sets OverallScore and Confidence from a 0.4/0.6 weighting of label and value

Field packs carry the vertical vocabulary; the library itself is domain-neutral.

FunctionReturns
RegisterPack(p Pack)Appends a pack. Concurrency-safe; duplicate names are not rejected
RegisteredPacks() []PackSnapshot in registration order
RegisteredFieldDefs() []FieldDefEvery definition across every pack
RegisteredFieldDef(name string) *FieldDefFirst match by name, case-insensitive; nil when absent
ResetPacks()Empties the registry

When two packs define the same field name, RegisteredFieldDef returns the one registered first — later registrations do not override earlier ones.

Repeating extraction is configured with a chainable builder:

Method or functionReturns
NewRepeatingFieldExtractor(labels ...string) *RepeatingFieldExtractorPackage function; MaxLines 10, MaxWords 3, MinMatchRatio 0.5
(*RepeatingFieldExtractor) SetEndMarkers(markers ...string) *RepeatingFieldExtractorText that ends a record
(*RepeatingFieldExtractor) SetMaxLines(n int) *RepeatingFieldExtractorLines per record
(*RepeatingFieldExtractor) SetMaxWords(n int) *RepeatingFieldExtractorDefault words per value
(*RepeatingFieldExtractor) SetFieldMaxWords(label string, n int) *RepeatingFieldExtractorWords for one field
(*RepeatingFieldExtractor) SetVerticalFields(labels ...string) *RepeatingFieldExtractorFields whose value sits below the label
(*RepeatingFieldExtractor) Extract(lines []text.Line) []RecordOne record per repeat
type RepeatingFieldExtractor struct {
Labels []string
EndMarkers []string
VerticalFields []string
MaxLines int
MaxWords int
FieldMaxWords map[string]int
MinMatchRatio float64
}

Field-detection constants: DefaultMaxLabelLength 50, DefaultShortLabelLength 20, DefaultLabelConfidenceNormalizationFactor 100.0, DefaultGapToWidthMultiplier 3.0, DefaultAlignmentToleranceRatio 0.5, DefaultBaselineTolerance 0.3, DefaultBaseLabelScore 0.5, DefaultColonBoost 0.3, DefaultShortLabelBoost 0.1, DefaultCapitalBoost 0.1, DefaultDigitPenalty 0.2, DefaultPatternMatchConfidence 0.95.

MethodReturns
AllTables() []table.TableEvery detected table
FirstTable() *table.TableThe first table
TableAt(index int64) *table.TableBy index
TableNear(anchorText string) *table.TableNearest to an anchor
TableNearPhrase(anchorPhrase string) *table.TableNearest to a phrase
HasTables() boolAny table detected
Table(index int64) *TableResultBy index, wrapped
TableContaining(text string) *TableResultFirst table containing the text
SafeTable(index int64) *SafeTableResultBy index, nil-safe
WrapTable(t *table.Table) *TableResultWraps a table; nil in, nil out
MethodReturns
TableBelow(anchor string) *TableResultFirst table below an anchor
TableAbove(anchor string) *TableResultFirst table above an anchor
TableBetween(startAnchor, endAnchor string) *TableResultTable between two anchors
TablesBetween(startAnchor, endAnchor string) []*TableResultEvery table between two anchors
TableBelowFuzzy(anchor string, maxDistPerWord, maxTotalDist int64) *TableResultFuzzy anchor
TableAboveFuzzy(anchor string, maxDistPerWord, maxTotalDist int64) *TableResultFuzzy anchor
TableBetweenFuzzy(startAnchor, endAnchor string, maxDistPerWord, maxTotalDist int64) *TableResultFuzzy anchors

Nil-safe variants of the same lookups:

MethodReturns
SafeTableBelow(anchor string) *SafeTableResultFirst table below an anchor
SafeTableAbove(anchor string) *SafeTableResultFirst table above an anchor
SafeTableBetween(startAnchor, endAnchor string) *SafeTableResultTable between two anchors
SafeTableBelowFuzzy(anchor string, maxDistPerWord, maxTotalDist int64) *SafeTableResultFuzzy anchor
SafeTableAboveFuzzy(anchor string, maxDistPerWord, maxTotalDist int64) *SafeTableResultFuzzy anchor
SafeTableBetweenFuzzy(startAnchor, endAnchor string, maxDistPerWord, maxTotalDist int64) *SafeTableResultFuzzy anchors
SafeTablesBetween(startAnchor, endAnchor string) []*TableResultEvery table between two anchors

TableResult embeds *table.Table.

MethodReturns
Row(index int) *RowResultRow by index, headers included
DataRow(index int) *RowResultRow by index, headers excluded
DataRowCount() intRows excluding headers
Headers() []string / HasHeaders() boolHeader row
CellValue(row, col int) stringCell by position
DataCell(row, col int) stringCell by position, headers excluded
CellByHeader(row int, header string) stringCell by row index and header name
ColumnByIndex(index int) []string / ColumnByName(header string) []stringColumn values
ColumnData(colIndex int) []stringColumn values excluding the header
FindRow(text string) *RowResultFirst row containing the text
FindColumn(text string) intIndex of the column containing the text, -1 when absent
RowsAsMaps() []map[string]stringRows keyed by header
AsMap() map[string][]stringColumns keyed by header
IsColumnRightAligned(colIndex int) bool / IsColumnLeftAligned(colIndex int) boolAlignment tests
ColumnAlignment(colIndex int) stringAlignment name
RightAlignedColumns() []intIndexes of right-aligned columns — usually the numeric ones

RowResult embeds *table.Row and adds three accessors:

MethodReturns
(*RowResult) Cell(col int) stringCell by column index
(*RowResult) CellByHeader(header string) stringCell by header name
(*RowResult) Values() []stringEvery cell in the row

SafeTableResult embeds *TableResult and returns empties instead of nil dereferences.

MethodReturns
Row(index int) *SafeRowResult / DataRow(index int) *SafeRowResultNever nil
Cell(row, col int) string / DataCell(row, col int) string"" when absent
CellByHeader(row int, header string) string"" when absent
RowCount() int, DataRowCount() int, ColumnCount() int0 on an absent table
HasData() bool / IsEmpty() boolEmptiness
RowsAsMaps() []map[string]string / AsMap() map[string][]stringEmpty on an absent table

SafeRowResult embeds *RowResult and overrides its accessors to be nil-safe.

MethodReturns
(*SafeRowResult) Cell(col int) string"" when absent
(*SafeRowResult) CellByHeader(header string) string"" when absent
(*SafeRowResult) Values() []stringEmpty slice on an absent row
(*SafeRowResult) IsEmpty() boolTrue on an absent row
type CellResult struct {
Row int // Row index (0-based)
Col int // Column index (0-based)
Text string // Cell text content
Box BoundingBox // Cell bounding box
IsHeader bool // True if this is a header cell
Confidence float64 // Detection confidence
}
MethodReturns
AsText() stringTrimmed text
AsNumber() float64Number, 0 on a parse failure
AsCurrency() float64Currency with symbols and separators stripped
AsPercent() float64Percentage
AsInt() intInteger
AsDate() time.TimeDate, zero time on a parse failure
IsEmpty() boolNo text
Contains(substr string) bool / Equals(text string) boolComparison

Every accessor is nil-safe on the receiver.

type CheckboxResult struct {
Label string // Associated label text
Checked bool // Whether the checkbox is selected
Confidence float64 // Detection confidence (0.0-1.0)
Page int // Page number
Box BoundingBox // Checkbox location
Type string // "checkbox", "radio", "bracket", etc.
GroupName string // Name of the group this checkbox belongs to
}
type CheckboxGroupResult struct {
Name string // Group identifier
Options []CheckboxResult // All checkboxes in the group
Selected []string // Labels of selected items
IsMultiple bool // True if multiple selections are allowed
Page int // Page number where the group appears
Confidence float64 // Overall group detection confidence
}
MethodReturns
(*CheckboxResult) IsChecked() boolfalse on a nil receiver
(*CheckboxResult) HasLabel() boolA label was associated
(*CheckboxResult) IsHighConfidence() boolConfidence >= 0.8
(*CheckboxGroupResult) SelectedValue() stringFirst selection, "" when none
(*CheckboxGroupResult) SelectedValues() []stringEvery selection
(*CheckboxGroupResult) HasSelection() boolAnything selected
(*CheckboxGroupResult) OptionCount() intOptions in the group
(*CheckboxGroupResult) IsYesSelected() bool / IsNoSelected() boolYes/No groups
(*CheckboxGroupResult) GetOption(label string) *CheckboxResultOne option by label

On the document:

MethodReturns
GetCheckbox(label string) *CheckboxResultOne checkbox
GetAllCheckboxes() []CheckboxResultEvery checkbox
GetCheckboxGroupResult(name string) *CheckboxGroupResultOne group
GetAllCheckboxGroups() []CheckboxGroupResultEvery group
IsCheckboxChecked(label string) boolState by label
GetCheckboxValue(label string) stringValue by label
IsYesNoChecked(groupName string) boolYes/No group state

When detection misses the box but the OCR carries a marker glyph, the marker family reads the glyph instead:

MethodReturns
CheckedOption(options ...string) stringFirst option with a checked marker to its left
CheckedOptionMarkers(options []string, checkedChars string) stringSame, with an explicit marker set
CheckedOptionOnPage(options []string, page int64) stringPage-scoped
CheckedOptionNear(anchor string, dir Direction, extent float64, options []string) stringScoped to a region near an anchor
CheckedOptionNearMarkers(anchor string, dir Direction, extent float64, options []string, checkedChars string) stringSame, with an explicit marker set

DefaultCheckedMarkers is "@®©■•✓✔☑█"; DefaultUncheckedMarkers is "O○□()" and is informational only — the checked set is what matching uses.

type SpecialRegionType string
const (
RegionSignature SpecialRegionType = "Signature"
RegionHandwriting SpecialRegionType = "Handwriting"
RegionBarcode1D SpecialRegionType = "Barcode1D"
RegionBarcodeQR SpecialRegionType = "QRCode"
RegionBarcode2D SpecialRegionType = "Barcode2D"
)
type SpecialRegionResult struct {
Type SpecialRegionType // Type of special region
Box BoundingBox // Region location
Page int // Page number
Confidence float64 // Detection confidence (0.0-1.0)
NearLabel string // Nearby label text, e.g. "Sign here"
OCRText string // Any OCR text found in the region
}
MethodReturns
IsSignature() bool, IsHandwriting() boolType tests
IsBarcode() boolTrue for any of the three barcode types
IsQRCode() bool, Is1DBarcode() boolNarrow barcode tests
IsHighConfidence() bool, IsMediumConfidence() boolConfidence bands
HasNearbyLabel() boolNearLabel is set
String() stringOne-line summary

On the document:

MethodReturns
HasSignatures() bool, HasHandwriting() bool, HasBarcodes() boolPresence
GetSignatures(pageNum int64) []SpecialRegionResultSignatures on a page
GetAllSignatures() []SpecialRegionResultEvery signature
GetAllHandwriting() []SpecialRegionResultEvery handwriting region
GetAllBarcodes() []SpecialRegionResultEvery barcode
GetAllSpecialRegions() []SpecialRegionResultEverything detected
GetHighConfidenceSignatures() []special.RegionSignatures above the confidence bar
GetSignaturesOnPage(pageNum int64) []special.RegionInternal-typed, page-scoped
GetHandwritingOnPage(pageNum int64) []special.RegionInternal-typed, page-scoped
GetBarcodesOnPage(pageNum int64) []special.RegionInternal-typed, page-scoped
GetSpecialRegionsByConfidence(minConfidence float64) []special.RegionInternal-typed, filtered
MethodReturns
GetFontSize(block text.Block) font.SizeEstimated size for a block
GetLineFontSize(line text.Line) font.SizeEstimated size for a line
GetFontSizeForText(searchText string) float64Size of the block containing the text
GetBodyFontSize() float64Median body size
GetHeadingSizes() []float64Distinct heading sizes
GetBlocksByFontSize(minPt, maxPt float64) []text.BlockBlocks inside a point band
GetHeadingBlocks() []text.BlockBlocks classified as headings
IsHeading(block text.Block) boolHeading classification
IsHeadingPhrase(phrase string) boolThe phrase sits in a heading
IsHeadingPhraseFirst(phrase string) boolOnly the first match is tested
IsHeadingPhraseInRegion(phrase, regionName string) boolHeading test inside a named region
IsHeadingPhraseIn(phrase, direction, regionName string, page int64, firstMatchOnly bool) boolHeading test, fully scoped
IsSmallText(block text.Block) boolSmall or fine print, per the font analysis. false when fonts were not analysed
IsTextBig(searchText string) boolThe block containing the text is taller than average
IsBold(block text.Block) boolWeight estimate from stroke width
StrokeWidth(block text.Block) float64Estimated stroke width
TypographyTier(block text.Block) font.TierSize tier
IsAllCaps(block text.Block) bool / IsTitleCase(block text.Block) boolCasing
IsCentered(block text.Block) boolHorizontally centred on the page within 5%, using Stats.PageWidth
IsCenteredInBox(block text.Block, box geometry.Box, tolerancePct float64) boolCentred inside a box

Install schemas with SetSchemas, then extract by name.

MethodReturns
HasForm(name string) bool / HasTable(name string) boolA schema of that kind is installed
ExtractForm(name string) map[string]anyField values for a form schema
ExtractFormOnPage(name string, page int64) map[string]anyPage-scoped
ExtractTable(name string) []map[string]anyRows for a table schema
ExtractTableOnPage(name string, page int64) []map[string]anyPage-scoped
SafeExtractForm(name string) map[string]anyNon-nil empty instead of nil
SafeExtractFormOnPage(name string, page int64) map[string]anyNon-nil empty, page-scoped
SafeExtractTable(name string) []map[string]anyNon-nil empty instead of nil
SafeExtractTableOnPage(name string, page int64) []map[string]anyNon-nil empty, page-scoped
ExtractFormScored(name string) map[string]query.FieldResultForm values with confidence
ExtractFormScoredOnPage(name string, page int64) map[string]query.FieldResultSame, page-scoped
DiagnoseForm(name string) []FieldDiagnosisWhy each property did or did not extract
type FieldDiagnosis struct {
Field string
Anchor string
ValueFound bool
AnchorInScope bool // matched at the configured tolerance within the schema's page/region
AnchorAnywhere bool // matched at a looser tolerance anywhere in the document
Reason string
}

DiagnoseForm is the tool for a form that extracts nothing: AnchorInScope == false with AnchorAnywhere == true means the scope is wrong, not the anchor.

type DoctypeSpec struct {
Name string
Keywords []string
TitleWeight float64 // defaults to 0.4 when zero
HeadingWeight float64 // defaults to 0.3 when zero
ContentWeight float64 // defaults to 0.3 when zero
}
type ClassifyResult struct {
Matches map[string]float64 // document type to confidence
BestType string
BestConfidence float64
}
Method or functionReturns
(*Document) Classify(specs []DoctypeSpec) ClassifyResultScores explicit specs
(*Document) ClassifyAs(docTypes ...string) ClassifyResultScores registered specs by name; an unknown name scores an empty spec
RegisterDoctype(spec DoctypeSpec)Package function; appends a spec. Concurrency-safe
RegisteredDoctypes() []DoctypeSpecDefaultDoctypes first, then registrations in order
ResetDoctypes()Empties the caller registry
(ClassifyResult) BestMatch() stringBestType
(ClassifyResult) Confidence() float64BestConfidence
(ClassifyResult) MatchesType(docType string, minConfidence float64) boolType scored at or above a threshold
(ClassifyResult) Is(docType string) boolType is the best match

DefaultDoctypes ships six domain-neutral specs: invoice, receipt, contract, tax_form, bank_statement, insurance. Vertical types are added with RegisterDoctype.

type SectionResult struct {
Heading string // Section heading text
Level int // Heading level (1=H1, 2=H2, ...)
Content string // All text content in the section
Subsections []SectionResult // Nested subsections
Page int // Page where the section starts
Box BoundingBox // Section bounding box
}
type OutlineEntryResult struct {
Text string // Heading text
Level int // Heading level
Page int // Page number
Box BoundingBox // Heading location
Children []OutlineEntryResult // Nested headings
}
type ColumnResult struct {
Index int // Column index (0-based, left to right)
Box BoundingBox // Column boundaries
Page int // Page number
Content string // Text content in the column
}
MethodReturns
(*SectionResult) Text() stringContent
(*SectionResult) AllText() stringContent plus every subsection
(*SectionResult) HasSubsections() bool / SubsectionCount() intNesting
(*SectionResult) GetSubsection(heading string) *SectionResultChild by heading, case-insensitive
(*SectionResult) FindSubsection(text string) *SectionResultChild by substring, recursive
(*SectionResult) IsEmpty() boolNo content
(*OutlineEntryResult) HasChildren() bool / ChildCount() intNesting
(*OutlineEntryResult) GetChild(text string) *OutlineEntryResultChild by text, case-insensitive
(*OutlineEntryResult) AllHeadings() []stringThis heading and every descendant
(*ColumnResult) Text() string / IsEmpty() bool / Width() float64Column content and geometry