Last active
May 2, 2026 22:52
-
-
Save v--/d87f71cd8736232bd3f66b55aefd21c8 to your computer and use it in GitHub Desktop.
A script to rescale all pages of a PDF file that are larger than the given reference page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env -S uv run --script | |
| # /// script | |
| # requires-python = ">=3.10" | |
| # dependencies = [ | |
| # "click (>= 7.0)", | |
| # "pypdf (>= 6.0)", | |
| # ] | |
| # /// | |
| import pathlib | |
| import click | |
| from pypdf import PdfReader, PdfWriter | |
| class ScalePdfError(click.ClickException): | |
| pass | |
| @click.command(help='Scale all pages of a PDF file to match a target width.') | |
| @click.argument('src', type=click.Path(exists=True, readable=True, dir_okay=False, resolve_path=True, path_type=pathlib.Path)) | |
| @click.option('-o', '--output', type=click.Path(exists=False, resolve_path=True, path_type=pathlib.Path), help='Output file path.') | |
| @click.option('-w', '--width', 'ref_width', type=click.FloatRange(min=1.0), help='Manually set the target page width.') | |
| @click.option('-r', '--ref', type=click.IntRange(min=1), help='Use the width of a reference page.') | |
| @click.option('-v', '--verbose', is_flag=True, help='Display information for every page.') | |
| @click.option('-i', '--inline', is_flag=True, help='Use the source file as a destination.') | |
| @click.option('-f', '--force', is_flag=True, help='Overwrite the destination file if it exists.') | |
| @click.version_option(version='2.0') | |
| def scalepdf( | |
| src: pathlib.Path, | |
| output: pathlib.Path | None, | |
| ref_width: float | None, | |
| ref: int | None, | |
| verbose: bool, | |
| inline: bool, | |
| force: bool, | |
| ) -> None: | |
| reader = PdfReader(src) | |
| if ref is not None: | |
| if ref_width is not None: | |
| raise ScalePdfError('Cannot specify both width and reference page') | |
| if ref >= len(reader.pages): | |
| raise ScalePdfError(f'Reference page {ref} not found') | |
| ref_page = reader.pages[ref - 1] | |
| ref_width = ref_page.user_unit * ref_page.mediabox[2] | |
| elif ref_width is None: | |
| raise ScalePdfError('No width nor reference page specified') | |
| if output is None and not inline: | |
| raise ScalePdfError('No output path given and the inline option is not activated') | |
| if ( | |
| output and output.exists() and | |
| not (force or click.confirm(f'File already exists: {output.as_posix()}. Overwrite?')) | |
| ): | |
| return | |
| writer = PdfWriter() | |
| writer.clone_reader_document_root(reader) | |
| if reader.metadata is not None: | |
| writer.add_metadata(reader.metadata) | |
| last_scaling_factor: float | None = None | |
| for i, page in enumerate(writer.pages, start=1): | |
| page_width = page.mediabox[2] | |
| factor = round(ref_width / page_width, 3) | |
| if factor != last_scaling_factor: | |
| if factor == 1: | |
| click.echo(f'Not using scaling starting at page {i}') | |
| else: | |
| click.echo(f'Using new scaling factor {100 * factor:.1f}% starting at page {i}') | |
| last_scaling_factor = factor | |
| if factor != 1: | |
| if verbose: | |
| click.echo(f'Scaling page {i} by {100 * factor:.1f}%') | |
| page.scale_by(factor) | |
| elif verbose: | |
| click.echo(f'No need to rescale page {i}') | |
| writer.write(output or src) | |
| if __name__ == '__main__': | |
| scalepdf() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment