[WIP] store font-map in appState

This commit is contained in:
Johannes Zillmann 2017-03-21 23:12:45 +01:00
parent a35ecd28b6
commit 94c2561717
3 changed files with 138 additions and 50 deletions

View File

@ -1,4 +1,5 @@
import React from 'react';
import FaCheck from 'react-icons/lib/fa/check'
import pdfjs from 'pdfjs-dist'; // eslint-disable-line no-unused-vars
import { Line } from 'rc-progress';
@ -6,6 +7,7 @@ import { Line } from 'rc-progress';
import Page from '../models/Page.jsx';
import TextItem from '../models/TextItem.jsx';
// Parses the PDF pages and displays progress
export default class LoadingView extends React.Component {
static propTypes = {
@ -16,42 +18,78 @@ export default class LoadingView extends React.Component {
constructor(props) {
super(props);
this.state = {
parsedPages: 0,
pages: []
pages: [],
fontIds: new Set(),
fontMap: new Map(),
progress: new Progress({
stages: [
new ProgressStage('Parsing PDF Pages'),
new ProgressStage('Parsing Fonts')
]
}),
};
}
anounceInitialParse(pages) {
announceInitialParse(document) {
const pageStage = this.state.progress.stages[0];
const numPages = document.numPages;
pageStage.steps = numPages;
pageStage.stepsDone;
var pages = [];
for (var i = 0; i < numPages; i++) {
pages.push(new Page({
index: i
}));
}
this.setState({
pages: pages
document: document,
pages: pages,
});
}
anouncePageParsed(index, textItems) {
//TODO might make problems.. concat unordered and order at the end ?
announcePageParsed(index, textItems) {
const pageStage = this.state.progress.stages[0];
const fontStage = this.state.progress.stages[1];
textItems.forEach(item => {
const fontId = item.font;
if (!this.state.fontIds.has(fontId)) {
const announceFontFunction = this.announceFontParsed.bind(this);
this.state.document.transport.commonObjs.get(fontId, function(font) {
announceFontFunction(fontId, font);
});
this.state.fontIds.add(fontId);
fontStage.steps = this.state.fontIds.size;
}
});
pageStage.stepsDone = pageStage.stepsDone + 1;
this.state.pages[index].items = textItems; // eslint-disable-line react/no-direct-mutation-state
this.setState({
parsedPages: this.state.parsedPages + 1
progress: this.state.progress
});
}
announceFontParsed(fontId, font) {
const fontStage = this.state.progress.stages[1];
this.state.fontMap.set(fontId, font); // eslint-disable-line react/no-direct-mutation-state
fontStage.stepsDone = fontStage.stepsDone + 1;
if (this.state.progress.currentStage == 1) {
this.setState({ //force rendering
fontMap: this.state.fontMap,
});
}
}
componentWillMount() {
const anounceInitialParseFunction = this.anounceInitialParse.bind(this);
const anouncePageParsedFunction = this.anouncePageParsed.bind(this);
const announceInitialParseFunction = this.announceInitialParse.bind(this);
const announcePageParsedFunction = this.announcePageParsed.bind(this);
PDFJS.getDocument(this.props.fileBuffer).then(function(pdfDocument) { // eslint-disable-line no-undef
// console.log('Number of pages: ' + pdfDocument.numPages);
// console.debug(pdfDocument);
const numPages = pdfDocument.numPages;
// const numPages = 4; // hack
var pages = [];
for (var i = 0; i < numPages; i++) {
pages.push(new Page({
index: i
}));
}
anounceInitialParseFunction(pages);
for (var j = 1; j <= numPages; j++) {
announceInitialParseFunction(pdfDocument);
for (var j = 1; j <= pdfDocument.numPages; j++) {
pdfDocument.getPage(j).then(function(page) {
var scale = 1.0;
var viewport = page.getViewport(scale);
@ -59,14 +97,8 @@ export default class LoadingView extends React.Component {
// pdfDocument.getMetadata().then(function(data) {
// console.debug(data);
// });
// page.getOperatorList().then(function(opList) {
// console.debug(opList);
// // var svgGfx = new svgLib.SVGGraphics(page.commonObjs, page.objs);
// // return svgGfx.getSVG(opList, viewport).then(function (svg) {
// // container.appendChild(svg);
// // });
// });
page.getTextContent().then(function(textContent) {
// console.debug(textContent);
const textItems = textContent.items.map(function(item) {
const tx = PDFJS.Util.transform( // eslint-disable-line no-undef
viewport.transform,
@ -75,20 +107,19 @@ export default class LoadingView extends React.Component {
const fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3]));
const dividedHeight = item.height / fontHeight;
const style = textContent.styles[item.fontName];
return new TextItem({
x: Math.round(item.transform[4]),
y: Math.round(item.transform[5]),
width: Math.round(item.width),
height: Math.round(dividedHeight <= 1 ? item.height : dividedHeight),
text: item.str,
font: item.fontName,
fontAscent: style.ascent,
fontDescent: style.descent
font: item.fontName
});
});
anouncePageParsedFunction(page.pageIndex, textItems);
announcePageParsedFunction(page.pageIndex, textItems);
});
page.getOperatorList().then(function() {
// do nothing... this is only for triggering the font retrieval
});
});
}
@ -96,16 +127,20 @@ export default class LoadingView extends React.Component {
}
render() {
const {parsedPages, pages} = this.state;
var percentDone = 0;
var details = '';
if (pages.length > 0) {
percentDone = parsedPages / pages.length * 100;
details = parsedPages + ' / ' + pages.length
if (parsedPages == pages.length) {
this.props.storePdfPagesFunction(this.state.pages);
}
const {pages, progress} = this.state;
const percentDone = getPercentDone(progress);
if (percentDone == 100) {
this.props.storePdfPagesFunction(pages, this.state.fontMap);
}
const stageItems = progress.stages.filter((elem, i) => i <= progress.currentStage).map((stage, i) => {
const progressDetails = stage.steps ? stage.stepsDone + ' / ' + stage.steps : '';
const checkmark = stage.isComplete() ? <FaCheck color={ 'green' } /> : '';
return <div key={ i }>
{ stage.name }
{ ' ' + progressDetails + ' ' }
{ checkmark }
</div>
});
return (
<div style={ { textAlign: 'center' } }>
<br/>
@ -115,10 +150,64 @@ export default class LoadingView extends React.Component {
<br/>
<br/>
<div>
Uploading and parsing PDF...
<br/>
{ ' ' + details }
{ stageItems }
</div>
</div>);
}
}
function getPercentDone(progress) {
const activeStage = progress.activeStage();
const percentDone = activeStage.percentDone();
if (percentDone == 100) {
progress.completeStage();
if (!progress.isComplete()) {
return getPercentDone(progress, 0);
}
}
return percentDone;
}
class Progress {
constructor(options) {
this.stages = options.stages;
this.currentStage = 0;
}
completeStage() {
this.currentStage++;
}
isComplete() {
return this.currentStage == this.stages.length;
}
activeStage() {
return this.stages[this.currentStage];
}
}
class ProgressStage {
constructor(name) {
this.name = name;
this.stepsDone = 0;
this.steps;
}
isComplete() {
return this.stepsDone == this.steps;
}
percentDone() {
if (!this.steps) {
return 0;
}
return this.stepsDone / this.steps * 100;
}
}

View File

@ -34,7 +34,6 @@ export default class TextItemTable extends React.Component {
</th>
<th>
Font
<br/>(asc/desc)
</th>
</tr>
</thead>
@ -81,8 +80,6 @@ export default class TextItemTable extends React.Component {
</td>
<td>
{ textItem.font }
<br/>
{ textItem.fontAscent + ' / ' + textItem.fontDescent }
</td>
</tr>
)

View File

@ -25,6 +25,7 @@ export default class AppState {
this.mainView = View.UPLOAD;
this.fileBuffer;
this.pages = [];
this.fontMap;
this.transformations = [
new CalculateGlobalStats(),
new CompactLines(),
@ -62,8 +63,9 @@ export default class AppState {
this.render()
}
storePdfPages(pages) {
storePdfPages(pages, fontMap) {
this.pages = pages;
this.fontMap = fontMap;
this.fileBuffer = null;
this.mainView = View.RESULT;
this.render();