Performing OCR on Japanese PDFs Using Tesseract and Pytesseract

Performing OCR on Japanese PDFs Using Tesseract and Pytesseract

Extracting Japanese text from a PDF with Tesseract OCR v4 and pytesseract, including the normalization step needed to clean up the output.

Takahiro Iwasa
4 min read

Tesseract OCR v4 and its Python wrapper pytesseract can extract Japanese text from PDFs.

The source text is Run, Melos! by Osamu Dazai, a work that is now in the public domain.

Requirements

Before we start, ensure the following libraries are installed:

Additionally, Tesseract OCR itself must be installed. In this note, it is set up using Docker. Please refer to the instructions on the official repository for more details.

Building

Writing Python Script

app.py
import re
from datetime import datetime
import pdf2image
import pytesseract
def to_images(pdf_path: str, first_page: int = None, last_page: int = None) -> list:
""" Convert a PDF to a PNG image.
Args:
pdf_path (str): PDF path
first_page (int): First page starting 1 to be converted
last_page (int): Last page to be converted
Returns:
list: List of image data
"""
print(f'Convert a PDF ({pdf_path}) to a png...')
images = pdf2image.convert_from_path(
pdf_path=pdf_path,
fmt='png',
first_page=first_page,
last_page=last_page,
)
print(f'A total of converted png images is {len(images)}.')
return images
def to_string(image) -> str:
""" OCR an image data.
Args:
image: Image data
Returns:
str: OCR processed characters
"""
print(f'Extract characters from an image...')
return pytesseract.image_to_string(image, lang='jpn')
def normalize(target: str) -> str:
""" Normalize result text.
Applying the following:
- Remove new line.
- Remove spaces between Japanese characters.
Args:
target (str): Target text to be normalized
Returns:
str: Normalized text
"""
result = re.sub('\n', '', target)
result = re.sub('([あ-んア-ン一-鿐])\s+((?=[あ-んア-ン一-鿐]))', r'\1\2', result)
return result
def save(result: str) -> str:
""" Save the result text in a text file.
Args:
result (str): Result text
Returns:
str: Text file path
"""
path = 'result.txt'
with open(path, 'w') as f:
f.write(result)
return path
def main() -> None:
start = datetime.now()
result = ''
images = to_images('run-melos.pdf', 1, 2)
for image in images:
result += to_string(image)
result = normalize(result)
path = save(result)
end = datetime.now()
duration = end.timestamp() - start.timestamp()
print('----------------------------------------')
print(f'Start: {start}')
print(f'End: {end}')
print(f'Duration: {int(duration)} seconds')
print(f'Result file path: {path}')
print('----------------------------------------')
if __name__ == '__main__':
main()

Creating Dockerfile

The run-melos.pdf on line 6 can be downloaded here.

Dockerfile
FROM python:3.10
WORKDIR /usr/src/app
COPY app.py ./
COPY requirements.txt ./
COPY run-melos.pdf ./
RUN apt update && apt install -y poppler-utils tesseract-ocr tesseract-ocr-jpn \
&& pip install -r requirements.txt
CMD ["python", "app.py"]
# CMD ["/bin/sh", "-c", "while :; do sleep 10; done"]

Testing

The script converts the PDF to PNG image data with pdf2image, extracts characters from the images with Tesseract OCR and pytesseract, and saves the result to a text file:

Terminal window
NAME=pytesseract-sample
docker build -t $NAME .
docker run --name $NAME $NAME
# You can see OCR processing result in `result.txt`.
docker cp $NAME:/usr/src/app/result.txt ./
less result.txt
# Clean up
docker container rm $NAME
docker image rm $NAME

Result

The result can be downloaded from:

Conclusion

Running a public-domain Japanese PDF through pdf2image and Tesseract in a Docker container extracted readable text that closely matched the original. The lang='jpn' argument to pytesseract.image_to_string is what activates Tesseract’s Japanese-trained model, but getting readable output also depends on the normalize step’s regex, which strips the whitespace Tesseract tends to insert between Japanese characters — without it, the extracted text reads as fragmented even when the underlying recognition is accurate. Comparing the result against the original text of Run, Melos! is worth doing directly rather than skimming, since misreads between visually similar kanji can slip past a quick check. Because this PDF is a clean, digitally rendered public-domain text rather than a scan, accuracy here represents close to a best case — lower-resolution or scanned source material would likely need image preprocessing before OCR to get comparable results.

About the author

Takahiro Iwasa

Takahiro Iwasa

Software Developer

This blog shares technical notes from hands-on projects—architecture, implementation, and AWS service integrations.