主な目的は、bord のソースコードをさらに追跡し、そのレイヤー描画プロセスを理解することです. PDF 形式の仕様
を理解する必要があります. 関連コンテンツ準備: (Mac 環境)
- Python仮想環境を生成する
$ python3.9 -m venv ./venv
$ cd venv/bin
#进入bin目录,激活环境
$ source activate
- 使用されているライブラリをいくつかダウンロードします
catrequirements.txt
borb==2.1.7
certifi==2022.12.7
charset-normalizer==2.1.1
fonttools==4.38.0
idna==3.4
lxml==4.9.2
packaging==22.0
Pillow==9.3.0
pytesseract==0.3.10
python-barcode==0.14.0
qrcode==7.3.1
requests==2.28.1
urllib3==1.26.13
$ pip install -r requirements.txt -i https://mirrors.ustc.edu.cn/pypi/web/simple/
- この
記事はデモの実行に使用されており、ここに再配置されています。
import typing
from pathlib import Path
import requests
from decimal import Decimal
from io import BytesIO
from PIL import Image as PILImage # Type: ignore [import]
from PIL import ImageDraw, ImageFont
from pathlib import Path
from borb.toolkit.ocr.ocr_as_optional_content_group import OCRAsOptionalContentGroup
from borb.toolkit.text.simple_text_extraction import SimpleTextExtraction
from borb.pdf.canvas.layout.layout_element import Alignment
import typing
# New imports
from borb.pdf.canvas.layout.image.image import Image
from borb.pdf import (
Document,
SingleColumnLayout,
Paragraph,
PageLayout,
Page,
PDF,
)
def download_image() -> PILImage:
req=requests.get("https://xxx/2022/11/ba916990aaa049a78fc1a5cb7a606924.png")
image: PILImage = PILImage.open(BytesIO(req.content))
w, h = image.size
lower = image.format.lower()
image.save('pic/'+'42345234'+'.'+lower)
return image
def load_image() -> PILImage:
image = PILImage.open('pic/44444.png')
w, h = image.size
print(image.size)
print(int(w/3), int(h/3))
image = image.resize((int(image.width/3), int(image.height/3)), PILImage.ANTIALIAS)
return image
def create_image() -> PILImage:
# Create new Image
img = PILImage.new("RGB", (256, 256), color=(255, 255, 255))
# Create ImageFont
# CAUTION: you may need to adjust the path to your particular font directory
font = ImageFont.truetype("Arial.ttf", 24)
# Draw text
draw = ImageDraw.Draw(img)
draw.text((10, 10),
"Hello World!",
fill=(0, 0, 0),
font=font)
# Return
return img
# Main method to create the document
def create_document():
# Create Document
d: Document = Document()
# Create/add Page
p: Page = Page()
d.add_page(p)
# Set PageLayout
l: PageLayout = SingleColumnLayout(p)
# Add Paragraph
l.add(Paragraph("Lorem Ipsum"))
# Add Image
l.add(Image(create_image()))
# l.add(Image(load_image()))
# l.add(Image(download_image()))
# l.add(Image(
# "https://xxx/licenseTest/2022/11/ba916990aaa049a78fc1a5cb7a606924.png",
# width=Decimal(256),
# height=Decimal(256),
# horizontal_alignment=Alignment.CENTERED,
# ))
# Write
with open("output_001.pdf", "wb") as pdf_file_handle:
PDF.dumps(pdf_file_handle, d)
def apply_ocr_to_document():
# Set up everything for OCR
tesseract_data_dir: Path = Path("tessdata/")
assert tesseract_data_dir.exists()
l: OCRAsOptionalContentGroup = OCRAsOptionalContentGroup(tesseract_data_dir)
# Read Document
doc: typing.Optional[Document] = None
with open("output_001.pdf", "rb") as pdf_file_handle:
doc = PDF.loads(pdf_file_handle, [l])
assert doc is not None
# print(doc)
# Store Document
with open("output_002.pdf", "wb") as pdf_file_handle:
PDF.dumps(pdf_file_handle, doc)
def read_modified_document():
doc: typing.Optional[Document] = None
l: SimpleTextExtraction = SimpleTextExtraction()
with open("output_002.pdf", "rb") as pdf_file_handle:
doc = PDF.loads(pdf_file_handle, [l])
print(l.get_text()[0])
def main():
# load_image()
# download_image()
create_document()
apply_ocr_to_document()
# read_modified_document()
if __name__ == "__main__":
main()
- 外部から画像をロードする場合、幅/高さが大きすぎることはできません。大きすぎると、bord がエラーを報告します。
Image("https://xxx/licenseTest/2022/11/ba916990aaa049a78fc1a5cb7a606924.png",
width=Decimal(256),
height=Decimal(256),
horizontal_alignment=Alignment.CENTERED,)
-
上記のデモの tessdata は github から取得する必要があります
-
操作が成功すると、2 つの PDF ファイルが生成されるので、2 番目の出力_002.pdf を開くと、画像のテキストをコピーできます。
-
OCRAsOptionalContentGroup オブジェクトはレイヤーを処理します
。OCRAsOptionalContentGroup が初期化されると、tessdata に加えて、最小信頼レベルもデフォルトで minimum_confidence=0.75 に設定されます。画像が認識された後、信頼レベルが判断されます
ChunkOfText(e.get_text(),
e.get_font(),
e.get_font_size(),
e.get_font_color()).paint(page, e.get_bounding_box())
ChunkOfText 形式: borb/pdf/canvas/layout/text/chunk_of_text.py
ペイント形式: borb/pdf/canvas/layout/layout_element.py
レンダリング前に出力されるログ:テキスト内容(認識結果)、レンダリング位置、その他必要な情報がPDF形式で出力されます。
q
BT
0.937255 0.937255 0.937255 rg
/F1 1.000000 Tf
22.000000 0 0 22.000000 76.500000 691.554000 Tm
(Hello) Tj
ET
Q
q
BT
0.937255 0.937255 0.937255 rg
/F1 1.000000 Tf
23.000000 0 0 23.000000 135.500000 690.761000 Tm
(World!) Tj
ET
Q
_add_ocr_optional_content_group メソッド、名前を参照: OCG レイヤーを PDF に追加
- bord は中国語の描画をサポートしていません。次の lang="eng" では、中国語を追加すると、認識が成功した後、描画が失敗します。
data = pytesseract.image_to_data(
event.get_image(),
lang="eng",
config='--tessdata-dir "%s"' % str(self._tesseract_data_dir.absolute()),
output_type=Output.DICT,
)
データ形式は次のとおりです。
{
'level': [1, 2, 3, 4, 5, 5], 'page_num': [1, 1, 1, 1, 1, 1], 'block_num': [0, 1, 1, 1, 1, 1], 'par_num': [0, 0, 1, 1, 1, 1], 'line_num': [0, 0, 0, 1, 1, 1], 'word_num': [0, 0, 0, 0, 1, 2], 'left': [0, 12, 12, 12, 12, 71], 'top': [0, 15, 15, 15, 15, 15], 'width': [256, 127, 127, 127, 52, 68], 'height': [256, 17, 17, 17, 17, 17], 'conf': [-1, -1, -1, -1, 84, 68], 'text': ['', '', '', '', 'Hello', 'Worldl']}
- 呼び出しチェーン: _event_occurred 関数で、pytesseract を実行し、結果をドキュメントとして返します。
# 1. pdf.py
doc = PDF.loads(pdf_file_handle, [l])
# 2. borb/pdf/pdf.py, line 56
return ReadAnyObjectTransformer().transform(
file,
parent_object=None,
context=ReadTransformerState(password=password),
event_listeners=event_listeners,
)
#3. borb/io/read/any_object_transformer.py, line 100,
return super().transform(
object_to_transform, parent_object, context, event_listeners
)
#4. borb/io/read/transformer.py, line 124
out = h.transform(
object_to_transform,
parent_object=parent_object,
context=context,
event_listeners=event_listeners,
)
#5. borb/io/read/reference/xref_transformer.py, line 77
l._event_occurred(BeginDocumentEvent())
#6. borb/toolkit/ocr/ocr_as_optional_content_group.py, line 145
def _event_occurred(self, event: Event) -> None:
...
- 詳細は追加予定です...