Compare commits

...
7 Commits
7 changed files with 33 additions and 19 deletions
+1
View File
@@ -133,6 +133,7 @@ jobs:
ghostscript \ ghostscript \
jbig2enc \ jbig2enc \
openjpeg \ openjpeg \
openssl \
pngquant \ pngquant \
tesseract tesseract
+6 -6
View File
@@ -12,12 +12,12 @@ OCRmyPDF is also available in Docker images that packages recent
versions of all dependencies. versions of all dependencies.
For users who already have Docker installed this may be an easy and For users who already have Docker installed this may be an easy and
convenient option. However, it is less performant than a system convenient option.
installation and may require Docker engine configuration. OCRmyPDF
needs a generous amount of RAM, CPU cores, temporary storage On platforms other than Linux, Docker runs in a virtual machine, and so may
space, whether running in a Docker container or on its own. It may be be less performant. You may also want to adjust the Docker virtual machine's
necessary to ensure the container is provisioned with additional memory and CPU allocation. On Linux, the Docker image runs natively and
resources. performance is comparable to a system installation.
.. _docker-install: .. _docker-install:
+7
View File
@@ -28,6 +28,13 @@ tagged yet.
.. |OCRmyPDF PyPI| image:: https://img.shields.io/pypi/v/ocrmypdf.svg .. |OCRmyPDF PyPI| image:: https://img.shields.io/pypi/v/ocrmypdf.svg
v15.3.1
=======
- Fixed an issue with logging settings for misc/watcher.py introduced in the
previous release. :issue:`1180`
- Updated documentation on Docker performance concerns.
v15.3.0 v15.3.0
======= =======
+3 -3
View File
@@ -260,12 +260,12 @@ def main(
ocrmypdf.configure_logging( ocrmypdf.configure_logging(
verbosity=( verbosity=(
ocrmypdf.Verbosity.default ocrmypdf.Verbosity.default
if loglevel != 'DEBUG' if loglevel != LoggingLevelEnum.DEBUG
else ocrmypdf.Verbosity.debug else ocrmypdf.Verbosity.debug
), ),
manage_root_logger=True, manage_root_logger=True,
) )
log.setLevel(loglevel) log.setLevel(loglevel.value)
log.info( log.info(
f"Starting OCRmyPDF watcher with config:\n" f"Starting OCRmyPDF watcher with config:\n"
f"Input Directory: {input_dir}\n" f"Input Directory: {input_dir}\n"
@@ -285,7 +285,7 @@ def main(
f"POLL_NEW_FILE_SECONDS: {poll_new_file_seconds}\n" f"POLL_NEW_FILE_SECONDS: {poll_new_file_seconds}\n"
f"RETRIES_LOADING_FILE: {retries_loading_file}\n" f"RETRIES_LOADING_FILE: {retries_loading_file}\n"
f"USE_POLLING: {use_polling}\n" f"USE_POLLING: {use_polling}\n"
f"LOGLEVEL: {loglevel}" f"LOGLEVEL: {loglevel.value}"
) )
json_settings = json.loads(ocr_json_settings.read() if ocr_json_settings else '{}') json_settings = json.loads(ocr_json_settings.read() if ocr_json_settings else '{}')
+3 -2
View File
@@ -7,6 +7,7 @@ from __future__ import annotations
import logging import logging
import re import re
from contextlib import suppress
from math import pi from math import pi
from os import fspath from os import fspath
from pathlib import Path from pathlib import Path
@@ -350,7 +351,7 @@ def generate_hocr(
tesseract_log_output(stdout) tesseract_log_output(stdout)
# The sidecar text file will get the suffix .txt; rename it to # The sidecar text file will get the suffix .txt; rename it to
# whatever caller wants it named # whatever caller wants it named
if prefix.with_suffix('.txt').exists(): with suppress(FileNotFoundError):
prefix.with_suffix('.txt').replace(output_text) prefix.with_suffix('.txt').replace(output_text)
@@ -406,7 +407,7 @@ def generate_pdf(
try: try:
p = run(args_tesseract, stdout=PIPE, stderr=STDOUT, timeout=timeout, check=True) p = run(args_tesseract, stdout=PIPE, stderr=STDOUT, timeout=timeout, check=True)
stdout = p.stdout stdout = p.stdout
if prefix.with_suffix('.txt').exists(): with suppress(FileNotFoundError):
prefix.with_suffix('.txt').replace(output_text) prefix.with_suffix('.txt').replace(output_text)
except TimeoutExpired: except TimeoutExpired:
page_timedout(timeout) page_timedout(timeout)
+11 -5
View File
@@ -14,7 +14,7 @@ from collections.abc import Iterable, Iterator, Sequence
from contextlib import suppress from contextlib import suppress
from datetime import datetime, timezone from datetime import datetime, timezone
from pathlib import Path from pathlib import Path
from shutil import copyfileobj from shutil import copyfileobj, copystat
from typing import Any, BinaryIO, TypeVar, cast from typing import Any, BinaryIO, TypeVar, cast
import img2pdf import img2pdf
@@ -1090,14 +1090,14 @@ def merge_sidecars(txt_files: Iterable[Path | None], context: PdfContext) -> Pat
def copy_final( def copy_final(
input_file: Path, output_file: str | Path | BinaryIO, _context: PdfContext input_file: Path, output_file: str | Path | BinaryIO, context: PdfContext
) -> None: ) -> None:
"""Copy the final temporary file to the output destination. """Copy the final temporary file to the output destination.
Args: Args:
input_file (Path): The input file to copy. input_file (Path): The intermediate input file to copy.
output_file (str | Path | BinaryIO): The output file to copy to. output_file (str | Path | BinaryIO): The output file to copy to.
_context (PdfContext): The PDF context. context (PdfContext): The PDF context.
Returns: Returns:
None None
@@ -1116,5 +1116,11 @@ def copy_final(
# At this point we overwrite the output_file specified by the user # At this point we overwrite the output_file specified by the user
# use copyfileobj because then we use open() to create the file and # use copyfileobj because then we use open() to create the file and
# get the appropriate umask, ownership, etc. # get the appropriate umask, ownership, etc.
with open(output_file, 'wb') as output_stream: with open(output_file, 'w+b') as output_stream:
copyfileobj(input_stream, output_stream) copyfileobj(input_stream, output_stream)
# Attempt to copy file attributes from input to output
with suppress(OSError):
# Copy original file's permissions, ownership, etc. if possible
copystat(context.options.input_file, output_file)
# Set output file's modification time to now
Path(output_file).touch(exist_ok=True)
+2 -3
View File
@@ -25,9 +25,8 @@ def is_macos():
def running_in_docker(): def running_in_docker():
# Docker creates a file named /.dockerenv (newer versions) or # Docker creates a file named /.dockerenv in all supported versions
# /.dockerinit (older) -- this is undocumented, not an offical test return Path('/.dockerenv').exists()
return Path('/.dockerenv').exists() or Path('/.dockerinit').exists()
def have_unpaper(): def have_unpaper():