Remote reportlab backend and make reportlab a test-only dependency
This commit is contained in:
@@ -313,7 +313,7 @@ class OcrGrafter:
|
||||
strip_invisible_text(self.pdf_base, base_page)
|
||||
|
||||
base_page.contents_add(
|
||||
new_text_layer, prepend=self.render_mode == RenderMode.UNDERNEATH
|
||||
new_text_layer, prepend=self.render_mode == RenderMode.ON_TOP
|
||||
)
|
||||
|
||||
_update_resources(obj=base_page.obj, font=font, font_key=font_key)
|
||||
|
||||
@@ -21,21 +21,18 @@ from xml.etree import ElementTree
|
||||
|
||||
from pikepdf import PdfMatrix
|
||||
|
||||
from ocrmypdf.hocrtransform.backends import (
|
||||
Canvas,
|
||||
)
|
||||
from ocrmypdf.hocrtransform.backends.pikepdf import PikepdfCanvas
|
||||
from ocrmypdf.hocrtransform.backends.reportlab import (
|
||||
ReportlabCanvas,
|
||||
black,
|
||||
blue,
|
||||
cyan,
|
||||
green,
|
||||
inch,
|
||||
magenta,
|
||||
red,
|
||||
from ocrmypdf.hocrtransform._canvas import PikepdfCanvas
|
||||
from ocrmypdf.hocrtransform.color import (
|
||||
BLACK,
|
||||
BLUE,
|
||||
CYAN,
|
||||
GREEN,
|
||||
MAGENTA,
|
||||
RED,
|
||||
)
|
||||
|
||||
INCH = 72.0
|
||||
|
||||
# According to Wikipedia these languages are supported in the ISO-8859-1 character
|
||||
# set, meaning reportlab can generate them and they are compatible with hocr,
|
||||
# assuming Tesseract has the necessary languages installed. Note that there may
|
||||
@@ -231,15 +228,15 @@ class HocrTransform:
|
||||
if bottomup:
|
||||
return Rect._make(
|
||||
[
|
||||
(pxl.x1 / self.dpi * inch),
|
||||
self.height - (pxl.y2 / self.dpi * inch), # swap y1/y2
|
||||
(pxl.x2 / self.dpi * inch),
|
||||
self.height - (pxl.y1 / self.dpi * inch),
|
||||
(pxl.x1 / self.dpi * INCH),
|
||||
self.height - (pxl.y2 / self.dpi * INCH), # swap y1/y2
|
||||
(pxl.x2 / self.dpi * INCH),
|
||||
self.height - (pxl.y1 / self.dpi * INCH),
|
||||
]
|
||||
)
|
||||
else:
|
||||
return Rect._make(
|
||||
(c / self.dpi * inch) for c in (pxl.x1, pxl.y1, pxl.x2, pxl.y2)
|
||||
(c / self.dpi * INCH) for c in (pxl.x1, pxl.y1, pxl.x2, pxl.y2)
|
||||
)
|
||||
|
||||
def _child_xpath(self, html_tag: str, html_class: str | None = None) -> str:
|
||||
@@ -292,7 +289,7 @@ class HocrTransform:
|
||||
"""
|
||||
# create the PDF file
|
||||
# page size in points (1/72 in.)
|
||||
canvas = PikepdfCanvas( # ReportlabCanvas(
|
||||
canvas = PikepdfCanvas(
|
||||
out_filename,
|
||||
page_size=(self.width, self.height),
|
||||
)
|
||||
@@ -307,7 +304,7 @@ class HocrTransform:
|
||||
# draw cyan box around paragraph
|
||||
if self.render_options.render_paragraph_bbox:
|
||||
# pragma: no cover
|
||||
canvas.set_stroke_color(cyan)
|
||||
canvas.set_stroke_color(CYAN)
|
||||
canvas.set_line_width(0.1) # no line for bounding box
|
||||
canvas.rect(pt.x1, pt.y2, pt.x2 - pt.x1, pt.y2 - pt.y1, fill=0)
|
||||
|
||||
@@ -355,7 +352,7 @@ class HocrTransform:
|
||||
|
||||
def _do_line(
|
||||
self,
|
||||
canvas: Canvas,
|
||||
canvas: PikepdfCanvas,
|
||||
line: Element | None,
|
||||
elemclass: str,
|
||||
fontname: str,
|
||||
@@ -375,7 +372,7 @@ class HocrTransform:
|
||||
if abs(slope) < 0.005:
|
||||
slope = 0.0
|
||||
angle = atan(slope)
|
||||
intercept = pxl_intercept / self.dpi * inch
|
||||
intercept = pxl_intercept / self.dpi * INCH
|
||||
|
||||
# Setup a new coordinate system on the line box's intercept and rotated by
|
||||
# its slope
|
||||
@@ -402,7 +399,7 @@ class HocrTransform:
|
||||
|
||||
self._do_debug_line_bbox(canvas, cm_line_box)
|
||||
self._do_debug_baseline(canvas, 0, cm_line_box, 0)
|
||||
canvas.set_fill_color(black) # text in black
|
||||
canvas.set_fill_color(BLACK) # text in black
|
||||
|
||||
elements = line.findall(self._child_xpath('span', elemclass))
|
||||
for elem, next_elem in pairwise(elements + [None]):
|
||||
@@ -474,7 +471,7 @@ class HocrTransform:
|
||||
return
|
||||
canvas.push()
|
||||
canvas.set_dashes()
|
||||
canvas.set_stroke_color(blue)
|
||||
canvas.set_stroke_color(BLUE)
|
||||
canvas.set_line_width(0.15)
|
||||
canvas.rect(
|
||||
line_box.x1,
|
||||
@@ -494,7 +491,7 @@ class HocrTransform:
|
||||
return
|
||||
canvas.push()
|
||||
canvas.set_dashes()
|
||||
canvas.set_stroke_color(red)
|
||||
canvas.set_stroke_color(RED)
|
||||
canvas.set_line_width(0.1)
|
||||
# Draw a triangle that conveys word height and drawing direction
|
||||
canvas.line(cm_box.x1, cm_box.y1, cm_box.x2, cm_box.y1) # across bottom
|
||||
@@ -507,7 +504,7 @@ class HocrTransform:
|
||||
return
|
||||
canvas.push()
|
||||
canvas.set_dashes()
|
||||
canvas.set_stroke_color(green)
|
||||
canvas.set_stroke_color(GREEN)
|
||||
canvas.set_line_width(0.1)
|
||||
canvas.rect(cm_box.x1, cm_line_box.y1, box_width, line_height, fill=0)
|
||||
canvas.pop()
|
||||
@@ -517,7 +514,7 @@ class HocrTransform:
|
||||
return
|
||||
canvas.push()
|
||||
canvas.set_dashes()
|
||||
canvas.set_fill_color(green)
|
||||
canvas.set_fill_color(GREEN)
|
||||
canvas.set_line_width(0.1)
|
||||
canvas.rect(box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1, fill=1)
|
||||
canvas.pop()
|
||||
@@ -527,7 +524,7 @@ class HocrTransform:
|
||||
return
|
||||
# draw the baseline in magenta, dashed
|
||||
canvas.set_dashes()
|
||||
canvas.set_stroke_color(magenta)
|
||||
canvas.set_stroke_color(MAGENTA)
|
||||
canvas.set_line_width(0.25)
|
||||
# negate slope because it is defined as a rise/run in pixel
|
||||
# coordinates and page coordinates have the y axis flipped
|
||||
|
||||
+4
-6
@@ -13,9 +13,6 @@ from pikepdf import (
|
||||
unparse_content_stream,
|
||||
)
|
||||
|
||||
from ocrmypdf.hocrtransform.backends._base import Canvas as BaseCanvas
|
||||
from ocrmypdf.hocrtransform.backends._base import Text as BaseText
|
||||
|
||||
GLYPHLESS_FONT_NAME = 'pdf.ttf'
|
||||
|
||||
GLYPHLESS_FONT = (package_files('ocrmypdf.data') / GLYPHLESS_FONT_NAME).read_bytes()
|
||||
@@ -247,9 +244,10 @@ class ContentStreamBuilder:
|
||||
return self._instructions
|
||||
|
||||
|
||||
class PikepdfCanvas(BaseCanvas):
|
||||
class PikepdfCanvas:
|
||||
def __init__(self, path, *, page_size):
|
||||
super().__init__(path, page_size=page_size)
|
||||
self.path = path
|
||||
self.page_size = page_size
|
||||
self._pdf = Pdf.new()
|
||||
self._page = self._pdf.add_blank_page(page_size=page_size)
|
||||
self._cs = ContentStreamBuilder()
|
||||
@@ -317,7 +315,7 @@ class PikepdfCanvas(BaseCanvas):
|
||||
self._pdf.save(self.path)
|
||||
|
||||
|
||||
class PikepdfText(BaseText):
|
||||
class PikepdfText:
|
||||
def __init__(self, x=0, y=0, direction=None):
|
||||
self._cs = ContentStreamBuilder()
|
||||
self._cs.begin_text()
|
||||
@@ -1,3 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from ._base import Canvas, Text
|
||||
@@ -1,88 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class Canvas(ABC):
|
||||
def __init__(self, path: Path, *, page_size):
|
||||
self.path = path
|
||||
self.page_size = page_size
|
||||
|
||||
@abstractmethod
|
||||
def set_stroke_color(color):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def set_fill_color(color):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def set_line_width(width):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def line(x1, y1, x2, y2):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def begin_text(self) -> Text:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def draw_text(self, text: Text):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def draw_image(self, image: Path, x, y, width, height):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def string_width(self, text, fontname, fontsize):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def set_dashes(self, array, phase):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def save(self):
|
||||
pass
|
||||
|
||||
|
||||
class Text(ABC):
|
||||
# @abstractmethod
|
||||
# def begin_marked_content(self, mctype, mcid):
|
||||
# pass
|
||||
|
||||
# @abstractmethod
|
||||
# def end_marked_content(self):
|
||||
# pass
|
||||
|
||||
@abstractmethod
|
||||
def set_render_mode(self, mode):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def set_font(self, font, size):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def set_text_transform(self, a, b, c, d, e, f):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def show(self, text):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def set_horiz_scale(self, scale):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_start_of_line(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def move_cursor(self, x, y):
|
||||
pass
|
||||
@@ -1,82 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import warnings
|
||||
from pathlib import Path
|
||||
|
||||
with warnings.catch_warnings():
|
||||
# reportlab uses deprecated load_module
|
||||
# shim can be removed when we require reportlab >= 3.7
|
||||
warnings.filterwarnings(
|
||||
'ignore', category=DeprecationWarning, message=r".*load_module.*"
|
||||
)
|
||||
from reportlab.lib.colors import black, blue, cyan, green, magenta, red
|
||||
from reportlab.lib.units import inch
|
||||
from reportlab.pdfgen.canvas import Canvas
|
||||
from reportlab.pdfgen.textobject import PDFTextObject
|
||||
|
||||
from ocrmypdf.hocrtransform.backends._base import Canvas as BaseCanvas
|
||||
from ocrmypdf.hocrtransform.backends._base import Text as BaseText
|
||||
|
||||
|
||||
class ReportlabCanvas(BaseCanvas):
|
||||
def __init__(self, path, *, page_size):
|
||||
super().__init__(path, page_size=page_size)
|
||||
self._canvas = Canvas(os.fspath(path), pagesize=page_size, pageCompression=1)
|
||||
|
||||
def set_stroke_color(self, color):
|
||||
self._canvas.setStrokeColor(color)
|
||||
|
||||
def set_fill_color(self, color):
|
||||
self._canvas.setFillColor(color)
|
||||
|
||||
def set_line_width(self, width):
|
||||
self._canvas.setLineWidth(width)
|
||||
|
||||
def line(self, x1, y1, x2, y2):
|
||||
self._canvas.line(x1, y1, x2, y2)
|
||||
|
||||
def begin_text(self, x=0, y=0, direction=None):
|
||||
return ReportlabText(self._canvas.beginText(x, y, direction))
|
||||
|
||||
def draw_text(self, text):
|
||||
self._canvas.drawText(text._text)
|
||||
|
||||
def draw_image(self, image: Path, x, y, width, height):
|
||||
self._canvas.drawImage(os.fspath(image), x, y, width, height)
|
||||
|
||||
def string_width(self, text, fontname, fontsize):
|
||||
return self._canvas.stringWidth(text, fontname, fontsize)
|
||||
|
||||
def set_dashes(self, dashes):
|
||||
self._canvas.setDash(*dashes)
|
||||
|
||||
def save(self):
|
||||
self._canvas.showPage()
|
||||
self._canvas.save()
|
||||
|
||||
|
||||
class ReportlabText(BaseText):
|
||||
def __init__(self, text: PDFTextObject):
|
||||
self._text = text
|
||||
|
||||
def set_font(self, font, size):
|
||||
self._text.setFont(font, size)
|
||||
|
||||
def set_render_mode(self, mode):
|
||||
self._text.setTextRenderMode(mode)
|
||||
|
||||
def set_text_transform(self, a, b, c, d, e, f):
|
||||
return self._text.setTextTransform(a, b, c, d, e, f)
|
||||
|
||||
def show(self, text):
|
||||
return self._text.textOut(text)
|
||||
|
||||
def set_horiz_scale(self, scale):
|
||||
return self._text.setHorizScale(scale)
|
||||
|
||||
def get_start_of_line(self):
|
||||
return self._text.getStartOfLine()
|
||||
|
||||
def move_cursor(self, x, y):
|
||||
return self._text.moveCursor(x, y)
|
||||
@@ -0,0 +1,13 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
Color = namedtuple('Color', ['red', 'green', 'blue', 'alpha'])
|
||||
|
||||
BLACK = Color(0, 0, 0, 1)
|
||||
WHITE = Color(1, 1, 1, 1)
|
||||
BLUE = Color(0, 0, 1, 1)
|
||||
CYAN = Color(0, 1, 1, 1)
|
||||
GREEN = Color(0, 1, 0, 1)
|
||||
MAGENTA = Color(1, 0, 1, 1)
|
||||
RED = Color(1, 0, 0, 1)
|
||||
Reference in New Issue
Block a user