diff --git a/src/ocrmypdf/_pipeline.py b/src/ocrmypdf/_pipeline.py index 1e494b39..8240ba90 100644 --- a/src/ocrmypdf/_pipeline.py +++ b/src/ocrmypdf/_pipeline.py @@ -162,6 +162,10 @@ def repair_and_parse_pdf( options = context.get_options() copyfile(input_file, output_file) + detailed_page_analysis = False + if options.redo_ocr: + detailed_page_analysis = True + try: pdfinfo = PdfInfo(output_file, log=log) except pikepdf.PasswordError as e: diff --git a/src/ocrmypdf/pdfinfo/__init__.py b/src/ocrmypdf/pdfinfo/__init__.py index 7a6972a3..851d7af4 100644 --- a/src/ocrmypdf/pdfinfo/__init__.py +++ b/src/ocrmypdf/pdfinfo/__init__.py @@ -27,7 +27,7 @@ import re from pikepdf import PdfMatrix import pikepdf -from .ghosttext import extract_text_xml +from . import ghosttext from .layout import get_page_analysis, get_text_boxes from ..helpers import fspath @@ -564,18 +564,20 @@ def _pdf_get_pageinfo(pdf, pageno: int, infile, xmltext): pageinfo['images'] = [] page = pdf.pages[pageno] - - # pageinfo['textinfo'] = _page_get_textblocks( - # fspath(infile), pageno, xmltext=xmltext) - pscript5_mode = str(pdf.metadata.get('/Creator')).startswith('PScript5') - miner = get_page_analysis(infile, pageno, pscript5_mode) - pageinfo['textboxes'] = list(simplify_textboxes(miner)) - mediabox = [Decimal(d) for d in page.MediaBox.as_list()] width_pt = mediabox[2] - mediabox[0] height_pt = mediabox[3] - mediabox[1] - bboxes = (box.bbox for box in pageinfo['textboxes']) + if xmltext: + bboxes = ghosttext.page_get_textblocks( + fspath(infile), pageno, xmltext=xmltext, height=height_pt) + pageinfo['bboxes'] = bboxes + else: + pscript5_mode = str(pdf.metadata.get('/Creator')).startswith('PScript5') + miner = get_page_analysis(infile, pageno, pscript5_mode) + pageinfo['textboxes'] = list(simplify_textboxes(miner)) + bboxes = (box.bbox for box in pageinfo['textboxes']) + pageinfo['has_text'] = _page_has_text( bboxes, width_pt, height_pt ) @@ -615,16 +617,20 @@ def _pdf_get_pageinfo(pdf, pageno: int, infile, xmltext): return pageinfo -def _pdf_get_all_pageinfo(infile, log=None): +def _pdf_get_all_pageinfo(infile, detailed_page_analysis, log=None): if not log: log = Mock() pdf = pikepdf.open(infile) - page_xml = extract_text_xml(infile, pdf, pageno=None, log=log) + if not detailed_page_analysis: + pages_xml = None + else: + pages_xml = ghosttext.extract_text_xml(infile, pdf, pageno=None, log=log) pages = [] for n in range(len(pdf.pages)): - page = PageInfo(pdf, n, infile, page_xml[n]) + page_xml = pages_xml[n] if pages_xml else None + page = PageInfo(pdf, n, infile, page_xml) pages.append(page) return pages, pdf @@ -694,9 +700,16 @@ class PageInfo: result = False return result + if 'textboxes' not in self._pageinfo: + if visible is not None and corrupt is not None: + raise NotImplementedError( + 'Ghostscript textboxes cannot be classified') + return self._pageinfo['bboxes'] + return (obj.bbox for obj in self._pageinfo['textboxes'] if predicate(obj, visible, corrupt)) + @property def xres(self): return self._pageinfo.get('xres', None) @@ -729,9 +742,10 @@ class PageInfo: class PdfInfo: """Get summary information about a PDF""" - def __init__(self, infile, log=None): + def __init__(self, infile, detailed_page_analysis=False, log=None): self._infile = infile - self._pages, pdf = _pdf_get_all_pageinfo(infile, log=log) + self._pages, pdf = _pdf_get_all_pageinfo( + infile, detailed_page_analysis, log=log) self._needs_rendering = pdf.root.get('/NeedsRendering', False) self._has_acroform = '/AcroForm' in pdf.root diff --git a/src/ocrmypdf/pdfinfo/ghosttext.py b/src/ocrmypdf/pdfinfo/ghosttext.py index 1545afb8..4b9e13a0 100644 --- a/src/ocrmypdf/pdfinfo/ghosttext.py +++ b/src/ocrmypdf/pdfinfo/ghosttext.py @@ -32,8 +32,8 @@ regex_remove_char_tags = re.compile(br""" """, re.VERBOSE) -def _page_get_textblocks(infile, pageno, xmltext): - """Smarter text detection""" +def page_get_textblocks(infile, pageno, xmltext, height): + """Get text boxes out of Ghostscript txtwrite xml""" root = xmltext if not hasattr(xmltext, 'findall'): @@ -45,8 +45,10 @@ def _page_get_textblocks(infile, pageno, xmltext): font_size = span.attrib['size'] pts = [int(pt) for pt in bbox_str.split()] pts[1] = pts[1] - int(float(font_size) + 0.5) - bbox = tuple(pts) - yield bbox + bbox_topdown = tuple(pts) + bb = bbox_topdown + bbox_bottomup = (bb[0], height - bb[3], bb[2], height - bb[1]) + yield bbox_bottomup def joined_blocks(): prev = None @@ -55,7 +57,7 @@ def _page_get_textblocks(infile, pageno, xmltext): prev = bbox if bbox[1] == prev[1] and bbox[3] == prev[3]: gap = prev[2] - bbox[0] - height = bbox[3] - bbox[1] + height = abs(bbox[3] - bbox[1]) if gap < height: # Join boxes prev = (prev[0], prev[1], bbox[2], bbox[3])