pdf.js-extract
Version:
super-simple async PDF reader that extracts text with x,y page positions based on pdf.js
111 lines (107 loc) • 3.02 kB
JavaScript
const utils = {
xStats: page => {
const x = {};
page.content.forEach(item => {
const xx = item.x.toFixed(0);
x[xx] = (x[xx] || 0) + 1;
});
return Object.keys(x).map(key => ({x: key, val: x[key]})).filter(o => o.val > 1).sort((a, b) => a.x - b.x);
},
lineStartWithStrings: (line, strings) => {
if (line.length < strings.length) return false;
for (let i = 0; i < strings.length; i++) {
if (line[i].str.indexOf(strings[i]) !== 0) return false;
}
return true;
},
extractTextRows: lines => lines.map(line => line.map(cell => {
if (!cell) return null;
return cell.str;
})),
extractColumnRows: (lines, columns, maxdiff) => {
lines = utils.extractColumnLines(lines, columns, maxdiff);
return utils.extractTextRows(lines);
},
extractColumnLines: (lines, columns, maxdiff) => {
const getCol = x => {
let col = 0;
for (let i = columns.length; i >= 0; i--) {
if (x < columns[i]) col = i;
}
return col;
};
return lines.map(line => {
const row = [];
line.forEach((cell, j) => {
const x = cell.x;
const col = getCol(x);
if (row[col]) {
const before = (line[j - 1]);
const diff = cell.x - (before.x + before.width);
if (diff < maxdiff) {
cell.str = row[col].str + cell.str;
row[col].merged = true;
row[col].str = "";
} else {
console.log("---------------");
console.log("warning, double content for cell", JSON.stringify(cell));
console.log("col", col);
console.log("diff", diff, "line-length", line.length);
console.log(line.filter(c => !c.merged).map(c => {
c.col = getCol(c.x);
return c;
}));
cell.str = row[col].str + "\n" + cell.str;
}
}
while (row.length <= col) {
row.push(null);
}
row[col] = cell;
});
return row;
});
},
extractLines: (lines, start_strings, end_strings) => {
let includeLine = -1;
return lines.filter(line => {
if (line.length === 0) return false;
if (includeLine === -1) {
if (utils.lineStartWithStrings(line, start_strings)) {
includeLine = 0;
}
} else if (includeLine > -1) {
if (utils.lineStartWithStrings(line, end_strings)) {
includeLine = -1;
} else {
includeLine++;
}
}
return includeLine > 0;
});
},
pageToLines: (page, maxDiff) => {
const collector = {};
page.content.forEach(text => {
collector[text.y] = collector[text.y] || [];
collector[text.y].push(text);
});
const list = Object.keys(collector).map(key => ({y: key, items: collector[key]})).sort((a, b) => a.y - b.y);
if (maxDiff > 0) {
for (let i = list.length - 1; i > 0; i--) {
const r1 = list[i - 1];
const r2 = list[i];
const diff = r2.y - r1.y;
if (diff < maxDiff) {
r1.items = r1.items.concat(r2.items);
r2.items = [];
}
}
}
list.forEach(item => {
item.items = item.items.sort((a, b) => a.x - b.x);
});
return list.filter(item => item.items.length > 0).map(item => item.items)
}
};
module.exports = utils;