Examine rows[row_start, row_end) as an independent section of text, and mark rows that are exceptionally clear as start-of-paragraph and paragraph-body lines. We presume that any lines surrounding rows[row_start, row_end) may have wildly different paragraph models, so we don't key any data off of those lines. We only take the very strongest signals, as we don't want to get confused and marking u
| 1828 | // confused and marking up centered text, poetry, or source code as |
| 1829 | // clearly part of a typical paragraph. |
| 1830 | void MarkStrongEvidence(GenericVector<RowScratchRegisters> *rows, |
| 1831 | int row_start, int row_end) { |
| 1832 | // Record patently obvious body text. |
| 1833 | for (int i = row_start + 1; i < row_end; i++) { |
| 1834 | const RowScratchRegisters &prev = (*rows)[i - 1]; |
| 1835 | RowScratchRegisters &curr = (*rows)[i]; |
| 1836 | tesseract::ParagraphJustification typical_justification = |
| 1837 | prev.ri_->ltr ? JUSTIFICATION_LEFT : JUSTIFICATION_RIGHT; |
| 1838 | if (!curr.ri_->rword_likely_starts_idea && |
| 1839 | !curr.ri_->lword_likely_starts_idea && |
| 1840 | !FirstWordWouldHaveFit(prev, curr, typical_justification)) { |
| 1841 | curr.SetBodyLine(); |
| 1842 | } |
| 1843 | } |
| 1844 | |
| 1845 | // Record patently obvious start paragraph lines. |
| 1846 | // |
| 1847 | // It's an extremely good signal of the start of a paragraph that |
| 1848 | // the first word would have fit on the end of the previous line. |
| 1849 | // However, applying just that signal would have us mark random |
| 1850 | // start lines of lineated text (poetry and source code) and some |
| 1851 | // centered headings as paragraph start lines. Therefore, we use |
| 1852 | // a second qualification for a paragraph start: Not only should |
| 1853 | // the first word of this line have fit on the previous line, |
| 1854 | // but also, this line should go full to the right of the block, |
| 1855 | // disallowing a subsequent word from having fit on this line. |
| 1856 | |
| 1857 | // First row: |
| 1858 | { |
| 1859 | RowScratchRegisters &curr = (*rows)[row_start]; |
| 1860 | RowScratchRegisters &next = (*rows)[row_start + 1]; |
| 1861 | tesseract::ParagraphJustification j = |
| 1862 | curr.ri_->ltr ? JUSTIFICATION_LEFT : JUSTIFICATION_RIGHT; |
| 1863 | if (curr.GetLineType() == LT_UNKNOWN && |
| 1864 | !FirstWordWouldHaveFit(curr, next, j) && |
| 1865 | (curr.ri_->lword_likely_starts_idea || |
| 1866 | curr.ri_->rword_likely_starts_idea)) { |
| 1867 | curr.SetStartLine(); |
| 1868 | } |
| 1869 | } |
| 1870 | // Middle rows |
| 1871 | for (int i = row_start + 1; i < row_end - 1; i++) { |
| 1872 | RowScratchRegisters &prev = (*rows)[i - 1]; |
| 1873 | RowScratchRegisters &curr = (*rows)[i]; |
| 1874 | RowScratchRegisters &next = (*rows)[i + 1]; |
| 1875 | tesseract::ParagraphJustification j = |
| 1876 | curr.ri_->ltr ? JUSTIFICATION_LEFT : JUSTIFICATION_RIGHT; |
| 1877 | if (curr.GetLineType() == LT_UNKNOWN && |
| 1878 | !FirstWordWouldHaveFit(curr, next, j) && |
| 1879 | LikelyParagraphStart(prev, curr, j)) { |
| 1880 | curr.SetStartLine(); |
| 1881 | } |
| 1882 | } |
| 1883 | // Last row |
| 1884 | { // the short circuit at the top means we have at least two lines. |
| 1885 | RowScratchRegisters &prev = (*rows)[row_end - 2]; |
| 1886 | RowScratchRegisters &curr = (*rows)[row_end - 1]; |
| 1887 | tesseract::ParagraphJustification j = |
no test coverage detected