diff --git a/README.md b/README.md index 9dd849e..51190b2 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,10 @@ You can also skip translating the text layer (it is sometimes not translated wel dpsprep --ocr '{"language": ["rus", "eng"]}' input.djvu +You can also configure how the outline/toc page numbers in the djvu is translated to page numbers in pdf. Sometimes, their numbering convention is not consistent. For example, when converting djvu whose page numbers are one page ahead of the pdf: + + dpsprep --toc-pg-offset=-1 input.djvu + Consult the man file ([online](./dpsprep.1.ronn)) for details; there are a lot of options to consider. See the next section for different ways to run the program. diff --git a/dpsprep.1.ronn b/dpsprep.1.ronn index 28dbc39..c9b45d8 100644 --- a/dpsprep.1.ronn +++ b/dpsprep.1.ronn @@ -17,7 +17,8 @@ This tool, initially made specifically for use with Sony's Digital Paper System * `-w`, `--preserve-working`: Preserve the working directory after script termination. * `-d`, `--delete-working`: Delete any existing files in the working directory prior to writing to it. * `-t`, `--no-text`: Disable the generation of text layers. Implied by --ocr. -* `--ocr` Perform OCR via OCRmyPDF rather than trying to convert the text layer. If this parameter has a value, it should be a JSON dictionary of options to be passed to OCRmyPDF. +* `--ocr`: Perform OCR via OCRmyPDF rather than trying to convert the text layer. If this parameter has a value, it should be a JSON dictionary of options to be passed to OCRmyPDF. +* `--toc-pg-offset`: Configure the page offset to be applied when translating outline/toc. This is to work with different djvu page numbering (starting from page 0 or page 1). * `-O1`: Use the lossless PDF image optimization from OCRmyPDF (without performing OCR). * `-O2`: Use the PDF image optimization from OCRmyPDF. * `-O3`: Use the aggressive lossy PDF image optimization from OCRmyPDF. diff --git a/dpsprep/dpsprep.py b/dpsprep/dpsprep.py index c92b434..572a4fa 100644 --- a/dpsprep/dpsprep.py +++ b/dpsprep/dpsprep.py @@ -79,9 +79,10 @@ def process_text(workdir: WorkingDirectory): @click.option('-p', '--pool-size', type=click.IntRange(min=0), default=4, help='Size of MultiProcessing pool for handling page-by-page operations.') @click.option('-q', '--quality', type=click.IntRange(min=0, max=100), default=75, help="Quality of images in output. Used only for JPEG compression, i.e. RGB and Grayscale images. Passed directly to Pillow and to OCRmyPDF's optimizer.") @click.option('--ocr', type=str, is_flag=False, flag_value='{}', help='Perform OCR via OCRmyPDF rather than trying to convert the text layer. If this parameter has a value, it should be a JSON dictionary of options to be passed to OCRmyPDF.') +@click.option('--toc-pg-offset', type=int, default=-1, help='The page offset to be applied when translating outline/toc.') @click.argument('dest', type=click.Path(exists=False, resolve_path=True), required=False) @click.argument('src', type=click.Path(exists=True, resolve_path=True), required=True) -@click.command() +@click.command(context_settings={'show_default': True}) def dpsprep( src: str, dest: Union[str, None], @@ -94,6 +95,7 @@ def dpsprep( no_text: bool, optlevel: Union[int, None], ocr: Union[str, None], + toc_pg_offset: int, ): configure_loguru(verbose) workdir = WorkingDirectory(src, dest) @@ -165,7 +167,7 @@ def dpsprep( if len(document.outline.sexpr) > 0: logger.info('Processing metadata.') - outline = OutlineTransformVisitor().visit(document.outline.sexpr) + outline = OutlineTransformVisitor(toc_pg_offset, len(document.pages)).visit(document.outline.sexpr) logger.info('Metadata processed.') else: logger.info('No metadata to process.') diff --git a/dpsprep/outline.py b/dpsprep/outline.py index ce9e2a8..d55d53b 100644 --- a/dpsprep/outline.py +++ b/dpsprep/outline.py @@ -1,6 +1,7 @@ from loguru import logger from pdfrw import PdfName, PdfDict, IndirectPdfDict import djvu.sexpr +import re from .sexpr import SExpressionVisitor @@ -8,16 +9,25 @@ # Based on # https://github.com/pmaupin/pdfrw/issues/52#issuecomment-271190546 class OutlineTransformVisitor(SExpressionVisitor): + def __init__(self, toc_pg_offset: int, total_pages: int): + self.toc_pg_offset = toc_pg_offset + self.total_pages = total_pages + super().__init__() def visit_plain_list(self, node: djvu.sexpr.StringExpression, parent: IndirectPdfDict): title, page, *rest = node - # I have experimentally determined that we need to translate page indices. -- Ianis, 2023-05-03 - try: - page_number = int(page.value[1:]) - 1 - except ValueError: - # As far as I understand, python-djvulibre doesn't support Djvu's page titles. -- Ianis, 2023-12-09 + + # Translate the first valid number in the page title to be the page indices. + m = re.search(r'[0-9]+', page.value) + if m is not None: + page_number = int(m.group(0), base=10) + self.toc_pg_offset + else: logger.warning(f'Could not determine page number from the page title {page.value}.') return + if page_number < 0 or page_number >= self.total_pages: + logger.warning(f'Refuse to translate the page title \'{page.value}\' to an invalid number {page_number}.') + return + bookmark = IndirectPdfDict( Parent = parent, Title = title.value,