{"owner":"ocrmypdf","repo":"OCRmyPDF","hasSkills":true,"totalSkillsCount":1,"totalTokensCount":1878,"categories":["project-spec"],"hasMcp":false,"mcpConfig":null,"found":["docs/api.md"],"skills":{"docs/api.md":"% SPDX-FileCopyrightText: 2022 James R. Barlow\n% SPDX-License-Identifier: CC-BY-SA-4.0\n\n# Using the OCRmyPDF API\n\nOCRmyPDF originated as a command line program and continues to have this\nlegacy, but parts of it can be imported and used in other Python\napplications.\n\nSome applications may want to consider running ocrmypdf from a\nsubprocess call anyway, as this provides isolation of its activities.\n\n## Example\n\nOCRmyPDF provides one high-level function to run its main engine from an\napplication.\n\n```{versionchanged} 17.0\nThe {func}`ocrmypdf.ocr` function now accepts an {class}`~ocrmypdf.OcrOptions`\nobject as its first argument, providing a cleaner API with full type hints\nand validation. The previous positional argument style remains supported.\n```\n\n### Modern API (recommended)\n\nThe recommended way to call {func}`ocrmypdf.ocr` is to construct an\n{class}`~ocrmypdf.OcrOptions` object with all settings, then pass it\nas the sole argument:\n\n```python\nimport ocrmypdf\nfrom ocrmypdf import OcrOptions\n\nif __name__ == '__main__':  # To ensure correct behavior on Windows and macOS\n    options = OcrOptions(\n        input_file='input.pdf',\n        output_file='output.pdf',\n        deskew=True,\n        languages=['eng'],\n    )\n    ocrmypdf.ocr(options)\n```\n\n{class}`~ocrmypdf.OcrOptions` is a Pydantic model that provides:\n\n- Full type hints and IDE autocompletion\n- Validation of option values at construction time\n- Clear documentation of all available options\n\n```{versionadded} 17.0\nThe {class}`~ocrmypdf.OcrOptions` class is now exported from the top-level\n`ocrmypdf` module.\n```\n\n### Legacy API\n\nFor compatibility with OCRmyPDF < v17, the traditional calling style\nwith positional arguments is still fully supported:\n\n```python\nimport ocrmypdf\n\nif __name__ == '__main__':  # To ensure correct behavior on Windows and macOS\n    ocrmypdf.ocr('input.pdf', 'output.pdf', deskew=True)\n```\n\nWith this style, all of the command line arguments are available\nand may be passed as equivalent keywords.\n\nA few differences are that `verbose` and `quiet` are not available.\nInstead, output should be managed by configuring logging.\n\n### Parent process requirements\n\nThe {func}`ocrmypdf.ocr` function runs OCRmyPDF similar to command line\nexecution. To do this, it will:\n\n- create worker processes or threads\n- manage the signal flags of its worker processes\n- execute other subprocesses (forking and executing other programs)\n\nThe Python process that calls {func}`ocrmypdf.ocr()` must be sufficiently\nprivileged to perform these actions.\n\nThere currently is no option to manage how jobs are scheduled other\nthan the argument `jobs=` which will limit the number of worker\nprocesses.\n\nCreating a child process to call {func}`ocrmypdf.ocr()` is suggested. That\nway your application will survive and remain interactive even if\nOCRmyPDF fails for any reason. For example:\n\n```python\nfrom multiprocessing import Process\nimport ocrmypdf\nfrom ocrmypdf import OcrOptions\n\n\ndef ocrmypdf_process():\n    options = OcrOptions(input_file='input.pdf', output_file='output.pdf')\n    ocrmypdf.ocr(options)\n\n\ndef call_ocrmypdf_from_my_app():\n    p = Process(target=ocrmypdf_process)\n    p.start()\n    p.join()\n```\n\nPrograms that call {func}`ocrmypdf.ocr()` should also install a SIGBUS signal\nhandler (except on Windows), to raise an exception if access to a memory\nmapped file fails. OCRmyPDF may use memory mapping.\n\nSeveral OCR jobs may run concurrently in the same Python interpreter process.\n\nInstalling a plugin set mutates interpreter-global state, because of how OCRmyPDF's\nplugins and Python's library import system work, and a running job cannot survive\nthat state being replaced underneath it. {func}`ocrmypdf.ocr()` therefore takes a\nreaders-writer lock: installing a plugin set takes it exclusively, so it waits for\nevery job already running, while a job holds it shared for its own run. A plugin set\nis installed once per interpreter and reused thereafter, so a job that asks for a\nplugin set some earlier job already installed never blocks.\n\nThe practical consequence is that concurrent jobs should all use the same plugin\nset. Jobs requesting different plugin sets serialize against each other. They must\nalso use the same `max_image_mpixels`, since Pillow's decompression-bomb limit is\ninterpreter-global and the last job to set it wins. If you need to run jobs with\ndiffering configurations, use separate processes.\n\nBecause a plugin set is installed only once, a plugin module given as a file path is\nexecuted once per interpreter rather than once per call. Plugins must not rely on\nbeing re-executed for each job, and must not store per-job state on the plugin\nmanager, which concurrent jobs may share.\n\nNote that N concurrent jobs each configured with `jobs=M` may spawn up to N*M\nworkers, so size `jobs` accordingly.\n\n:::{warning}\nOn Windows and macOS, the script that calls {func}`ocrmypdf.ocr()` must be\nprotected by an \"ifmain\" guard (`if __name__ == '__main__'`). If you do\nnot take at least one of these steps, process semantics will prevent\nOCRmyPDF from working correctly.\n:::\n\n### Logging\n\nOCRmyPDF will log under loggers named `ocrmypdf`. In addition, it\nimports `pdfminer` and `PIL`, both of which post log messages under\nthose logging namespaces.\n\nYou can configure the logging as desired for your application or call\n{func}`ocrmypdf.configure_logging` to configure logging the same way\nOCRmyPDF itself does. The command line parameters such as `--quiet`\nand `--verbose` have no equivalents in the API; you must use the\nprovided configuration function or do configuration in a way that suits\nyour use case.\n\n### Progress monitoring\n\nOCRmyPDF uses the `rich` package to implement its progress bars.\n{func}`ocrmypdf.configure_logging` will set up logging output to\n`sys.stderr` in a way that is compatible with the display of the\nprogress bar. Use `ocrmypdf.ocr(...progress_bar=False)` to disable\nthe progress bar.\n\n### Standard output\n\nOCRmyPDF is strict about not writing to standard output so that\nusers can safely use it in a pipeline and produce a valid output\nfile. A caller application will have to ensure it does not write to\nstandard output either, if it wants to be compatible with this\nbehavior and support piping to a file. Another benefit of running\nOCRmyPDF in a child process, as recommended above, is that it will\nnot interfere with the parent process's standard output.\n\n### Exceptions\n\nOCRmyPDF may throw standard Python exceptions, `ocrmypdf.exceptions.*`\nexceptions, some exceptions related to multiprocessing, and\n{exc}`KeyboardInterrupt`. The parent process should provide an exception\nhandler. OCRmyPDF will clean up its temporary files and worker processes\nautomatically when an exception occurs.\n\nWhen OCRmyPDF succeeds conditionally, it returns an integer exit code.\n\n### Bundling with PyInstaller\n\nOCRmyPDF ships a PyInstaller hook, which PyInstaller finds automatically,\nso applications that call {func}`ocrmypdf.ocr` can be frozen without extra\n`--collect-*` options. The hook bundles OCRmyPDF's builtin plugins, fonts\nand color profiles, and the pikepdf data needed for PDF/A output.\n\nThe external programs are not bundled. Tesseract and Ghostscript must still\nbe installed on the target machine and be on the `PATH`, as must any optional\ntools you use, such as unpaper or pngquant. Third party plugins must be\nbundled by your application.\n\nLike any frozen application that uses multiprocessing, call\n{func}`multiprocessing.freeze_support` at the start of your\n`if __name__ == '__main__':` block.\n\n### Plugin Development Changes\n\n```{versionchanged} 16.13\nPlugin hooks now receive {class}`~ocrmypdf.OcrOptions` objects instead of\n`argparse.Namespace`.\n```\n\n- {class}`~ocrmypdf.OcrOptions` provides the same attribute access as `Namespace` (duck-typing compatible)\n- Plugin developers should update type hints: `from ocrmypdf import OcrOptions`\n- Built-in plugins no longer modify options in-place for better immutability\n\nMost existing plugins will continue working without modification due to the\nduck-typing compatibility between {class}`~ocrmypdf.OcrOptions` and `Namespace`.\n"},"files":{"docs/api.md":"% SPDX-FileCopyrightText: 2022 James R. Barlow\n% SPDX-License-Identifier: CC-BY-SA-4.0\n\n# Using the OCRmyPDF API\n\nOCRmyPDF originated as a command line program and continues to have this\nlegacy, but parts of it can be imported and used in other Python\napplications.\n\nSome applications may want to consider running ocrmypdf from a\nsubprocess call anyway, as this provides isolation of its activities.\n\n## Example\n\nOCRmyPDF provides one high-level function to run its main engine from an\napplication.\n\n```{versionchanged} 17.0\nThe {func}`ocrmypdf.ocr` function now accepts an {class}`~ocrmypdf.OcrOptions`\nobject as its first argument, providing a cleaner API with full type hints\nand validation. The previous positional argument style remains supported.\n```\n\n### Modern API (recommended)\n\nThe recommended way to call {func}`ocrmypdf.ocr` is to construct an\n{class}`~ocrmypdf.OcrOptions` object with all settings, then pass it\nas the sole argument:\n\n```python\nimport ocrmypdf\nfrom ocrmypdf import OcrOptions\n\nif __name__ == '__main__':  # To ensure correct behavior on Windows and macOS\n    options = OcrOptions(\n        input_file='input.pdf',\n        output_file='output.pdf',\n        deskew=True,\n        languages=['eng'],\n    )\n    ocrmypdf.ocr(options)\n```\n\n{class}`~ocrmypdf.OcrOptions` is a Pydantic model that provides:\n\n- Full type hints and IDE autocompletion\n- Validation of option values at construction time\n- Clear documentation of all available options\n\n```{versionadded} 17.0\nThe {class}`~ocrmypdf.OcrOptions` class is now exported from the top-level\n`ocrmypdf` module.\n```\n\n### Legacy API\n\nFor compatibility with OCRmyPDF < v17, the traditional calling style\nwith positional arguments is still fully supported:\n\n```python\nimport ocrmypdf\n\nif __name__ == '__main__':  # To ensure correct behavior on Windows and macOS\n    ocrmypdf.ocr('input.pdf', 'output.pdf', deskew=True)\n```\n\nWith this style, all of the command line arguments are available\nand may be passed as equivalent keywords.\n\nA few differences are that `verbose` and `quiet` are not available.\nInstead, output should be managed by configuring logging.\n\n### Parent process requirements\n\nThe {func}`ocrmypdf.ocr` function runs OCRmyPDF similar to command line\nexecution. To do this, it will:\n\n- create worker processes or threads\n- manage the signal flags of its worker processes\n- execute other subprocesses (forking and executing other programs)\n\nThe Python process that calls {func}`ocrmypdf.ocr()` must be sufficiently\nprivileged to perform these actions.\n\nThere currently is no option to manage how jobs are scheduled other\nthan the argument `jobs=` which will limit the number of worker\nprocesses.\n\nCreating a child process to call {func}`ocrmypdf.ocr()` is suggested. That\nway your application will survive and remain interactive even if\nOCRmyPDF fails for any reason. For example:\n\n```python\nfrom multiprocessing import Process\nimport ocrmypdf\nfrom ocrmypdf import OcrOptions\n\n\ndef ocrmypdf_process():\n    options = OcrOptions(input_file='input.pdf', output_file='output.pdf')\n    ocrmypdf.ocr(options)\n\n\ndef call_ocrmypdf_from_my_app():\n    p = Process(target=ocrmypdf_process)\n    p.start()\n    p.join()\n```\n\nPrograms that call {func}`ocrmypdf.ocr()` should also install a SIGBUS signal\nhandler (except on Windows), to raise an exception if access to a memory\nmapped file fails. OCRmyPDF may use memory mapping.\n\nSeveral OCR jobs may run concurrently in the same Python interpreter process.\n\nInstalling a plugin set mutates interpreter-global state, because of how OCRmyPDF's\nplugins and Python's library import system work, and a running job cannot survive\nthat state being replaced underneath it. {func}`ocrmypdf.ocr()` therefore takes a\nreaders-writer lock: installing a plugin set takes it exclusively, so it waits for\nevery job already running, while a job holds it shared for its own run. A plugin set\nis installed once per interpreter and reused thereafter, so a job that asks for a\nplugin set some earlier job already installed never blocks.\n\nThe practical consequence is that concurrent jobs should all use the same plugin\nset. Jobs requesting different plugin sets serialize against each other. They must\nalso use the same `max_image_mpixels`, since Pillow's decompression-bomb limit is\ninterpreter-global and the last job to set it wins. If you need to run jobs with\ndiffering configurations, use separate processes.\n\nBecause a plugin set is installed only once, a plugin module given as a file path is\nexecuted once per interpreter rather than once per call. Plugins must not rely on\nbeing re-executed for each job, and must not store per-job state on the plugin\nmanager, which concurrent jobs may share.\n\nNote that N concurrent jobs each configured with `jobs=M` may spawn up to N*M\nworkers, so size `jobs` accordingly.\n\n:::{warning}\nOn Windows and macOS, the script that calls {func}`ocrmypdf.ocr()` must be\nprotected by an \"ifmain\" guard (`if __name__ == '__main__'`). If you do\nnot take at least one of these steps, process semantics will prevent\nOCRmyPDF from working correctly.\n:::\n\n### Logging\n\nOCRmyPDF will log under loggers named `ocrmypdf`. In addition, it\nimports `pdfminer` and `PIL`, both of which post log messages under\nthose logging namespaces.\n\nYou can configure the logging as desired for your application or call\n{func}`ocrmypdf.configure_logging` to configure logging the same way\nOCRmyPDF itself does. The command line parameters such as `--quiet`\nand `--verbose` have no equivalents in the API; you must use the\nprovided configuration function or do configuration in a way that suits\nyour use case.\n\n### Progress monitoring\n\nOCRmyPDF uses the `rich` package to implement its progress bars.\n{func}`ocrmypdf.configure_logging` will set up logging output to\n`sys.stderr` in a way that is compatible with the display of the\nprogress bar. Use `ocrmypdf.ocr(...progress_bar=False)` to disable\nthe progress bar.\n\n### Standard output\n\nOCRmyPDF is strict about not writing to standard output so that\nusers can safely use it in a pipeline and produce a valid output\nfile. A caller application will have to ensure it does not write to\nstandard output either, if it wants to be compatible with this\nbehavior and support piping to a file. Another benefit of running\nOCRmyPDF in a child process, as recommended above, is that it will\nnot interfere with the parent process's standard output.\n\n### Exceptions\n\nOCRmyPDF may throw standard Python exceptions, `ocrmypdf.exceptions.*`\nexceptions, some exceptions related to multiprocessing, and\n{exc}`KeyboardInterrupt`. The parent process should provide an exception\nhandler. OCRmyPDF will clean up its temporary files and worker processes\nautomatically when an exception occurs.\n\nWhen OCRmyPDF succeeds conditionally, it returns an integer exit code.\n\n### Bundling with PyInstaller\n\nOCRmyPDF ships a PyInstaller hook, which PyInstaller finds automatically,\nso applications that call {func}`ocrmypdf.ocr` can be frozen without extra\n`--collect-*` options. The hook bundles OCRmyPDF's builtin plugins, fonts\nand color profiles, and the pikepdf data needed for PDF/A output.\n\nThe external programs are not bundled. Tesseract and Ghostscript must still\nbe installed on the target machine and be on the `PATH`, as must any optional\ntools you use, such as unpaper or pngquant. Third party plugins must be\nbundled by your application.\n\nLike any frozen application that uses multiprocessing, call\n{func}`multiprocessing.freeze_support` at the start of your\n`if __name__ == '__main__':` block.\n\n### Plugin Development Changes\n\n```{versionchanged} 16.13\nPlugin hooks now receive {class}`~ocrmypdf.OcrOptions` objects instead of\n`argparse.Namespace`.\n```\n\n- {class}`~ocrmypdf.OcrOptions` provides the same attribute access as `Namespace` (duck-typing compatible)\n- Plugin developers should update type hints: `from ocrmypdf import OcrOptions`\n- Built-in plugins no longer modify options in-place for better immutability\n\nMost existing plugins will continue working without modification due to the\nduck-typing compatibility between {class}`~ocrmypdf.OcrOptions` and `Namespace`.\n"},"items":[{"name":"api.md","path":"docs/api.md","rawUrl":"https://raw.githubusercontent.com/ocrmypdf/OCRmyPDF/HEAD/docs/api.md","title":"docs - API Interface Contract & Specifications","category":"project-spec","format":"markdown","content":"% SPDX-FileCopyrightText: 2022 James R. Barlow\n% SPDX-License-Identifier: CC-BY-SA-4.0\n\n# Using the OCRmyPDF API\n\nOCRmyPDF originated as a command line program and continues to have this\nlegacy, but parts of it can be imported and used in other Python\napplications.\n\nSome applications may want to consider running ocrmypdf from a\nsubprocess call anyway, as this provides isolation of its activities.\n\n## Example\n\nOCRmyPDF provides one high-level function to run its main engine from an\napplication.\n\n```{versionchanged} 17.0\nThe {func}`ocrmypdf.ocr` function now accepts an {class}`~ocrmypdf.OcrOptions`\nobject as its first argument, providing a cleaner API with full type hints\nand validation. The previous positional argument style remains supported.\n```\n\n### Modern API (recommended)\n\nThe recommended way to call {func}`ocrmypdf.ocr` is to construct an\n{class}`~ocrmypdf.OcrOptions` object with all settings, then pass it\nas the sole argument:\n\n```python\nimport ocrmypdf\nfrom ocrmypdf import OcrOptions\n\nif __name__ == '__main__':  # To ensure correct behavior on Windows and macOS\n    options = OcrOptions(\n        input_file='input.pdf',\n        output_file='output.pdf',\n        deskew=True,\n        languages=['eng'],\n    )\n    ocrmypdf.ocr(options)\n```\n\n{class}`~ocrmypdf.OcrOptions` is a Pydantic model that provides:\n\n- Full type hints and IDE autocompletion\n- Validation of option values at construction time\n- Clear documentation of all available options\n\n```{versionadded} 17.0\nThe {class}`~ocrmypdf.OcrOptions` class is now exported from the top-level\n`ocrmypdf` module.\n```\n\n### Legacy API\n\nFor compatibility with OCRmyPDF < v17, the traditional calling style\nwith positional arguments is still fully supported:\n\n```python\nimport ocrmypdf\n\nif __name__ == '__main__':  # To ensure correct behavior on Windows and macOS\n    ocrmypdf.ocr('input.pdf', 'output.pdf', deskew=True)\n```\n\nWith this style, all of the command line arguments are available\nand may be passed as equivalent keywords.\n\nA few differences are that `verbose` and `quiet` are not available.\nInstead, output should be managed by configuring logging.\n\n### Parent process requirements\n\nThe {func}`ocrmypdf.ocr` function runs OCRmyPDF similar to command line\nexecution. To do this, it will:\n\n- create worker processes or threads\n- manage the signal flags of its worker processes\n- execute other subprocesses (forking and executing other programs)\n\nThe Python process that calls {func}`ocrmypdf.ocr()` must be sufficiently\nprivileged to perform these actions.\n\nThere currently is no option to manage how jobs are scheduled other\nthan the argument `jobs=` which will limit the number of worker\nprocesses.\n\nCreating a child process to call {func}`ocrmypdf.ocr()` is suggested. That\nway your application will survive and remain interactive even if\nOCRmyPDF fails for any reason. For example:\n\n```python\nfrom multiprocessing import Process\nimport ocrmypdf\nfrom ocrmypdf import OcrOptions\n\n\ndef ocrmypdf_process():\n    options = OcrOptions(input_file='input.pdf', output_file='output.pdf')\n    ocrmypdf.ocr(options)\n\n\ndef call_ocrmypdf_from_my_app():\n    p = Process(target=ocrmypdf_process)\n    p.start()\n    p.join()\n```\n\nPrograms that call {func}`ocrmypdf.ocr()` should also install a SIGBUS signal\nhandler (except on Windows), to raise an exception if access to a memory\nmapped file fails. OCRmyPDF may use memory mapping.\n\nSeveral OCR jobs may run concurrently in the same Python interpreter process.\n\nInstalling a plugin set mutates interpreter-global state, because of how OCRmyPDF's\nplugins and Python's library import system work, and a running job cannot survive\nthat state being replaced underneath it. {func}`ocrmypdf.ocr()` therefore takes a\nreaders-writer lock: installing a plugin set takes it exclusively, so it waits for\nevery job already running, while a job holds it shared for its own run. A plugin set\nis installed once per interpreter and reused thereafter, so a job that asks for a\nplugin set some earlier job already installed never blocks.\n\nThe practical consequence is that concurrent jobs should all use the same plugin\nset. Jobs requesting different plugin sets serialize against each other. They must\nalso use the same `max_image_mpixels`, since Pillow's decompression-bomb limit is\ninterpreter-global and the last job to set it wins. If you need to run jobs with\ndiffering configurations, use separate processes.\n\nBecause a plugin set is installed only once, a plugin module given as a file path is\nexecuted once per interpreter rather than once per call. Plugins must not rely on\nbeing re-executed for each job, and must not store per-job state on the plugin\nmanager, which concurrent jobs may share.\n\nNote that N concurrent jobs each configured with `jobs=M` may spawn up to N*M\nworkers, so size `jobs` accordingly.\n\n:::{warning}\nOn Windows and macOS, the script that calls {func}`ocrmypdf.ocr()` must be\nprotected by an \"ifmain\" guard (`if __name__ == '__main__'`). If you do\nnot take at least one of these steps, process semantics will prevent\nOCRmyPDF from working correctly.\n:::\n\n### Logging\n\nOCRmyPDF will log under loggers named `ocrmypdf`. In addition, it\nimports `pdfminer` and `PIL`, both of which post log messages under\nthose logging namespaces.\n\nYou can configure the logging as desired for your application or call\n{func}`ocrmypdf.configure_logging` to configure logging the same way\nOCRmyPDF itself does. The command line parameters such as `--quiet`\nand `--verbose` have no equivalents in the API; you must use the\nprovided configuration function or do configuration in a way that suits\nyour use case.\n\n### Progress monitoring\n\nOCRmyPDF uses the `rich` package to implement its progress bars.\n{func}`ocrmypdf.configure_logging` will set up logging output to\n`sys.stderr` in a way that is compatible with the display of the\nprogress bar. Use `ocrmypdf.ocr(...progress_bar=False)` to disable\nthe progress bar.\n\n### Standard output\n\nOCRmyPDF is strict about not writing to standard output so that\nusers can safely use it in a pipeline and produce a valid output\nfile. A caller application will have to ensure it does not write to\nstandard output either, if it wants to be compatible with this\nbehavior and support piping to a file. Another benefit of running\nOCRmyPDF in a child process, as recommended above, is that it will\nnot interfere with the parent process's standard output.\n\n### Exceptions\n\nOCRmyPDF may throw standard Python exceptions, `ocrmypdf.exceptions.*`\nexceptions, some exceptions related to multiprocessing, and\n{exc}`KeyboardInterrupt`. The parent process should provide an exception\nhandler. OCRmyPDF will clean up its temporary files and worker processes\nautomatically when an exception occurs.\n\nWhen OCRmyPDF succeeds conditionally, it returns an integer exit code.\n\n### Bundling with PyInstaller\n\nOCRmyPDF ships a PyInstaller hook, which PyInstaller finds automatically,\nso applications that call {func}`ocrmypdf.ocr` can be frozen without extra\n`--collect-*` options. The hook bundles OCRmyPDF's builtin plugins, fonts\nand color profiles, and the pikepdf data needed for PDF/A output.\n\nThe external programs are not bundled. Tesseract and Ghostscript must still\nbe installed on the target machine and be on the `PATH`, as must any optional\ntools you use, such as unpaper or pngquant. Third party plugins must be\nbundled by your application.\n\nLike any frozen application that uses multiprocessing, call\n{func}`multiprocessing.freeze_support` at the start of your\n`if __name__ == '__main__':` block.\n\n### Plugin Development Changes\n\n```{versionchanged} 16.13\nPlugin hooks now receive {class}`~ocrmypdf.OcrOptions` objects instead of\n`argparse.Namespace`.\n```\n\n- {class}`~ocrmypdf.OcrOptions` provides the same attribute access as `Namespace` (duck-typing compatible)\n- Plugin developers should update type hints: `from ocrmypdf import OcrOptions`\n- Built-in plugins no longer modify options in-place for better immutability\n\nMost existing plugins will continue working without modification due to the\nduck-typing compatibility between {class}`~ocrmypdf.OcrOptions` and `Namespace`.\n","isInternal":false,"tokens":1878,"sizeBytes":8119}],"systemPromptSnippet":"<yakaai_skills repo=\"ocrmypdf/OCRmyPDF\">\n<!-- File: docs/api.md (Tokens: ~1878 | Category: project-spec) -->\n% SPDX-FileCopyrightText: 2022 James R. Barlow\n% SPDX-License-Identifier: CC-BY-SA-4.0\n\n# Using the OCRmyPDF API\n\nOCRmyPDF originated as a command line program and continues to have this\nlegacy, but parts of it can be imported and used in other Python\napplications.\n\nSome applications may want to consider running ocrmypdf from a\nsubprocess call anyway, as this provides isolation of its activities.\n\n## Example\n\nOCRmyPDF provides one high-level function to run its main engine from an\napplication.\n\n```{versionchanged} 17.0\nThe {func}`ocrmypdf.ocr` function now accepts an {class}`~ocrmypdf.OcrOptions`\nobject as its first argument, providing a cleaner API with full type hints\nand validation. The previous positional argument style remains supported.\n```\n\n### Modern API (recommended)\n\nThe recommended way to call {func}`ocrmypdf.ocr` is to construct an\n{class}`~ocrmypdf.OcrOptions` object with all settings, then pass it\nas the sole argument:\n\n```python\nimport ocrmypdf\nfrom ocrmypdf import OcrOptions\n\nif __name__ == '__main__':  # To ensure correct behavior on Windows and macOS\n    options = OcrOptions(\n        input_file='input.pdf',\n        output_file='output.pdf',\n        deskew=True,\n        languages=['eng'],\n    )\n    ocrmypdf.ocr(options)\n```\n\n{class}`~ocrmypdf.OcrOptions` is a Pydantic model that provides:\n\n- Full type hints and IDE autocompletion\n- Validation of option values at construction time\n- Clear documentation of all available options\n\n```{versionadded} 17.0\nThe {class}`~ocrmypdf.OcrOptions` class is now exported from the top-level\n`ocrmypdf` module.\n```\n\n### Legacy API\n\nFor compatibility with OCRmyPDF < v17, the traditional calling style\nwith positional arguments is still fully supported:\n\n```python\nimport ocrmypdf\n\nif __name__ == '__main__':  # To ensure correct behavior on Windows and macOS\n    ocrmypdf.ocr('input.pdf', 'output.pdf', deskew=True)\n```\n\nWith this style, all of the command line arguments are available\nand may be passed as equivalent keywords.\n\nA few differences are that `verbose` and `quiet` are not available.\nInstead, output should be managed by configuring logging.\n\n### Parent process requirements\n\nThe {func}`ocrmypdf.ocr` function runs OCRmyPDF similar to command line\nexecution. To do this, it will:\n\n- create worker processes or threads\n- manage the signal flags of its worker processes\n- execute other subprocesses (forking and executing other programs)\n\nThe Python process that calls {func}`ocrmypdf.ocr()` must be sufficiently\nprivileged to perform these actions.\n\nThere currently is no option to manage how jobs are scheduled other\nthan the argument `jobs=` which will limit the number of worker\nprocesses.\n\nCreating a child process to call {func}`ocrmypdf.ocr()` is suggested. That\nway your application will survive and remain interactive even if\nOCRmyPDF fails for any reason. For example:\n\n```python\nfrom multiprocessing import Process\nimport ocrmypdf\nfrom ocrmypdf import OcrOptions\n\n\ndef ocrmypdf_process():\n    options = OcrOptions(input_file='input.pdf', output_file='output.pdf')\n    ocrmypdf.ocr(options)\n\n\ndef call_ocrmypdf_from_my_app():\n    p = Process(target=ocrmypdf_process)\n    p.start()\n    p.join()\n```\n\nPrograms that call {func}`ocrmypdf.ocr()` should also install a SIGBUS signal\nhandler (except on Windows), to raise an exception if access to a memory\nmapped file fails. OCRmyPDF may use memory mapping.\n\nSeveral OCR jobs may run concurrently in the same Python interpreter process.\n\nInstalling a plugin set mutates interpreter-global state, because of how OCRmyPDF's\nplugins and Python's library import system work, and a running job cannot survive\nthat state being replaced underneath it. {func}`ocrmypdf.ocr()` therefore takes a\nreaders-writer lock: installing a plugin set takes it exclusively, so it waits for\nevery job already running, while a job holds it shared for its own run. A plugin set\nis installed once per interpreter and reused thereafter, so a job that asks for a\nplugin set some earlier job already installed never blocks.\n\nThe practical consequence is that concurrent jobs should all use the same plugin\nset. Jobs requesting different plugin sets serialize against each other. They must\nalso use the same `max_image_mpixels`, since Pillow's decompression-bomb limit is\ninterpreter-global and the last job to set it wins. If you need to run jobs with\ndiffering configurations, use separate processes.\n\nBecause a plugin set is installed only once, a plugin module given as a file path is\nexecuted once per interpreter rather than once per call. Plugins must not rely on\nbeing re-executed for each job, and must not store per-job state on the plugin\nmanager, which concurrent jobs may share.\n\nNote that N concurrent jobs each configured with `jobs=M` may spawn up to N*M\nworkers, so size `jobs` accordingly.\n\n:::{warning}\nOn Windows and macOS, the script that calls {func}`ocrmypdf.ocr()` must be\nprotected by an \"ifmain\" guard (`if __name__ == '__main__'`). If you do\nnot take at least one of these steps, process semantics will prevent\nOCRmyPDF from working correctly.\n:::\n\n### Logging\n\nOCRmyPDF will log under loggers named `ocrmypdf`. In addition, it\nimports `pdfminer` and `PIL`, both of which post log messages under\nthose logging namespaces.\n\nYou can configure the logging as desired for your application or call\n{func}`ocrmypdf.configure_logging` to configure logging the same way\nOCRmyPDF itself does. The command line parameters such as `--quiet`\nand `--verbose` have no equivalents in the API; you must use the\nprovided configuration function or do configuration in a way that suits\nyour use case.\n\n### Progress monitoring\n\nOCRmyPDF uses the `rich` package to implement its progress bars.\n{func}`ocrmypdf.configure_logging` will set up logging output to\n`sys.stderr` in a way that is compatible with the display of the\nprogress bar. Use `ocrmypdf.ocr(...progress_bar=False)` to disable\nthe progress bar.\n\n### Standard output\n\nOCRmyPDF is strict about not writing to standard output so that\nusers can safely use it in a pipeline and produce a valid output\nfile. A caller application will have to ensure it does not write to\nstandard output either, if it wants to be compatible with this\nbehavior and support piping to a file. Another benefit of running\nOCRmyPDF in a child process, as recommended above, is that it will\nnot interfere with the parent process's standard output.\n\n### Exceptions\n\nOCRmyPDF may throw standard Python exceptions, `ocrmypdf.exceptions.*`\nexceptions, some exceptions related to multiprocessing, and\n{exc}`KeyboardInterrupt`. The parent process should provide an exception\nhandler. OCRmyPDF will clean up its temporary files and worker processes\nautomatically when an exception occurs.\n\nWhen OCRmyPDF succeeds conditionally, it returns an integer exit code.\n\n### Bundling with PyInstaller\n\nOCRmyPDF ships a PyInstaller hook, which PyInstaller finds automatically,\nso applications that call {func}`ocrmypdf.ocr` can be frozen without extra\n`--collect-*` options. The hook bundles OCRmyPDF's builtin plugins, fonts\nand color profiles, and the pikepdf data needed for PDF/A output.\n\nThe external programs are not bundled. Tesseract and Ghostscript must still\nbe installed on the target machine and be on the `PATH`, as must any optional\ntools you use, such as unpaper or pngquant. Third party plugins must be\nbundled by your application.\n\nLike any frozen application that uses multiprocessing, call\n{func}`multiprocessing.freeze_support` at the start of your\n`if __name__ == '__main__':` block.\n\n### Plugin Development Changes\n\n```{versionchanged} 16.13\nPlugin hooks now receive {class}`~ocrmypdf.OcrOptions` objects instead of\n`argparse.Namespace`.\n```\n\n- {class}`~ocrmypdf.OcrOptions` provides the same attribute access as `Namespace` (duck-typing compatible)\n- Plugin developers should update type hints: `from ocrmypdf import OcrOptions`\n- Built-in plugins no longer modify options in-place for better immutability\n\nMost existing plugins will continue working without modification due to the\nduck-typing compatibility between {class}`~ocrmypdf.OcrOptions` and `Namespace`.\n</yakaai_skills>"}