modm_data.pdf.render

  1# Copyright 2022, Niklas Hauser
  2# SPDX-License-Identifier: MPL-2.0
  3
  4import math
  5import ctypes
  6from ..utils import VLine, HLine
  7import pypdfium2 as pp
  8
  9def _vline(pageobj, rotation, x, y0, y1, **kw):
 10    _line(pageobj, rotation, VLine(x, y0, y1), **kw)
 11
 12def _hline(pageobj, rotation, y, x0, x1, **kw):
 13    _line(pageobj, rotation, HLine(y, x0, x1), **kw)
 14
 15def _line(pageobj, rotation, line, **kw):
 16    if rotation:
 17        obj = pp.raw.FPDFPageObj_CreateNewPath(height - line.p0.y, line.p0.x)
 18        assert pp.raw.FPDFPath_LineTo(obj, height - line.p1.y, line.p1.x)
 19    else:
 20        obj = pp.raw.FPDFPageObj_CreateNewPath(line.p0.x, line.p0.y)
 21        assert pp.raw.FPDFPath_LineTo(obj, line.p1.x, line.p1.y)
 22    if fill := kw.get("fill"):
 23        assert pp.raw.FPDFPageObj_SetFillColor(obj, (fill >> 16) & 0xff, (fill >> 8) & 0xff, fill & 0xff, 0xC0)
 24    if stroke := kw.get("stroke"):
 25        assert pp.raw.FPDFPageObj_SetStrokeColor(obj, (stroke >> 16) & 0xff, (stroke >> 8) & 0xff, stroke & 0xff, 0xC0)
 26    if width := kw.get("width"):
 27        assert pp.raw.FPDFPageObj_SetStrokeWidth(obj, width)
 28    assert pp.raw.FPDFPath_SetDrawMode(obj, 1 if kw.get("fill") else 0,
 29                                   kw.get("width") is not None)
 30    pp.raw.FPDFPage_InsertObject(pageobj, obj)
 31
 32def _rect(pageobj, rotation, rect, **kw):
 33    if rotation:
 34        obj = pp.raw.FPDFPageObj_CreateNewRect(
 35                height - rect.bottom - rect.height, rect.left, rect.height, rect.width)
 36    else:
 37        obj = pp.raw.FPDFPageObj_CreateNewRect(rect.left, rect.bottom, rect.width, rect.height)
 38    if fill := kw.get("fill"):
 39        assert pp.raw.FPDFPageObj_SetFillColor(obj, (fill >> 16) & 0xff, (fill >> 8) & 0xff, fill & 0xff, 0xC0)
 40    if stroke := kw.get("stroke"):
 41        assert pp.raw.FPDFPageObj_SetStrokeColor(obj, (stroke >> 16) & 0xff, (stroke >> 8) & 0xff, stroke & 0xff, 0xC0)
 42    if width := kw.get("width"):
 43        assert pp.raw.FPDFPageObj_SetStrokeWidth(obj, width)
 44    assert pp.raw.FPDFPath_SetDrawMode(obj, 1 if kw.get("fill") else 0,
 45                                   kw.get("width") is not None)
 46    pp.raw.FPDFPage_InsertObject(pageobj, obj)
 47
 48
 49
 50def render_page_pdf(doc, page, new_doc = None, index = 0):
 51    width, height = page.width, page.height
 52
 53    if new_doc is None:
 54        new_doc = pp.raw.FPDF_CreateNewDocument()
 55    # copy page over to new doc
 56    assert pp.raw.FPDF_ImportPages(new_doc, doc, str(page.number).encode("ascii"), index)
 57    new_page = pp.raw.FPDF_LoadPage(new_doc, index)
 58    rotation = page.rotation
 59
 60    for path in page.paths:
 61        p0 = path.points[0]
 62        if rotation: obj = pp.raw.FPDFPageObj_CreateNewPath(height - p0.y, p0.x)
 63        else: obj = pp.raw.FPDFPageObj_CreateNewPath(p0.x, p0.y)
 64        assert pp.raw.FPDFPageObj_SetStrokeColor(obj, 0,0,0xff, 0xC0)
 65        assert pp.raw.FPDFPageObj_SetStrokeWidth(obj, 0.25)
 66        assert pp.raw.FPDFPageObj_SetLineJoin(obj, pp.raw.FPDF_LINEJOIN_ROUND)
 67        assert pp.raw.FPDFPageObj_SetLineCap(obj, pp.raw.FPDF_LINECAP_ROUND)
 68        assert pp.raw.FPDFPath_SetDrawMode(obj, 0, True)
 69        for point in path.points[1:]:
 70            if point.type == path.Type.MOVE:
 71                if rotation: assert pp.raw.FPDFPath_MoveTo(obj, height - point.y, point.x)
 72                else: assert pp.raw.FPDFPath_MoveTo(obj, point.x, point.y)
 73            else:
 74                if rotation: assert pp.raw.FPDFPath_LineTo(obj, height - point.y, point.x)
 75                else: assert pp.raw.FPDFPath_LineTo(obj, point.x, point.y)
 76        pp.raw.FPDFPage_InsertObject(new_page, obj)
 77
 78    for bbox, _ in page.graphic_clusters():
 79        _rect(new_page, rotation, bbox, width=2, stroke=0x00FFFF)
 80
 81    for link in page.objlinks:
 82        _rect(new_page, rotation, link.bbox, width=0.75, stroke=0x9ACD32)
 83
 84    for link in page.weblinks:
 85        for bbox in link.bboxes:
 86            _rect(new_page, rotation, bbox, width=0.75, stroke=0x00ff00)
 87
 88    for char in page.chars:
 89        color = 0x0000ff
 90        if char.bbox.width:
 91            _rect(new_page, rotation, char.bbox, width=0.5, stroke=0xff0000)
 92            _vline(new_page, rotation, char.bbox.midpoint.x, char.bbox.midpoint.y - 1, char.bbox.midpoint.y + 1, width=0.25, stroke=0xff0000)
 93            _hline(new_page, rotation, char.bbox.midpoint.y, char.bbox.midpoint.x - 1, char.bbox.midpoint.x + 1, width=0.25, stroke=0xff0000)
 94            color = 0x000000
 95        _vline(new_page, rotation, char.origin.x, char.origin.y - 1, char.origin.y + 1, width=0.25, stroke=color)
 96        _hline(new_page, rotation, char.origin.y, char.origin.x - 1, char.origin.x + 1, width=0.25, stroke=color)
 97
 98    assert pp.raw.FPDFPage_GenerateContent(new_page)
 99    pp.raw.FPDF_ClosePage(new_page)
