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
3 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

Install the following Python libraries:

Tesseract OCR itself is also required. This example installs it in a Docker image; see the official repository for other installation options.

Implementation

Writing the 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 the 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 uses pdf2image to convert the PDF pages into PNG image data, extracts text with Tesseract OCR through 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

Processing a public-domain Japanese PDF with pdf2image and Tesseract in a Docker container produced readable text that closely matched the original.

The lang='jpn' argument to pytesseract.image_to_string activates Tesseract’s Japanese trained-data file. The regular expression in normalize is also important: it removes whitespace that Tesseract tends to insert between Japanese characters, which would otherwise make accurate output look fragmented.

Compare the result directly with the original text of Run, Melos! because a quick review can miss substitutions between visually similar kanji.

Because this PDF contains clean, digitally rendered text rather than scanned pages, the accuracy is close to a best-case result. Lower-resolution or scanned material would likely require image preprocessing before OCR.

About the author

Takahiro Iwasa

Takahiro Iwasa

Software Developer

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