mindee
Version:
Mindee Client Library for Node.js
131 lines (130 loc) • 5.2 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.CustomLines = exports.CustomLine = void 0;
exports.getLineItems = getLineItems;
const handler_1 = require("../../errors/handler");
const errors_1 = require("../../errors");
const geometry_1 = require("../../geometry");
const listField_1 = require("./listField");
class CustomLine {
constructor(rowNumber) {
this.rowNumber = rowNumber;
this.bbox = new geometry_1.BBox(1, 1, 0, 0);
this.fields = new Map();
}
/**
* Extends the current bbox of the line with the bbox.
*/
extendWithBbox(bbox) {
this.bbox = (0, geometry_1.mergeBbox)(this.bbox, bbox);
}
/**
* Extends the current bbox of the line with the polygon.
*/
extendWith(polygon) {
this.bbox = (0, geometry_1.mergeBbox)(this.bbox, (0, geometry_1.getBbox)(polygon));
}
updateField(name, fieldValue) {
if (!this.fields.has(name)) {
this.fields.set(name, fieldValue);
}
else {
const existingField = this.fields.get(name);
if (existingField === undefined) {
handler_1.errorHandler.throw(new errors_1.MindeeError(`The field '${name}' should exist but was not found.`));
return;
}
const mergedContent = existingField?.content === undefined
? fieldValue.content
: existingField.content + " " + fieldValue.content;
const mergedBbox = (0, geometry_1.getBBoxForPolygons)([
existingField.polygon,
fieldValue.polygon,
]);
this.fields.set(name, new listField_1.ListFieldValue({
content: mergedContent,
confidence: existingField.confidence * fieldValue.confidence,
polygon: (0, geometry_1.getBoundingBoxFromBBox)(mergedBbox),
}));
}
}
}
exports.CustomLine = CustomLine;
class CustomLines extends Array {
}
exports.CustomLines = CustomLines;
/**
* Get line items from fields.
*/
function getLineItems(anchorNames, fieldNames, fields, heightLineTolerance) {
const fieldsToTransformIntoLines = new Map([...fields].filter(([k]) => fieldNames.includes(k)));
const anchorName = findBestAnchor(anchorNames, fieldsToTransformIntoLines);
const linesPrepared = prepare(anchorName, fieldsToTransformIntoLines, heightLineTolerance);
linesPrepared.forEach((currentLine) => {
fieldsToTransformIntoLines.forEach((field, fieldName) => {
field.values.forEach((listFieldValue) => {
const minMaxY = (0, geometry_1.getMinMaxY)(listFieldValue.polygon);
if (Math.abs(minMaxY.max - currentLine.bbox.yMax) <= heightLineTolerance &&
Math.abs(minMaxY.min - currentLine.bbox.yMin) <= heightLineTolerance) {
currentLine.updateField(fieldName, listFieldValue);
}
});
});
});
return linesPrepared;
}
/**
* Loop through the possible anchor fields and find the one with the most values.
*/
function findBestAnchor(possibleAnchorNames, fields) {
let anchorName = "";
let anchorRows = 0;
possibleAnchorNames.forEach((fieldName) => {
const fieldValues = fields.get(fieldName)?.values;
if (fieldValues !== undefined && fieldValues.length > anchorRows) {
anchorRows = fieldValues.length;
anchorName = fieldName;
}
});
if (anchorName === "") {
handler_1.errorHandler.throw(new errors_1.MindeeError("No anchor was found."));
}
return anchorName;
}
/**
* Check if the bbox fits inside the line.
*/
function isBboxInLine(line, bbox, heightTolerance) {
if (Math.abs(bbox.yMin - line.bbox.yMin) <= heightTolerance) {
return true;
}
return Math.abs(line.bbox.yMin - bbox.yMin) <= heightTolerance;
}
function prepare(anchorName, fields, heightLineTolerance) {
const linesPrepared = [];
const anchorField = fields.get(anchorName);
if (anchorField === undefined || anchorField.values.length === 0) {
handler_1.errorHandler.throw(new errors_1.MindeeError("No lines have been detected."));
}
let currentLineNumber = 1;
let currentLine = new CustomLine(currentLineNumber);
if (anchorField !== undefined) {
let currentValue = anchorField.values[0];
currentLine.extendWith(currentValue.polygon);
for (let index = 1; index < anchorField.values.length; index++) {
currentValue = anchorField.values[index];
const currentFieldBbox = (0, geometry_1.getBbox)(currentValue.polygon);
if (!isBboxInLine(currentLine, currentFieldBbox, heightLineTolerance)) {
linesPrepared.push(currentLine);
currentLineNumber++;
currentLine = new CustomLine(currentLineNumber);
}
currentLine.extendWithBbox(currentFieldBbox);
}
if (linesPrepared.filter((line) => line.rowNumber === currentLineNumber)
.length === 0) {
linesPrepared.push(currentLine);
}
}
return linesPrepared;
}
;