100    return new_doc
def render_page_pdf(doc, page, new_doc=None, index=0):
 51def render_page_pdf(doc, page, new_doc = None, index = 0):
 52    width, height = page.width, page.height
 53
 54    if new_doc is None:
 55        new_doc = pp.raw.FPDF_CreateNewDocument()
 56    # copy page over to new doc
 57    assert pp.raw.FPDF_ImportPages(new_doc, doc, str(page.number).encode("ascii"), index)
 58    new_page = pp.raw.FPDF_LoadPage(new_doc, index)
 59    rotation = page.rotation
 60
 61    for path in page.paths:
 62        p0 = path.points[0]
 63        if rotation: obj = pp.raw.FPDFPageObj_CreateNewPath(height - p0.y, p0.x)
 64        else: obj = pp.raw.FPDFPageObj_CreateNewPath(p0.x, p0.y)
 65        assert pp.raw.FPDFPageObj_SetStrokeColor(obj, 0,0,0xff, 0xC0)
 66        assert pp.raw.FPDFPageObj_SetStrokeWidth(obj, 0.25)
 67        assert pp.raw.FPDFPageObj_SetLineJoin(obj, pp.raw.FPDF_LINEJOIN_ROUND)
 68        assert pp.raw.FPDFPageObj_SetLineCap(obj, pp.raw.FPDF_LINECAP_ROUND)
 69        assert pp.raw.FPDFPath_SetDrawMode(obj, 0, True)
 70        for point in path.points[1:]:
 71            if point.type == path.Type.MOVE:
 72                if rotation: assert pp.raw.FPDFPath_MoveTo(obj, height - point.y, point.x)
 73                else: assert pp.raw.FPDFPath_MoveTo(obj, point.x, point.y)
 74            else:
 75                if rotation: assert pp.raw.FPDFPath_LineTo(obj, height - point.y, point.x)
 76                else: assert pp.raw.FPDFPath_LineTo(obj, point.x, point.y)
 77        pp.raw.FPDFPage_InsertObject(new_page, obj)
 78
 79    for bbox, _ in page.graphic_clusters():
 80        _rect(new_page, rotation, bbox, width=2, stroke=0x00FFFF)
 81
 82    for link in page.objlinks:
 83        _rect(new_page, rotation, link.bbox, width=0.75, stroke=0x9ACD32)
 84
 85    for link in page.weblinks:
 86        for bbox in link.bboxes:
 87            _rect(new_page, rotation, bbox, width=0.75, stroke=0x00ff00)
 88
 89    for char in page.chars:
 90        color = 0x0000ff
 91        if char.bbox.width:
 92            _rect(new_page, rotation, char.bbox, width=0.5, stroke=0xff0000)
 93            _vline(new_page, rotation, char.bbox.midpoint.x, char.bbox.midpoint.y - 1, char.bbox.midpoint.y + 1, width=0.25, stroke=0xff0000)
 94            _hline(new_page, rotation, char.bbox.midpoint.y, char.bbox.midpoint.x - 1, char.bbox.midpoint.x + 1, width=0.25, stroke=0xff0000)
 95            color = 0x000000
 96        _vline(new_page, rotation, char.origin.x, char.origin.y - 1, char.origin.y + 1, width=0.25, stroke=color)
 97        _hline(new_page, rotation, char.origin.y, char.origin.x - 1, char.origin.x + 1, width=0.25, stroke=color)
 98
 99    assert pp.raw.FPDFPage_GenerateContent(new_page)
100    pp.raw.FPDF_ClosePage(new_page)
101    return new_doc